---
{
  "title": "Proof Key for Code Exchange (PKCE)",
  "summary": "PKCE binds an OAuth authorization-code exchange to a verifier created by the initiating client.",
  "topic": "foundations",
  "level": "Intermediate",
  "updated": "2026-10-12",
  "published": "2026-10-04",
  "units": [
    7
  ],
  "aliases": [],
  "sources": [
    {
      "title": "OWASP: OAuth2",
      "url": "https://cheatsheetseries.owasp.org/cheatsheets/OAuth2_Cheat_Sheet.html"
    },
    {
      "title": "IETF RFC 7636: Proof Key for Code Exchange",
      "url": "https://www.rfc-editor.org/rfc/rfc7636.html"
    }
  ],
  "editorialVersion": 2
}
---

## What it means

PKCE binds an OAuth authorization-code exchange to a verifier created by the initiating client. The authorization request carries a challenge derived from that verifier, and the token exchange presents the verifier. This reduces the usefulness of an intercepted authorization code when correctly implemented.

## A practical example

A public client generates a fresh unpredictable verifier for each flow and uses the recommended challenge method. It stores the verifier only for the relevant exchange and rejects attempts to complete a flow with a mismatched value.

## What to check

Check per-flow randomness, challenge derivation, verifier handling, and enforcement by the authorization server. Review redirect and response-correlation protections separately, because PKCE is one part of the overall flow.

## A common pitfall

PKCE does not replace validating redirect destinations or every other OAuth security requirement. Reusing a predictable verifier defeats the intended binding.

## Think it through

Why must the verifier be unpredictable and fresh?

**Answer:** An interceptor who knows or can reuse it may redeem the code, undermining the protection PKCE is meant to provide.

## The code and verifier travel different paths

A fictional mobile client begins an authorization flow by creating a verifier and deriving its challenge. The challenge accompanies the authorization request, while the verifier is retained for the later token exchange. The authorization server binds the resulting code to that challenge. Possessing the code alone should therefore be insufficient to complete the protected exchange.

This is a binding mechanism, not a hidden client password. A public client still has the properties of a public client, and the user must still be sent to the correct authorization service. The server must enforce the expected challenge method and verify the code exchange; a client generating a verifier is not enough if the server silently accepts an unprotected fallback.

Freshness matters when several login attempts occur at once. Each flow needs its own context, and the client should associate the correct verifier with the correct response. Reusing a fixed value across installations or requests removes the protection's intended unpredictability. Use a maintained library's supported implementation instead of improvising encoding or storage rules.

## Explain a failed exchange

For a local protocol exercise, draw one authorization request and its corresponding token request. Label the challenge and verifier without using real credentials. Then describe what the authorization server should do if the verifier is missing or does not match the challenge. The useful result is an expected rejection, not a successful workaround.

Finally, identify what PKCE does not decide: the registered redirect destination, the resource permissions granted, and the application's interpretation of returned identity information. These remain separate protocol requirements. Understanding that scope prevents a correct PKCE implementation from being mistaken for a complete review of the entire login and delegation design.

## Related concepts

- [[oauth-security]]
- [[randomness]]
- [[identity-federation]]
