PKCE (Proof Key for Code Exchange), pronounced "pixy," is an extension to OAuth 2.0 (RFC 7636) that prevents authorization code interception attacks. Originally designed for public clients (mobile apps, SPAs), PKCE is now recommended for all OAuth clients and required in OAuth 2.1.
In the standard OAuth authorization code flow, an attacker who intercepts the authorization code (via malicious app, URL handler hijacking, or referrer leakage) can exchange it for tokens. Public clients can't use client secrets, making them especially vulnerable.
1. Client generates random code_verifier (43-128 chars)
code_verifier = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
2. Client computes code_challenge from verifier
code_challenge = BASE64URL(SHA256(code_verifier))
code_challenge = "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"
3. Client sends authorization request WITH code_challenge
GET /authorize?
response_type=code&
client_id=CLIENT_ID&
code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&
code_challenge_method=S256&
redirect_uri=...
4. Authorization server stores code_challenge with auth code
5. Client exchanges code WITH code_verifier
POST /token
{
grant_type: authorization_code,
code: AUTH_CODE,
code_verifier: "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk",
redirect_uri: ...
}
6. Server verifies: SHA256(code_verifier) == stored code_challenge
// JavaScript - Generate PKCE parameters
async function generatePKCE() {
// Generate random verifier
const array = new Uint8Array(32);
crypto.getRandomValues(array);
const verifier = base64URLEncode(array);
// Compute challenge
const hash = await crypto.subtle.digest('SHA-256',
new TextEncoder().encode(verifier));
const challenge = base64URLEncode(new Uint8Array(hash));
return { verifier, challenge };
}
function base64URLEncode(buffer) {
return btoa(String.fromCharCode(...buffer))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
code_challenge = BASE64URL(SHA256(code_verifier))code_challenge = code_verifier (no transformation)OAuth 2.1 (draft) makes PKCE mandatory for all clients, including confidential clients. This provides defense-in-depth even when client secrets are used.