The problem with public clients
Mobile and single page apps are public clients: they cannot safely keep a client secret because their code ships to users. Without a secret, a stolen authorization code could be redeemed by an attacker. PKCE, proof key for code exchange, fixes this.
A per request proof
Before starting the flow the client generates a random code verifier and derives a hashed code challenge from it. The steps are:
- Send the code challenge with the authorization request.
- Receive the authorization code in the redirect as usual.
- Send the original code verifier when exchanging the code.
The authorization server hashes the verifier and checks it matches the earlier challenge. An attacker who intercepts only the code cannot complete the exchange because they never saw the verifier.
Why hashing matters
Sending the challenge rather than the verifier in the first leg means anyone watching the authorization request still cannot derive the verifier, since a hash is one way.
Key idea
PKCE binds the token exchange to a secret verifier known only to the original client, so a public client stays safe even if its authorization code is intercepted.