Skip to content

PKCE (Proof Key for Code Exchange)

PKCE (Proof Key for Code Exchange) is a critical security extension for OAuth 2.0. It was originally designed for mobile apps and Single Page Applications (SPAs) but is now a “Best Current Practice” (BCP) for all OAuth clients, including server-side apps.

SECURITY

Critical Extension
Core Mission
Code Interception Defense. Preventing an attacker from using an authorization code even if they successfully intercept it in the browser redirect.
Like a Secret Handshake: You announce a "challenge" at the front door. To enter the back room, you must provide the "secret verifier" that matches that specific challenge. An observer only sees the challenge, which is useless without the secret.
Mobile / SPA / Public Clients

PKCE adds a local cryptographic step before the redirect and a validation step during the token exchange.

1

Generate (Local)

The client creates a random `code_verifier` and its SHA-256 hash, the `code_challenge`.

2

Commit (Auth Request)

The client sends the `code_challenge` in the initial authorization request to the server.

3

Prove (Token Export)

The client sends the raw `code_verifier` during the token exchange. The server verifies it matches the previous challenge.

Without PKCE, public clients (which cannot keep a secret) are vulnerable to authorization code injection and interception.

ThreatMitigated by PKCE?Mechanism
Code InterceptionYesAttacker lacks the code_verifier required to swap the code.
Man-in-the-MiddleYesBinds the token exchange to the specific initiation request.
Reverse EngineeringYesChallenges are unique per session; static secrets are not used.
// 1. Generate a Code Verifier
const verifier = generateRandomString(128);
// 2. Generate a Code Challenge (SHA-256)
async function generateChallenge(verifier) {
const encoder = new TextEncoder();
const data = encoder.encode(verifier);
const digest = await window.crypto.subtle.digest('SHA-256', data);
return b64url(digest);
}
// 3. Initiate Auth Request
const authUrl = `https://auth.com/authorize?` +
`response_type=code&` +
`code_challenge=${await generateChallenge(verifier)}&` +
`code_challenge_method=S256&...`;

Learn how PKCE fits into the broader secure authentication landscape.

EOF < /dev/null