GitHub Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Authorization Code Flow with Proof Key for Code Exchange

The Authorization Code Flow with Proof Key for Code Exchange (PKCE) is an OAuth 2.0 flow that is used to secure the authorization process in native applications and single-page applications (SPAs). It is an extension to the standard authorization code flow, and it adds a step that helps to prevent authorization code interception attacks.

A description of the authorization code flow with PKCE:

  1. The client application initiates the authorization process by directing the user’s browser to the authorization server. The client includes a number of parameters in the request, such as the client_id, the redirect_url, and the scope of the authorization request.
  2. The authorization server prompts the user to log in and grant authorization to the client. If the user grants authorization, the authorization server sends an authorization code to the client’s redirect URI.
  3. The client receives the authorization code and sends a request to the token endpoint to exchange the code for an access token. In this request, the client includes the authorization_code, the client_id, and the client_secret (if the client is confidential).
  4. To secure the authorization process, the client also includes a code_verifier in the request. The code verifier is a cryptographically random string that is generated by the client, and it is used to prove that the client is the same one that initiated the authorization request.
  5. The authorization server verifies the authorization_code and the code_verifier, and if they are valid, it issues an access_token to the client. The access token can then be used to access the API resources on behalf of the user.

The main advantage of the authorization code flow with PKCE is that it helps to prevent authorization code interception attacks. In these attacks, an attacker tries to intercept the authorization code as it is being sent from the authorization server to the client’s redirect URI. If the attacker is successful, they can use the authorization code to obtain an access token and access the API resources on behalf of the user.

To prevent this from happening, the authorization code flow with PKCE adds a step in which the client generates a code verifier and sends it to the authorization server along with the authorization code. The authorization server uses the code verifier to verify that the client is the same one that initiated the authorization request, and it only issues an access token if the code verifier is valid. This helps to ensure that the authorization process is secure and that only the intended client can obtain an access token.

In general, it is a good idea to use PKCE whenever you are using the authorization code flow, unless you have a specific reason not to. For example if you are using a client library or framework that does not support PKCE: PKCE is a relatively new extension to OAuth 2.0, so some client libraries or frameworks might not yet support it. In this case, you would not be able to use PKCE with these libraries or frameworks. Consider to update the client library.

Clients as describes in tenant and client configuration can be set to except PKCE-only clients. This should be the default and could be the default if not set explicitly to false in the configuration of the client.

Generating a code verifier

If not covered by the client library you use, then a code verifier can be calculated easily by your own.

To calculate a code verifier in the client, you can use a cryptographically secure random number generator (CSPRNG) to generate a random string of sufficient length and complexity. The code verifier should be at least 43 characters long and consist of upper and lower case letters, digits, and special characters.

Example of how you might generate a code verifier in a JavaScript client:

function generateCodeVerifier() {
    const charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~';
    let codeVerifier = '';
    for (let i = 0; i < 43; i++) {
        codeVerifier += charset[Math.floor(Math.random() * charset.length)];
    }
    return codeVerifier;
}

This function uses the Math.random() function to generate random numbers, and it uses these numbers to select characters from a predefined character set. It then concatenates the selected characters to form a random string of 43 characters.

You can use a similar approach to generate a code verifier in other programming languages. Just make sure to use a CSPRNG to ensure that the code verifier is truly random and secure.

Once you have generated the code verifier, you will need to create a code_challenge from it. The code challenge is a hashed version of the code verifier that is sent to the authorization server in the authorization request. You can create the code challenge by running the code verifier through a SHA-256 hash function, and then base64-url encoding the result.

To create a code_challenge in JavaScript, you can use the crypto module to perform the SHA-256 hash and the btoa function to perform the base64-url encoding.

Here’s an example of how you could create a code_challenge in JavaScript:

const crypto = require('crypto');

function createCodeChallenge(codeVerifier) {
    // Perform SHA-256 hash of codeVerifier
    const hash = crypto.createHash('sha256');
    hash.update(codeVerifier);
    const codeChallenge = hash.digest('base64');

    // Base64-url encode the code challenge
    return codeChallenge.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}

const codeVerifier = generateCodeVerifier();
const codeChallenge = createCodeChallenge(codeVerifier);

Further readings