Skip to main content
Category: OAuth & OIDC

Proof Key for Code Exchange

Also known as: PKCE, PKCE (pronounced "pixy")
Simply put

Proof Key for Code Exchange (PKCE) is a security extension to the OAuth 2.0 authorization code flow that helps prevent attackers from stealing and misusing the temporary authorization code exchanged during login. It works by having the application create a secret value up front and later prove it holds that same secret when redeeming the code, so an intercepted code cannot be used by anyone else.

Formal definition

PKCE, defined in RFC 7636, is an extension to the OAuth 2.0 authorization code grant that mitigates authorization code injection and, per some sources, CSRF attacks against the flow. The client generates a high-entropy random value called the code verifier and derives a code challenge from it (typically via a transform such as S256); the code challenge is sent on the initial authorization request, and the original code verifier is sent when exchanging the authorization code for tokens at the token endpoint, allowing the authorization server to confirm the same client that initiated the request is redeeming the code. It was originally introduced to strengthen public clients that cannot securely store a client secret, though it is recommended for OAuth clients more broadly; note that PKCE is an authorization-flow protection and is not itself an authentication mechanism. Exact behavior, such as supported challenge methods, depends on the authorization server and deployment configuration.

Why it matters

The OAuth 2.0 authorization code flow relies on a short-lived authorization code that is returned to the client via a redirect and then exchanged at the token endpoint for tokens. If an attacker can intercept that authorization code, through a malicious app registered to the same redirect URI, a compromised inter-app communication channel on a mobile device, or logging and referrer leakage, they may attempt to redeem it for tokens. PKCE, defined in RFC 7636, closes this gap by binding the code to a secret that only the legitimate client possesses, so an intercepted code cannot be redeemed by another party. According to the OAuth community documentation, PKCE prevents authorization code injection and CSRF attacks in the authorization code flow.

PKCE was originally introduced to strengthen public clients, such as native mobile and single-page applications, that cannot securely store a client secret, and it remains especially important there. However, current guidance (per oauth.net) recommends PKCE for OAuth clients more broadly, not only public ones, because the authorization code injection threat is not unique to secret-less clients. Treating PKCE as a default protection for the authorization code grant rather than a niche public-client feature reflects where mainstream practice has moved.

It is worth being precise about scope: PKCE is an authorization-flow protection, not an authentication mechanism. It does not verify who the user is; it ensures that the entity redeeming the authorization code is the same one that initiated the request. Deployments that need user authentication still layer OpenID Connect on top of OAuth 2.0. Exact behavior, including which challenge transforms are supported, depends on the authorization server and deployment configuration.

Who it's relevant to

