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
PKCE is enabled by default in every OAuth42 SDK — the SDK generates the code_verifier, computes the S256 code_challenge, stores the verifier in the session, and sends it on code exchange. You do not need to write PKCE primitives yourself.
- Next.js (
@oauth42/next): PKCE is configured in the OAuth42 provider — nothing to enable. See the tutorial. - Other JS/TS (
openid-client/oidc-client-ts): both libraries do PKCE by default. See JavaScript SDK page. - Python:
OAuth42Client.create_authorization_url()returns the verifier; the Flask/FastAPI middleware handles the whole flow end-to-end. See Python SDK page. - Rust:
SessionManagerandTokenCachehandle PKCE inside the authorization-code grant. See Rust SDK page.
If you really must do it by hand
The two primitives, for reference:
// Node.js
import crypto from 'crypto';
const codeVerifier = crypto.randomBytes(64).toString('base64url');
const codeChallenge = crypto
.createHash('sha256')
.update(codeVerifier)
.digest('base64url');
// Send code_challenge + code_challenge_method=S256 on /authorize,
// then code_verifier on /token.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.