Stackvora.tech

OAuth 2.0 + PKCE Walkthrough

Modern OAuth 2.1 flow with PKCE explained for web and mobile apps — with a real code example.

OAuth 2.1 with PKCE (Proof Key for Code Exchange) is the recommended flow for any public client — SPAs, mobile apps and desktop apps — because it removes the need for a client secret while still preventing authorization-code interception attacks.

The flow at a glance

  1. Client generates a random code_verifier (43–128 URL-safe chars).
  2. Client derives code_challenge = BASE64URL(SHA256(code_verifier)).
  3. Client redirects the user to /authorize with code_challenge and code_challenge_method=S256.
  4. Auth server returns an authorization code to the redirect URI.
  5. Client exchanges the code at /token, sending the original code_verifier.
  6. Auth server verifies the SHA-256 hash matches and issues an access token.

Working JavaScript example

function base64url(buf) {
  return btoa(String.fromCharCode(...new Uint8Array(buf)))
    .replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}

async function pkcePair() {
  const verifier = base64url(crypto.getRandomValues(new Uint8Array(32)));
  const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier));
  return { verifier, challenge: base64url(digest) };
}

const { verifier, challenge } = await pkcePair();
sessionStorage.setItem("pkce_verifier", verifier);

const params = new URLSearchParams({
  response_type: "code",
  client_id: CLIENT_ID,
  redirect_uri: REDIRECT_URI,
  code_challenge: challenge,
  code_challenge_method: "S256",
  scope: "openid profile email",
  state: crypto.randomUUID(),
});
window.location.href = `${AUTH_URL}?${params}`;

Common mistakes

  • Storing code_verifier in localStorage — use sessionStorage or an httpOnly cookie so an XSS on another tab can't steal it.
  • Using SHA-1 or the plain method — always use S256.
  • Skipping the state parameter — it prevents CSRF on the callback.
  • Not rotating refresh tokens — 2.1 mandates rotation for public clients.

When PKCE is NOT enough

PKCE prevents code interception, not token theft. If the browser gets XSSed after login, the attacker still gets the access token. Pair PKCE with:

  • Short-lived access tokens (5–15 minutes).
  • Rotating refresh tokens.
  • Strict CSP that disallows inline scripts.

Back to the knowledge base · Ask the AI assistant