MiniUtil field guide

OAuth PKCE: code_verifier, code_challenge, and S256

How PKCE protects an authorization code exchange, what the verifier and challenge must contain, and why S256 should always be used instead of plain.

Short answer: Generate a fresh high-entropy verifier of 43 to 128 characters per request, send the base64url SHA-256 digest as the challenge with method S256, and keep the verifier out of logs and URLs.

PKCE binds the code to the client that asked for it

In the authorization code flow the code travels back through the user agent, where it can be intercepted through a redirect, a log, or a malicious application registered for the same custom scheme. PKCE makes an intercepted code useless on its own: the token request must also present the original verifier, which never left the client that started the exchange.

The verifier has explicit content requirements

A code verifier is 43 to 128 characters drawn from the unreserved set of letters, digits, hyphen, period, underscore, and tilde. The practical way to satisfy both the length and the entropy expectation is to generate at least 32 random octets from a cryptographically secure source and base64url-encode them without padding, which yields 43 characters. Generate a new one for every authorization request.

  • Use a cryptographically secure random source, never a general-purpose random function.
  • Never reuse a verifier across requests or sessions.
  • Keep the verifier out of logs, analytics, and the browser address bar.

Use S256 rather than plain

With method S256 the challenge is the base64url encoding of the SHA-256 digest of the ASCII verifier, so the authorization request reveals nothing that can be replayed. With method plain the challenge is the verifier itself, which removes the protection for anyone who can observe the authorization request. Clients capable of computing SHA-256 are required to use S256, and current security guidance expects authorization servers to support PKCE.

state and PKCE solve different problems

The state parameter ties the redirect back to the session that began it and defends against cross-site request forgery on the callback. PKCE defends the code exchange itself. Sending one is not a substitute for the other, and a nonce in an OpenID Connect flow addresses a third concern, namely binding the identity token to the authentication request.

Challenge methods

MethodChallenge valueWhen it is acceptable
plainThe verifier, sent as isOnly when the client genuinely cannot compute SHA-256
S256base64url of SHA-256 over the verifierAlways preferred, and required when the client can support it