OAuth PKCE - Secure Authorization for Public Clients
About 2 min read
PKCE (Proof Key for Code Exchange, pronounced "pixy") is a security extension added to the authorization code flow of OAuth 2.0. It was standardized as RFC 7636 in 2015. Originally designed for public clients such as mobile apps that cannot securely store a client_secret, its effectiveness has led to OAuth 2.1 moving toward making it mandatory for all client types.
What Is an Authorization Code Interception Attack
To understand the threat that PKCE solves, you first need to know how the attack works. In the OAuth 2.0 authorization code flow, after the user logs in at the authorization server, the authorization code is returned to the client via the redirect URI. On mobile operating systems, redirection uses custom URL schemes (e.g., myapp://), but if a malicious app registers the same URL scheme, it can intercept the authorization code.
SPAs (Single Page Applications) face a similar risk, because the authorization code can leak through the browser history, the referrer header, or browser extensions.
How code_verifier and code_challenge Work
PKCE cryptographically guarantees that "only the party that sent the authorization request can obtain the token." The mechanism is simple and uses two values.
| Element | When it is generated | Role |
|---|---|---|
| code_verifier | Generated by the client before the authorization request | A random string of 43-128 characters. A secret held only by the client |
| code_challenge | Derived from code_verifier | The Base64URL encoding of the SHA-256 hash. Included in the authorization request |
Even if an attacker intercepts the authorization code, they cannot obtain a token without the code_verifier. Because code_verifier cannot be reverse-derived from code_challenge (the one-way property of SHA-256), intercepting the authorization request is meaningless.
Why It Is Necessary for Public Clients
In traditional OAuth 2.0, confidential clients (server-side apps) could protect the token endpoint with a client_secret. However, because the source code of SPAs and mobile apps is in the user's hands, a client_secret cannot be embedded securely. PKCE solves this problem, allowing the legitimate owner of an authorization code to be proven even without a client_secret.
PKCE is also effective as a countermeasure against CSRF. Unlike the state parameter, PKCE performs cryptographic verification, providing more robust protection. Combining it with the management of session tokens improves the security of the entire authentication flow.
Becoming Mandatory in OAuth 2.1
In OAuth 2.1 (in draft as of 2025), PKCE becomes mandatory for all client types. Even confidential clients must use PKCE. This is based on the idea of "defense in depth." Even if a client_secret leaks, PKCE can still prevent interception of the authorization code. When using OpenID Connect as well, the use of PKCE is strongly recommended.
Common Implementation Mistakes
- Using plain for code_challenge_method. Since plain sends the code_verifier itself as the code_challenge, it is meaningless if intercepted. Always use S256 (SHA-256)
- Storing the code_verifier in local storage instead of session storage. This increases the risk of it being read by an XSS attack
- Insufficient entropy in the code_verifier. Use a cryptographically secure random number generator (the Web Crypto API's getRandomValues)
Reading the articles on the pitfalls of OAuth permissions and API key management together will give you a clearer picture of the security design of the entire authorization flow. Knowing when to use an API key instead is also an important decision point in practice.OAuth security books on Amazon are also recommended for systematic learning.
Was this article helpful?