OAuth 2.0 with PKCE
Understand the OAuth 2.0 Authorization Code flow with PKCE (Proof Key for Code Exchange).
What is PKCE?
PKCE (pronounced "pixy") is a security extension to OAuth 2.0 that protects against authorization code interception attacks.
Why PKCE?
Without PKCE, if an attacker intercepts the authorization code, they could:
- Exchange it for tokens
- Gain access to user accounts
PKCE prevents this by requiring proof that the same client that initiated the flow is completing it.
How PKCE Works
1. Generate Code Verifier & Challenge
The client must first create a high-entropy random string (verifier) and its hash (challenge).
- JavaScript
- Python
// 1. Generate Code Verifier (Random 43-128 chars)
const generateRandomString = (length) => {
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';
let text = '';
for (let i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
};
const codeVerifier = generateRandomString(64);
// 2. Generate Code Challenge (SHA-256 of verifier)
async function generateCodeChallenge(verifier) {
const encoder = new TextEncoder();
const data = encoder.encode(verifier);
const digest = await window.crypto.subtle.digest('SHA-256', data);
const base64Digest = btoa(String.fromCharCode(...new Uint8Array(digest)))
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
return base64Digest;
}
import secrets
import hashlib
import base64
# 1. Generate Code Verifier (Random 43-128 chars)
code_verifier = secrets.token_urlsafe(64)[:128]
# 2. Generate Code Challenge (SHA-256 of verifier)
code_challenge_hash = hashlib.sha256(code_verifier.encode('ascii')).digest()
code_challenge = base64.urlsafe_b64encode(code_challenge_hash).decode('ascii').rstrip('=')
print(f"Verifier: {code_verifier}")
print(f"Challenge: {code_challenge}")
3. Authorization Request
GET /authorize?
response_type=code
&client_id=your-client-id
&redirect_uri=https://yourapp.com/callback
&scope=openid profile email
&state=random-state-value
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
4. Token Exchange
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=received-auth-code
&redirect_uri=https://yourapp.com/callback
&client_id=your-client-id
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
The server verifies that sha256(code_verifier) == code_challenge before issuing tokens.
Complete Flow Diagram
SyAuth Server-Side PKCE
SyAuth also supports server-side PKCE sessions to solve cross-origin issues in certain architectures.
Initialize PKCE Session
POST /oauth/pkce/init
Content-Type: application/json
{}
Response:
{
"session_id": "pkce_session_xxx",
"code_challenge": "ABC123...",
"code_challenge_method": "S256"
}
Use in Token Exchange
POST /oauth/token
{
"grant_type": "authorization_code",
"code": "xxx",
"pkce_session_id": "pkce_session_xxx" // Instead of code_verifier
}
SDK Handling
The SyAuth SDK handles all PKCE complexity automatically:
import { useSyAuth } from '@syauth/nextjs';
function LoginButton() {
const { loginWithRedirect } = useSyAuth();
// SDK automatically:
// 1. Generates code_verifier
// 2. Calculates code_challenge
// 3. Stores verifier in secure cookie
// 4. Includes challenge in auth request
// 5. Retrieves verifier for token exchange
return (
<button onClick={() => loginWithRedirect()}>
Login
</button>
);
}
Security Best Practices
| Practice | Description |
|---|---|
| Use S256 method | SHA-256 is more secure than plain |
| Secure verifier storage | Use HttpOnly cookies, not localStorage |
| Validate state parameter | Prevent CSRF attacks |
| Use short-lived auth codes | Codes expire in 5 minutes |
Common Issues
"Invalid code_verifier"
The verifier doesn't match the challenge. Ensure you're using the exact same verifier that was used to create the challenge.
"Code already used"
Authorization codes are one-time use. Request a new one if needed.
"Code expired"
Authorization codes expire after 5 minutes. Restart the flow.
Next Steps
- Token Management - Learn about access and refresh tokens
- Security Best Practices - Security recommendations