Auth Code Flow with PKCE
The recommended OAuth 2.0 flow for browser and mobile apps — Authorization Code with PKCE adds a dynamic proof that stops an intercepted authorization code from being usable by an attacker.
What is Authorization Code flow with PKCE?
The Authorization Code flow with PKCE (Proof Key for Code Exchange) is the recommended OAuth 2.0 flow for user login in browser-based and mobile applications. The base Authorization Code flow is OAuth’s most secure flow — the user authenticates at the identity provider, which returns a short-lived authorization code that the app then exchanges for tokens — and PKCE (pronounced “pixie”) is a security extension that protects that exchange for “public” clients (apps that can’t keep a secret), closing an interception attack. Together they’re the modern standard for “Sign in with…” in SPAs and mobile apps, replacing the now-deprecated Implicit flow.
The problem PKCE solves — intercepted authorization codes
To see why PKCE exists, follow the base flow’s weak point for public clients. In the Authorization Code flow, the IdP redirects back to the app with an authorization code, which the app swaps for access/ID tokens at the token endpoint. For a confidential server-side app, that swap is authenticated with a client secret, so a stolen code is useless without the secret. But public clients — SPAs and mobile apps — can’t safely hold a client secret (anyone can extract it from JavaScript or a decompiled app), so historically they used the Implicit flow (tokens returned directly in the redirect) which had real weaknesses, or the code flow without a secret, which left a gap: if an attacker could intercept the authorization code (via a malicious app registered for the same redirect URI on mobile, browser history, logs, or a compromised redirect), they could exchange it for tokens themselves. PKCE closes this. Before starting, the app generates a random secret called the code verifier and sends a hashed version, the code challenge, with the initial authorization request. When it later exchanges the code for tokens, it must present the original code verifier; the IdP hashes it and checks it matches the challenge from the start. So even if an attacker intercepts the authorization code, they can’t use it — they don’t have the code verifier, which never left the legitimate app. PKCE effectively provides a dynamic, per-request secret that a public client can safely use, replacing the static client secret it can’t protect.
Why it’s the standard now, and the practical points
PKCE with the Authorization Code flow is now the recommended approach for all OAuth clients (the OAuth 2.1 direction makes it effectively mandatory, and recommends it even for confidential clients as defense-in-depth), and the Implicit flow is deprecated for security reasons (it exposed tokens in URLs and lacked PKCE’s protection). The practical guidance: for user login in a browser or mobile app, use Authorization Code + PKCE, and don’t reach for the Implicit flow (obsolete) or try to embed a client secret in a public client (impossible to protect — that’s exactly what PKCE replaces). This is distinct from the client credentials flow, which is for machine-to-machine auth with no user — the two solve different problems (user delegation vs service-as-itself), and choosing the wrong one is a common error. Alongside PKCE, correct implementation still requires the usual token hygiene: validate the returned ID token (signature, issuer, audience, expiry), use exact redirect-URI matching, and protect against CSRF on the redirect with the state parameter. The recurring mistakes: still using the deprecated Implicit flow, attempting to put a client secret in an SPA/mobile app, omitting the state parameter (leaving the redirect open to CSRF), and skipping ID-token validation.
What people get wrong
- Using the deprecated Implicit flow — it’s obsolete and less secure; Authorization Code + PKCE is the current standard for SPAs and mobile apps.
- Trying to use a client secret in a public app: SPAs and mobile apps can’t protect a secret — PKCE’s dynamic verifier is precisely the replacement, so don’t embed a static secret.
- Skipping
stateand token validation — omit the CSRF-protectingstateparameter or the ID-token signature/issuer/audience checks and you reopen holes PKCE alone doesn’t cover.
Primary source: RFC 7636: Proof Key for Code Exchange (PKCE)
Historical figures and technical concepts for informational purposes only. Not technical, professional, legal, or financial advice. Sources: Official Documentation.