Proof Key for Code Exchange by OAuth Public Clients


Proof Key for Code Exchange by OAuth Public Clients specification defined in RFC 7636 adds additional parameters to the OAuth 2.0 Authorization Request and Access Token Requests.

OAuth 2.0 OAuth Public Clients utilizing the Authorization Code Grant are susceptible to the authorization code interception attack. Proof Key for Code Exchange by OAuth Public Clients specification describes the attack as well as a technique to mitigate against the threat through the use of Proof Key for Code Exchange (PKCE, pronounced "pixy").

Proof Key for Code Exchange by OAuth Public Clients extension utilizes a dynamically created cryptographically random key called "code_verifier".

A unique Code_verifier is created for every authorization Request, and its transformed value, called "code_challenge", is sent to the Authorization Server to obtain the Authorization Code. The Authorization Code obtained is then sent to the Token_endpoint with the "code verifier", and the Authorization Server compares it with the previously received request code so that it can perform the Proof-of-Possession of the "code verifier" by the client. This works as the mitigation since the attacker would not know this one-time key, since it is sent over TLS and cannot be intercepted.

"how (PKCE) would mitigate the issue where the browser-based app can't store the client secret securely"#

Because there are no Client Secrets using PKCE.
PKCE works by having the application generate a random the unique string value at the beginning of the flow called a code_verifier. The Application hashes the code_verifier and the result is called the code_challenge. The Application then kicks off the Authorization Code Flow, EXCEPT without the Client Secret but includes the code_challenge in the query string for the Authorization Request to the Authorization Server.

3. Terminology#

In addition to the terms defined in OAuth 2.0 RFC 6749, this specification defines the following terms:

4. Protocol#

4.1. OAuth Client creates a code verifier#

The OAuth Client first creates a code_verifier, "code_verifier", for each OAuth 2.0 RFC 6749 Authorization Request

4.2. OAuth Client creates the code_challenge#

The OAuth Client then creates a code_challenge derived from the code_verifier

4.3. OAuth Client sends the code challenge with the Authorization Request#

The client sends the code_challenge as part of the OAuth 2.0 Authorization Request (Section 4.1.1 of RFC 6749.)

4.4. Server returns the code#

When the Authorization Server issues the Authorization Code in the Authorization Response, it MUST associate the code_challenge and code_challenge_method values with the Authorization Code so it can be verified later.

Typically, the code_challenge and code_challenge_method values are stored in encrypted form in the "code" itself, but could alternatively be stored on the server, associated with the code. The server MUST NOT include the code_challenge value in client requests in a form that other entities can extract.

The exact method that the Authorization Server uses to associate the code_challenge with the issued "code" is out of scope for this specification.

4.4.1. Error Response If the server requires Proof Key for Code Exchange by OAuth Public Clients (PKCE) by OAuth Public Clients, and the OAuth Client does not send the code_challenge in the request, the Authorization_endpoint MUST return the authorization error response with "error" value set to "invalid_request". The "error_description" or the response of "error_uri" SHOULD explain the nature of error, e.g., Code_challenge required.

If the server supporting PKCE does not support the requested transform, the authorization endpoint MUST return the authorization error response with "error" value set to "invalid_request". The "error_description" or the response of "error_uri" SHOULD explain the nature of error, e.g., transform algorithm not supported.

4.5. Client sends the Authorization Code and the Code Verifier to the Token_endpoint#

Upon receipt of the Authorization Code, the client sends an Access Token Request to the Token_endpoint.

4.6. Server verifies code_verifier before returning the tokens#

Upon receipt of the request at the Token_endpoint, the server verifies it by calculating the code_challenge from received code_verifier and comparing it with the previously associated code_challenge, after first transforming it according to the code_challenge_method method specified by the client.

If the code_challenge_method from Section 4.2 was "S256", the received code_verifier is hashed by SHA-256, then base64url encoded, and then compared to the "code_challenge". i.e.,

code_challenge = base64url.encode(crypto.createHash('sha256').update(code_verifier).digest());

If the "code_challenge_method" from Section 4.2 was "plain", they are compared directly. i.e.,

"code_verifier" == "code_challenge".
If the values are equal, the Access Token_endpoint MUST continue processing as normal (as defined by OAuth 2.0 RFC 6749). If the values are not equal, an error response indicating "invalid_grant" as described in section 5.2 of RFC 6749 MUST be returned.

5. Compatibility#

Server implementations of this specification MAY accept OAuth Clients that do not implement this extension. If the code_verifier is not received from the OAuth Client in the Authorization Request, servers supporting backwards compatibility revert to a normal OAuth 2.0 RFC 6749 protocol.

As the OAuth 2.0 RFC 6749 server responses are unchanged by this specification, client implementations of this specification do not need to know if the server has implemented this specification or not, and SHOULD send the additional parameters as defined in Section 3. to all servers.

Proof Key for Code Exchange by OAuth Public Clients (PKCE)#

Although not part of the current OAuth 2.0 Security Best Current Practice (BCP)it has been proposed to make PKCE REQUIRED.

PKCE solves two problems:

The section of the OAuth 2.0 Security Best Current Practice BCP (4.5.3). Proposed Countermeasures) which says clients can do PKCE or use the nonce, is only talking about preventing authorization_code injection.

The nonce parameter solves authorization code injection if the client requests an Id_token. OAuth Public Clients using the nonce parameter are still susceptible to stolen authorization_codes so they still need to do PKCE as well.

The only case where OpenID Connect clients do not benefit from PKCE is if they are also OAuth Confidential Clients. OAuth Public Clients (even OIDC clients) still need to do PKCE even if they check the nonce.

More Information#

There might be more information for this subject on one of the following: