Authentication Flow
ConsentKeys implements the OAuth 2.0 Authorization Code flow with passwordless magic link authentication. This page explains how the complete flow works from start to finish.
Overview
The authentication flow consists of several steps that ensure secure, privacy-focused user authentication:
Detailed Breakdown
Step 1: Initiate Authorization
Your application redirects the user to the ConsentKeys authorization endpoint:
GET /auth?
response_type=code&
client_id=ck_your_client_id&
redirect_uri=https://yourapp.com/callback&
scope=openid profile email&
state=random_csrf_token&
nonce=random_replay_token
Required Parameters:
response_type: Must becodefor authorization code flowclient_id: Your application's client IDredirect_uri: Where to send the user after authentication (must match registered URI)scope: Requested permissions (must includeopenid)
Recommended Parameters:
state: Random string for CSRF protection (verify this matches on callback)nonce: Random string to prevent token replay attackscode_challenge: PKCE code challenge for public clientscode_challenge_method: UsuallyS256(SHA-256)
Optional Parameters:
prompt: Controls authentication behaviorlogin: Force user to re-authenticate even if they have an active sessionconsent: Force consent screen to be shown (note: consent behavior depends on frontend implementation)
Step 2-3: Email Collection
ConsentKeys displays an email input screen. If the user has an existing session, they'll see an account chooser instead.
New User Experience:
┌────────────────────────────────────────┐
│ │
│ Sign in to YourApp │
│ │
│ ┌────────────────────────────────┐ │
│ │ Enter your email │ │
│ └────────────────────────────────┘ │
│ │
│ [Continue] │
│ │
└────────────────────────────────────────┘
Returning User Experience:
┌────────────────────────────────────────┐
│ │
│ Choose an account for YourApp │
│ │
│ ┌────────────────────────────────┐ │
│ │ 👤 john@example.com │ │
│ └────────────────────────────────┘ │
│ ┌────────────────────────────────┐ │
│ │ 👤 jane@work.com │ │
│ └────────────────────────────────┘ │
│ │
│ + Use a different account │
│ │
└────────────────────────────────────────┘
Step 4-7: Magic Link Verification
POST /request-magic-link
Content-Type: application/json
{
"email": "user@example.com",
"client_id": "ck_your_client_id",
"redirect_uri": "https://yourapp.com/callback",
"scope": "openid profile email",
"state": "...",
"nonce": "..."
}
ConsentKeys sends an email with a secure, time-limited link:
Subject: Sign in to YourApp
Click here to sign in:
https://pseudoidc.consentkeys.com/verify-email?token=...
This link expires in 15 minutes.
When the user clicks the link, ConsentKeys:
- Validates the token
- Creates or retrieves the user account
- Establishes a browser session
Step 8-9: Consent Screen
The user sees what data your app is requesting:
┌────────────────────────────────────────┐
│ │
│ YourApp wants to access: │
│ │
│ ✓ Your email address │
│ ✓ Your profile information │
│ │
│ [Allow] [Deny] │
│ │
└────────────────────────────────────────┘
If the user has already granted consent to your app, this screen is skipped.
Step 10: Authorization Code Redirect
After consent, ConsentKeys redirects back to your app:
HTTP/1.1 302 Found
Location: https://yourapp.com/callback?
code=auth_code_abc123&
state=random_csrf_token
Your app must:
- Verify the
stateparameter matches what you sent - Extract the authorization
code
Step 11-12: Token Exchange
Your backend server exchanges the code for tokens:
POST /token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=auth_code_abc123&
redirect_uri=https://yourapp.com/callback&
client_id=ck_your_client_id&
client_secret=your_client_secret
Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"id_token": "eyJhbGciOiJSUzI1NiIs...",
"scope": "openid profile email"
}
The token exchange must happen on your backend server. Never expose your client secret in frontend code!
Step 13-14: User Information
Use the access token to get user details:
GET /userinfo
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
Response:
{
"sub": "user_unique_id",
"email": "user@example.com",
"email_verified": true,
"name": "John Doe",
"preferred_username": "johnd",
"picture": "https://..."
}
Security Considerations
CSRF Protection (State Parameter)
Always include and verify the state parameter:
// Generate state before redirect
const state = generateRandomString(32);
sessionStorage.setItem('oauth_state', state);
// Verify on callback
const returnedState = new URLSearchParams(window.location.search).get('state');
if (returnedState !== sessionStorage.getItem('oauth_state')) {
throw new Error('Invalid state - possible CSRF attack');
}
PKCE for Public Clients
For single-page apps and mobile apps, use PKCE:
// Generate code verifier
const codeVerifier = generateRandomString(128);
sessionStorage.setItem('code_verifier', codeVerifier);
// Generate code challenge
const challenge = await sha256(codeVerifier);
const codeChallenge = base64UrlEncode(challenge);
// Include in authorization request
const authUrl = `https://pseudoidc.consentkeys.com/auth?
...&code_challenge=${codeChallenge}&code_challenge_method=S256`;
// Include in token exchange
const tokenResponse = await fetch('/token', {
method: 'POST',
body: new URLSearchParams({
grant_type: 'authorization_code',
code: authCode,
code_verifier: sessionStorage.getItem('code_verifier'),
...
})
});
Token Storage
Best Practices:
- Access tokens: Store in memory (React state, Vue store)
- Refresh tokens: Store in httpOnly cookies (backend-managed)
- Never: Store tokens in localStorage (XSS vulnerable)
Error Handling
Common OAuth errors and how to handle them:
| Error | Cause | Solution |
|---|---|---|
invalid_request | Missing required parameter | Check your authorization URL |
access_denied | User denied consent | Show appropriate message |
invalid_grant | Expired/invalid auth code | Restart the flow |
invalid_client | Wrong client credentials | Verify your client ID/secret |
unsupported_response_type | Wrong response_type | Use code |
See the Error Codes reference for a complete list.
Next Steps
- Learn about Magic Link authentication
- Understand Scopes and Claims
- Explore the API Reference