IAM engineers and application developers
Teams building native mobile apps, single-page applications, and other public clients that cannot securely store a client secret should implement PKCE on the authorization code flow. Developers configuring confidential clients should also consider it, since current guidance recommends PKCE for OAuth clients broadly. Implementation involves generating the code verifier, deriving and sending the code challenge, and supplying the verifier at token exchange.
Security architects
Architects evaluating OAuth 2.0 authorization code deployments should treat PKCE as a baseline mitigation against authorization code injection and, per some sources, CSRF against the flow. When defining standards, note that PKCE protects the authorization flow but is not an authentication mechanism; authentication requirements are addressed separately, for example via OpenID Connect layered on OAuth 2.0.
Platform and identity provider administrators
Administrators configuring authorization servers or identity platforms (for example, following vendor guides such as Okta's) should verify which PKCE challenge methods are supported and whether PKCE is enforced or optional for a given client type, since exact behavior depends on the authorization server and deployment configuration.
Compliance and security reviewers
Reviewers assessing OAuth integrations can use PKCE adoption as a concrete control for the authorization code flow. When auditing, confirm that PKCE is applied where recommended and understand its scope, it defends against code interception and injection but does not by itself establish user identity or replace other authentication and session controls.

Inside PKCE

code_verifier
A high-entropy, cryptographically random string generated by the client before initiating the authorization request. It is retained by the client and never sent in the initial authorization request, so it is not exposed on the front channel.
code_challenge
A value derived from the code_verifier that is sent in the authorization request. In the recommended S256 method it is the base64url-encoded SHA-256 hash of the code_verifier; with the plain method it is the code_verifier itself, which offers no transformation and is generally discouraged.
code_challenge_method
A parameter indicating how the code_challenge was derived from the code_verifier, typically S256 or plain. Authorization servers commonly require S256 where clients can compute a SHA-256 hash.
Authorization server binding and verification
The authorization server associates the code_challenge with the issued authorization code, then, at the token endpoint, verifies the presented code_verifier against that stored challenge before issuing tokens. A mismatch causes the token request to be rejected.

Common questions

Answers to the questions practitioners most commonly ask about PKCE.

Does PKCE authenticate the user or the client application?
No. PKCE does neither in the sense of proving identity. It is a mechanism within the OAuth 2.0 authorization code flow that mitigates authorization code interception; it does not authenticate the end user, and it is not a substitute for client authentication. User authentication is handled by the authorization server (and, for identity claims, by OpenID Connect layered on top of OAuth 2.0). PKCE simply binds the authorization request to the token request so that an intercepted authorization code cannot be redeemed by an attacker who lacks the original secret.
Is PKCE only for public clients like mobile and single-page apps?
PKCE originated to protect public clients that cannot safely store a client secret, but its use is not restricted to them. Current OAuth security guidance typically recommends PKCE for confidential clients using the authorization code flow as well, since it defends against code interception independently of client authentication. Whether it is required depends on the authorization server configuration and the OAuth profile in use, but treating it as public-client-only is out of step with prevailing recommendations.
How do I generate a compliant code verifier and code challenge?
In most deployments the code verifier is a high-entropy, cryptographically random string that the client creates and keeps for the duration of the flow. The code challenge is derived from it, typically using the S256 method (a SHA-256 hash of the verifier, base64url-encoded). A plain method, where the challenge equals the verifier, also exists but is generally discouraged because it offers weaker protection if the authorization request is intercepted. Confirm the exact length and character-set constraints against the applicable specification and your authorization server's requirements.
Which code challenge method should I choose, S256 or plain?
S256 is the preferred method in most implementations because the transmitted challenge is a hash rather than the verifier itself, so intercepting the authorization request does not reveal the value needed at the token endpoint. The plain method should generally be reserved for constrained clients that cannot perform SHA-256, and many authorization servers can be configured to reject plain outright. Verify which methods your authorization server advertises and enforces before selecting one.
What happens at the token endpoint if the verifier does not match?
When the client redeems the authorization code, it sends the original code verifier. The authorization server recomputes the challenge from that verifier using the method registered during the authorization request and compares it to the value it stored. If they do not match, the token request is rejected and no tokens are issued. The exact error response depends on the server, but a mismatch is treated as a failed exchange rather than downgraded silently.
Does using PKCE remove the need for other flow protections like state or nonce?
No. PKCE addresses authorization code interception, but it is not a replacement for other safeguards. The state parameter is still typically used for CSRF protection and request correlation, and in OpenID Connect the nonce is used to bind the ID token to the authentication request. These mechanisms address different threats, so PKCE should be combined with them rather than viewed as a single control that covers all of them; the precise combination depends on your profile and deployment.

Common misconceptions

PKCE is a replacement for the OAuth 2.0 client secret and only applies to public clients such as mobile and single-page apps.
PKCE was introduced primarily to protect public clients that cannot securely store a secret, but guidance in more recent OAuth security practice recommends applying PKCE to confidential clients as well. It complements, rather than universally replaces, client authentication depending on the deployment and profile.
PKCE authenticates the user or provides authentication like OpenID Connect.
PKCE is a mechanism within the OAuth 2.0 authorization code flow that mitigates authorization code interception; it does not authenticate the end user. Authentication in this context is handled separately, for example by OpenID Connect layered on top of OAuth 2.0.
Using PKCE means the authorization code is encrypted or otherwise made confidential in transit.
PKCE does not encrypt the authorization code. It binds the code to a client-held secret (the code_verifier) so that an intercepted code cannot be redeemed by an attacker who lacks the verifier. Transport confidentiality still relies on TLS.

Best practices

Use the S256 code_challenge_method rather than plain wherever the client can compute a SHA-256 hash, and configure the authorization server to reject or discourage the plain method.
Generate the code_verifier using a cryptographically secure random source with sufficient entropy for each authorization request, and never reuse a code_verifier across flows.
Apply PKCE to the authorization code flow for both public and confidential clients where supported, consistent with current OAuth security guidance, rather than treating it as relevant only to public clients.
Ensure the authorization server binds the code_challenge to the issued authorization code and strictly verifies the code_verifier at the token endpoint, rejecting requests on any mismatch.
Continue to enforce TLS for all authorization and token endpoint traffic, since PKCE mitigates code interception but does not by itself provide transport confidentiality.
Store the code_verifier only on the client that initiated the request and for the minimum time needed, avoiding exposure on the front channel or in logs.
Promotional banner graphic asking if you are ready for PCI DSS 4.0 with a call-to-action to get the guide