bknd-oauth-setup
π―Skillfrom cameronapak/bknd-skills
Configures OAuth authentication providers like Google and GitHub in a Bknd application, handling credentials, callback URLs, and strategy setup.
Part of
cameronapak/bknd-skills(55 items)
Installation
npx add-skill cameronapak/bknd-skillsnpx add-skill cameronapak/bknd-skills -a cursor -a claude-codenpx add-skill cameronapak/bknd-skills -gSkill Details
Use when configuring OAuth or social login providers in a Bknd application. Covers Google OAuth, GitHub OAuth, custom OAuth providers, callback URLs, environment variables, and frontend OAuth integration.
Overview
# OAuth/Social Login Setup
Configure OAuth authentication providers (Google, GitHub, or custom) in Bknd.
Prerequisites
- Bknd project with auth enabled (
bknd-setup-auth) - OAuth app credentials from provider (client_id, client_secret)
- For Google: Google Cloud Console project with OAuth 2.0 credentials
- For GitHub: GitHub OAuth App in Developer Settings
- For custom: Provider's authorization server endpoints
When to Use UI Mode
- Testing OAuth login flow via admin panel
- Viewing enabled OAuth strategies
- Checking callback URL configuration
UI steps: Admin Panel > Auth > Strategies
When to Use Code Mode
- Configuring OAuth providers in
bknd.config.ts - Setting up multiple OAuth providers
- Implementing frontend OAuth buttons
- Configuring custom OAuth providers (Slack, Discord, etc.)
Built-in OAuth Providers
Bknd has pre-configured support for:
| Provider | Type | Scopes |
|----------|------|--------|
| google | OIDC | openid, email, profile |
| github | OAuth2 | read:user, user:email |
Google OAuth Setup
1. Create Google OAuth Credentials
- Go to [Google Cloud Console](https://console.cloud.google.com/)
- Create project or select existing
- Navigate: APIs & Services > Credentials
- Click Create Credentials > OAuth client ID
- Application type: Web application
- Add authorized redirect URI:
```
http://localhost:7654/api/auth/google/callback
```
(Replace with your production URL)
- Copy Client ID and Client Secret
2. Configure Bknd
```typescript
// bknd.config.ts
import { defineConfig } from "bknd";
export default defineConfig({
auth: {
enabled: true,
jwt: {
secret: process.env.JWT_SECRET!,
expires: 604800,
},
strategies: {
google: {
type: "oauth",
enabled: true,
config: {
name: "google",
client: {
client_id: process.env.GOOGLE_CLIENT_ID!,
client_secret: process.env.GOOGLE_CLIENT_SECRET!,
},
},
},
},
},
});
```
3. Environment Variables
```bash
# .env
GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=your-google-client-secret
JWT_SECRET=your-256-bit-secret
```
GitHub OAuth Setup
1. Create GitHub OAuth App
- Go to [GitHub Developer Settings](https://github.com/settings/developers)
- Click New OAuth App
- Fill in:
- Application name: Your app name
- Homepage URL: http://localhost:7654
- Authorization callback URL: http://localhost:7654/api/auth/github/callback
- Click Register application
- Copy Client ID and generate Client Secret
2. Configure Bknd
```typescript
// bknd.config.ts
import { defineConfig } from "bknd";
export default defineConfig({
auth: {
enabled: true,
jwt: {
secret: process.env.JWT_SECRET!,
expires: 604800,
},
strategies: {
github: {
type: "oauth",
enabled: true,
config: {
name: "github",
client: {
client_id: process.env.GITHUB_CLIENT_ID!,
client_secret: process.env.GITHUB_CLIENT_SECRET!,
},
},
},
},
},
});
```
3. Environment Variables
```bash
# .env
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
JWT_SECRET=your-256-bit-secret
```
Multiple OAuth Providers
Enable multiple providers simultaneously:
```typescript
// bknd.config.ts
import { defineConfig } from "bknd";
export default defineConfig({
auth: {
enabled: true,
jwt: {
secret: process.env.JWT_SECRET!,
expires: 604800,
},
strategies: {
password: {
type: "password",
enabled: true,
config: {
hashing: "bcrypt",
rounds: 4,
},
},
google: {
type: "oauth",
enabled: true,
config: {
name: "google",
client: {
client_id: process.env.GOOGLE_CLIENT_ID!,
client_secret: process.env.GOOGLE_CLIENT_SECRET!,
},
},
},
github: {
type: "oauth",
enabled: true,
config: {
name: "github",
client: {
client_id: process.env.GITHUB_CLIENT_ID!,
client_secret: process.env.GITHUB_CLIENT_SECRET!,
},
},
},
},
},
});
```
Custom OAuth Provider
For providers not built-in (Slack, Discord, Microsoft, etc.):
```typescript
// bknd.config.ts
import { defineConfig } from "bknd";
export default defineConfig({
auth: {
enabled: true,
strategies: {
slack: {
type: "custom_oauth",
enabled: true,
config: {
name: "slack",
type: "oauth2", // "oauth2" or "oidc"
client: {
client_id: process.env.SLACK_CLIENT_ID!,
client_secret: process.env.SLACK_CLIENT_SECRET!,
token_endpoint_auth_method: "client_secret_basic",
},
as: {
issuer: "https://slack.com",
authorization_endpoint: "https://slack.com/oauth/v2/authorize",
token_endpoint: "https://slack.com/api/oauth.v2.access",
userinfo_endpoint: "https://slack.com/api/users.identity",
scopes_supported: ["openid", "profile", "email"],
},
},
},
},
},
});
```
Custom OAuth config options:
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| name | string | Yes | Strategy identifier |
| type | "oauth2" \| "oidc" | Yes | Protocol type |
| client.client_id | string | Yes | OAuth client ID |
| client.client_secret | string | Yes | OAuth client secret |
| client.token_endpoint_auth_method | string | Yes | Auth method (client_secret_basic) |
| as.issuer | string | Yes | Authorization server issuer URL |
| as.authorization_endpoint | string | Yes | OAuth authorize URL |
| as.token_endpoint | string | Yes | Token exchange URL |
| as.userinfo_endpoint | string | No | User info URL |
| as.scopes_supported | string[] | No | Available scopes |
OAuth Endpoints
Once configured, Bknd exposes these endpoints:
| Method | Path | Description |
|--------|------|-------------|
| POST | /api/auth/{provider}/login | Start OAuth login (cookie mode) |
| POST | /api/auth/{provider}/register | Start OAuth registration (cookie mode) |
| GET | /api/auth/{provider}/login | Get OAuth URL (token mode) |
| GET | /api/auth/{provider}/callback | OAuth callback handler |
Frontend Integration
Cookie-Based Flow (Recommended for SSR)
```typescript
// Redirect user to OAuth provider
function loginWithGoogle() {
// POST redirects to Google, callback sets cookie, redirects to pathSuccess
const form = document.createElement("form");
form.method = "POST";
form.action = "http://localhost:7654/api/auth/google/login";
document.body.appendChild(form);
form.submit();
}
```
Token-Based Flow (SPA)
```typescript
import { Api } from "bknd";
const api = new Api({
host: "http://localhost:7654",
storage: localStorage,
});
async function loginWithGoogle() {
// Get OAuth URL
const { data } = await api.auth.login("google");
if (data?.url) {
// Store challenge for callback verification
sessionStorage.setItem("oauth_challenge", data.challenge);
// Redirect to Google
window.location.href = data.url;
}
}
// On callback page, complete the flow
async function handleOAuthCallback() {
const params = new URLSearchParams(window.location.search);
const code = params.get("code");
const challenge = sessionStorage.getItem("oauth_challenge");
if (code && challenge) {
// Complete OAuth flow
const response = await fetch(
http://localhost:7654/api/auth/google/callback?code=${code},
{
headers: {
"X-State-Challenge": challenge,
"X-State-Action": "login",
},
}
);
const { user, token } = await response.json();
api.setToken(token);
sessionStorage.removeItem("oauth_challenge");
}
}
```
React OAuth Buttons
```tsx
import { useAuth } from "@bknd/react";
function OAuthButtons() {
const { login } = useAuth();
async function handleGoogleLogin() {
const result = await login("google");
if (result.data?.url) {
window.location.href = result.data.url;
}
}
async function handleGitHubLogin() {
const result = await login("github");
if (result.data?.url) {
window.location.href = result.data.url;
}
}
return (
Continue with Google Continue with GitHub
);
}
```
OAuth Callback Page (React)
```tsx
import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { Api } from "bknd";
const api = new Api({
host: import.meta.env.VITE_API_URL,
storage: localStorage,
});
function OAuthCallback() {
const navigate = useNavigate();
const [error, setError] = useState
useEffect(() => {
const params = new URLSearchParams(window.location.search);
const code = params.get("code");
const challenge = sessionStorage.getItem("oauth_challenge");
if (!code) {
setError("No authorization code received");
return;
}
if (!challenge) {
setError("OAuth session expired. Please try again.");
return;
}
fetch(${import.meta.env.VITE_API_URL}/api/auth/google/callback?code=${code}, {
headers: {
"X-State-Challenge": challenge,
"X-State-Action": "login",
},
})
.then((res) => res.json())
.then(({ user, token }) => {
api.setToken(token);
sessionStorage.removeItem("oauth_challenge");
navigate("/dashboard");
})
.catch((err) => {
setError("Authentication failed. Please try again.");
});
}, [navigate]);
if (error) {
return (
);
}
return
}
```
Callback URL Configuration
Development:
```
http://localhost:7654/api/auth/{provider}/callback
```
Production:
```
https://api.yourapp.com/api/auth/{provider}/callback
```
Update redirect URIs in provider dashboard when deploying.
Cookie Settings for OAuth
Configure cookie behavior for OAuth flow:
```typescript
{
auth: {
cookie: {
secure: process.env.NODE_ENV === "production", // HTTPS only in prod
httpOnly: true,
sameSite: "lax", // Required for OAuth redirects
pathSuccess: "/dashboard", // Redirect after login
pathLoggedOut: "/login", // Redirect after logout
},
},
}
```
Common Pitfalls
Callback URL Mismatch
Problem: redirect_uri_mismatch error from provider
Fix: Ensure callback URL exactly matches provider dashboard:
```
# Provider dashboard (Google/GitHub)
http://localhost:7654/api/auth/google/callback
# Must match Bknd host configuration
host: "http://localhost:7654"
```
Missing Environment Variables
Problem: OAuth login fails silently
Fix: Verify all required env vars are set:
```bash
# Required for Google OAuth
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
# Required for GitHub OAuth
GITHUB_CLIENT_ID=...
GITHUB_CLIENT_SECRET=...
# Always required
JWT_SECRET=...
```
CORS Issues (SPA)
Problem: CORS error when calling OAuth endpoints
Fix: Configure CORS on backend:
```typescript
{
server: {
cors: {
origin: ["http://localhost:3000"], // Your frontend URL
credentials: true,
},
},
}
```
Strategy Conflict
Problem: "User signed up with different strategy"
Cause: User has existing account with different auth method
Solution: Users can only have ONE strategy. Guide them to use their original login method or implement account linking (requires custom code).
OAuth Cookie Not Set
Problem: Cookie not received after OAuth callback
Fix: Ensure secure cookie settings:
```typescript
{
auth: {
cookie: {
secure: false, // Set false for localhost (no HTTPS)
sameSite: "lax", // Required for OAuth redirects
},
},
}
```
Invalid Scopes
Problem: Provider rejects scope request
Fix: Use only scopes from scopes_supported:
```typescript
// Google OIDC defaults
scopes_supported: ["openid", "email", "profile"]
// GitHub OAuth2 defaults
scopes_supported: ["read:user", "user:email"]
```
Verification
Test OAuth setup:
1. Check available strategies:
```bash
curl http://localhost:7654/api/auth/strategies
```
Response should include your OAuth providers:
```json
{
"strategies": ["password", "google", "github"],
"basepath": "/api/auth"
}
```
2. Test OAuth URL generation:
```bash
curl http://localhost:7654/api/auth/google/login
```
Response:
```json
{
"url": "https://accounts.google.com/o/oauth2/v2/auth?...",
"challenge": "...",
"action": "login"
}
```
3. Complete full OAuth flow:
- Visit the OAuth URL in browser
- Complete provider login
- Verify redirect to
pathSuccess - Check
api/auth/mereturns user
DOs and DON'Ts
DO:
- Store client secrets in environment variables
- Use HTTPS in production
- Set
sameSite: "lax"for cookie (required for OAuth redirects) - Match callback URLs exactly in provider dashboard
- Test OAuth flow in incognito (avoid cached sessions)
- Set appropriate JWT expiration
DON'T:
- Hardcode client secrets in code
- Use
secure: truecookie on localhost (no HTTPS) - Mix up client_id and client_secret
- Forget to update callback URLs for production
- Expect users to have multiple strategies (one per user)
- Skip the challenge verification in token flow
Related Skills
- bknd-setup-auth - Initialize authentication system
- bknd-login-flow - Login/logout functionality
- bknd-registration - User registration setup
- bknd-session-handling - Manage user sessions
- bknd-create-role - Define user roles for OAuth users
More from this repository10
btca-bknd-repo-learn skill from cameronapak/bknd-skills
bknd-storage-config skill from cameronapak/bknd-skills
Configures public vs authenticated access in Bknd, defining role-based permissions for unauthenticated and authenticated users across data entities.
Skill
Skill
Enables efficient bulk data operations in Bknd, supporting mass insert, update, and delete with advanced processing and error handling strategies.
Skill
bknd-seed-data skill from cameronapak/bknd-skills
bknd-create-user skill from cameronapak/bknd-skills
bknd-custom-endpoint skill from cameronapak/bknd-skills