PKCE Implementation
Proof Key for Code Exchange (PKCE) is an extension to the OAuth 2.0 authorization code flow that prevents authorization code interception attacks.
What is PKCE?
PKCE (pronounced "pixie") is a security extension for OAuth 2.0 public clients on mobile devices and single-page applications (SPAs) performing the Authorization Code grant. It prevents several attacks and is now recommended for all OAuth 2.0 clients, including confidential clients.
PKCE was originally designed to protect mobile apps, but it's now considered a best practice for all OAuth 2.0 authorization code flows. OAuth42 requires PKCE for all authorization code grants.
Security Requirement
OAuth42 enforces PKCE for all authorization code flows. Requests without valid PKCE parameters will be rejected.
How PKCE Works
PKCE introduces two new parameters to the authorization code flow:
Generate Code Verifier
The client creates a cryptographically random string called the code_verifier. This should be a high-entropy random string between 43-128 characters.
// Generate a random code verifier
const codeVerifier = generateRandomString(128);
// Example output:
// "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"Create Code Challenge
The client creates a code_challenge by hashing the code verifier with SHA-256 and base64url-encoding the result.
// Create code challenge from verifier
const codeChallenge = base64urlEncode(
sha256(codeVerifier)
);
// Example output:
// "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"Send Authorization Request
The client includes the code challenge and challenge method in the authorization request.
GET /oauth/authorize?
response_type=code&
client_id=YOUR_CLIENT_ID&
redirect_uri=https://yourapp.com/callback&
scope=openid+profile+email&
state=random_state&
code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&
code_challenge_method=S256Exchange Code with Verifier
When exchanging the authorization code for tokens, the client includes the original code verifier.
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=AUTHORIZATION_CODE&
redirect_uri=https://yourapp.com/callback&
client_id=YOUR_CLIENT_ID&
code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXkServer Validates
OAuth42 hashes the code verifier and compares it to the stored code challenge. If they match, tokens are issued.
Validation:
sha256(code_verifier) === stored_code_challengeWhy PKCE is Important
Prevents Authorization Code Interception
Without PKCE, if an attacker intercepts the authorization code (e.g., through a malicious app on the same device), they can exchange it for tokens. PKCE prevents this because the attacker doesn't have the code verifier.
No Client Secret Needed
PKCE allows public clients (mobile apps, SPAs) to securely use the authorization code flow without needing to store a client secret, which can't be kept secure in these environments.
Defense in Depth
Even for confidential clients that use a client secret, PKCE provides an additional layer of security against sophisticated attacks.
Implementation Examples
JavaScript/TypeScript
import { OAuth42Client } from '@oauth42/sdk';
// SDK handles PKCE automatically
const oauth42 = new OAuth42Client({
clientId: 'your_client_id',
redirectUri: 'http://localhost:3000/callback',
issuer: 'https://auth.oauth42.com',
});
// Generate PKCE parameters
const { codeVerifier, codeChallenge } = await oauth42.generatePKCE();
// Store code verifier securely (e.g., session)
session.codeVerifier = codeVerifier;
// Create authorization URL with code challenge
const authUrl = oauth42.getAuthorizationUrl({
state: 'random_state',
codeChallenge,
codeChallengeMethod: 'S256',
});
// Redirect user
window.location.href = authUrl;Python
from oauth42_sdk import OAuth42Client
# SDK handles PKCE automatically
oauth42 = OAuth42Client(
client_id='your_client_id',
redirect_uri='http://localhost:8000/callback',
issuer='https://auth.oauth42.com',
)
# Generate PKCE parameters
code_verifier, code_challenge = oauth42.generate_pkce()
# Store code verifier securely (e.g., session)
session['code_verifier'] = code_verifier
# Create authorization URL with code challenge
auth_url = oauth42.get_authorization_url(
state='random_state',
code_challenge=code_challenge,
code_challenge_method='S256'
)
# Redirect user
return redirect(auth_url)Manual Implementation (Node.js)
import crypto from 'crypto';
function generateCodeVerifier() {
return crypto.randomBytes(64).toString('base64url');
}
function generateCodeChallenge(verifier) {
return crypto
.createHash('sha256')
.update(verifier)
.digest('base64url');
}
// Usage
const codeVerifier = generateCodeVerifier();
const codeChallenge = generateCodeChallenge(codeVerifier);
console.log('Code Verifier:', codeVerifier);
console.log('Code Challenge:', codeChallenge);Best Practices
Always Use S256
Always use S256 as the code challenge method. The plain method is deprecated and insecure.
Use Sufficient Entropy
Generate code verifiers with at least 43 characters of high-entropy random data. Use cryptographically secure random number generators.
Store Code Verifier Securely
Store the code verifier securely between the authorization request and token exchange. Use secure session storage on the server, not client-side storage.
Use SDKs When Possible
OAuth42's official SDKs handle PKCE implementation correctly and securely. Use them instead of implementing PKCE manually unless you have specific requirements.