---
title: Authorization code grant with PKCE
description: /oauth2/authorize
component: pingam
version: 7.2
page_id: pingam:oauth2-guide:oauth2-authz-grant-pkce
canonical_url: https://docs.pingidentity.com/pingam/8.1/am-oauth2/oauth2-authz-grant-pkce.html
llms_txt: https://docs.pingidentity.com/pingam/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
superseded_by: https://docs.pingidentity.com/pingam/8.1/am-oauth2/oauth2-authz-grant-pkce.html
section_ids:
  proc-auth-code-generate-pkce: Generate a code verifier and a code challenge
  proc-auth-code-browser-pkce: Obtain an authorization code using a browser
  proc-auth-code-no-browser-pkce: Obtain an authorization code without using a browser
  proc-auth-code-token-pkce: Exchange an authorization code for an access token
---

# Authorization code grant with PKCE

* Endpoints

  * [/oauth2/authorize](oauth2-authorize-endpoint.html)

  * [/oauth2/access_token](oauth2-access_token-endpoint.html)

The authorization code grant, when combined with the PKCE standard ([RFC 7636](https://www.rfc-editor.org/info/rfc7636)), is used when the client, usually a mobile or a JavaScript application, requires access to protected resources.

The flow is similar to the regular authorization code grant type, but the client must generate a code that will be part of the communication between the client and the authorization server. This code mitigates against interception attacks performed by malicious users.

Since communication between the client and the authorization server is not secure, clients are usually *public* so their secrets do not get compromised. Also, browser-based clients making OAuth 2.0 requests to different domains must implement Cross-Origin Resource Sharing (CORS) calls to access OAuth 2.0 resources in different domains.

The PKCE flow adds three parameters on top of those used for the authorization code grant:

* **code_verifier** (form parameter). Contains a random string that correlates the authorization request to the token request.

* **code_challenge** (query parameter). Contains a string derived from the code verifier that is sent in the authorization request and that needs to be verified later with the code verifier.

* **code_challenge_method** (query parameter). Contains the method used to derive the code challenge.

![OAuth 2.0 Authorization Code Grant with PKCE Flow](https://kroki.io/plantuml/svg/eNp1lE1r4zAQhu_-FUN6KAuO080xlIAJFBa27JK2t0BQ5HGsrSx5JTnZ9tfvSIrt2DQ52dJ8PO87Ey_uE6DfRjcfRhwrB8uH78v58mG5BHjS5ohbzd8hf8kglxK2PsTCFi2aExZJyH2zCLoEVwkLXBcIBv-2wqAFRu91jYYLJsHq0p2ZQZCCo6Kcs3DVuEcop0280SqUFdSPlaWQgjm0EaOlbFsxejog4D8uWytOKD_Atoc_yF2o4zS98qpvd0B3RlTE2SMgMFVMEELuq4YjKjTUkkRY0oOKIxSCHQ2roTS6jnqJC1NojOZobUgVLuL_lky5t-efKVTONavFovEHbS0zq1vDsfRdM4Vu0ZXPKlfL5H6RJKx1WrX1AQ3MHg_ru7tvsyRpmHGCi4aqwIwmEKrArzNh7hTNwMxzYnYzYDaejjM2UnS38XF8nT_vVN66ShvxyZzQCl78iE1I8Bef8f0GxlVwd3aJT2K3-TowrWBj0LsaFoX7GaI6xjmEI0oRpUCT7dRrhSqlZSpol7jLMppNqDFfX_GsgC7ISyDPKJ7QAn0X-zgJzocov6cXeu1DPcNOca1KYerhjvEw2uSqTK_lRwmc-HxBJmlNablPTIoiBeu0iSL3vcid6lQOZ_sayfMi6P9KaTQviAxbxUYjCo7RnneZ-9aIbHB8pHzrt8y6ix7Keqf_wo2a6U5dl0wjdDeaiRcdojdjpC2I-gJ4sMm3ca1RI6iBf7xJg4R-NhF_lDvOueFBFB8YIpcnFYrWqA7vE4VTDlI6cpG-A4Me22gqFshGFadgV7bdLhbMoa-Lo0lg0QtP_gP4SAiD?id=figure-oauth2-authz-2)Figure 1. OAuth 2.0 Authorization Code Grant with PKCE Flow

> **Collapse: Authorization code grant with PKCE flow explained**
>
> 1. The client receives a request to access a protected resource. To access the resources, the client requires authorization from the resource owner. When using the PKCE standard, the client must generate a unique code and a way to verify it, and append the code to the request for the authorization code.
>
> 2. The client redirects the resource owner's user-agent to the authorization server.
>
> 3. The authorization server authenticates the resource owner, confirms resource access, and gathers consent if not previously saved.
>
> 4. If the resource owner's credentials are valid, the authorization server stores the code challenge and redirects the resource owner's user agent to the redirection URI.
>
> 5. During the redirection process, the authorization server appends an authorization code to the request to the client.
>
> 6. The client receives the authorization code and calls the authorization server's token endpoint to exchange the authorization code for an access token appending the verification code to the request.
>
> 7. The authorization server verifies the code stored in memory using the validation code. It also verifies the authorization code. If both codes are valid, the authorization server returns an access token (and a refresh token, if configured) to the client.
>
> 8. The client requests access to the protected resources from the resource server.
>
> 9. The resource server contacts the authorization server to validate the access token.
>
> 10. The authorization server validates the token and responds to the resource server.
>
> 11. If the token is valid, the resource server allows the client to access the protected resources.

Perform the steps in the following procedures to obtain an authorization code and exchange it for an access token:

* [Generate a code verifier and a code challenge](#proc-auth-code-generate-pkce)

* [Obtain an authorization code using a browser](#proc-auth-code-browser-pkce)

* [Obtain an authorization code without using a browser](#proc-auth-code-no-browser-pkce)

* [Exchange an authorization code for an access token](#proc-auth-code-token-pkce)

## Generate a code verifier and a code challenge

The client application must be able to generate a code verifier and a code challenge. For details, see the PKCE standard ([RFC 7636](https://www.rfc-editor.org/info/rfc7636)). The information contained in this procedure is for example purposes only:

1. The client generates the code challenge and the code verifier. Creating the challenge using a SHA-256 algorithm is mandatory if the client supports it, as per the RFC 7636 standard.

   The following is an example of a code verifier and code challenge written in JavaScript:

   ```javascript
   function base64URLEncode(words) {
      return CryptoJS.enc.Base64.stringify(words)
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=/g, '');
   }
   var verifier = base64URLEncode(CryptoJS.lib.WordArray.random(50));
   var challenge = base64URLEncode(CryptoJS.SHA256(verifier));
   ```

   This example generates values such as `ZpJiIM_G0SE9WlxzS69Cq0mQh8uyFaeEbILlW8tHs62SmEE6n7Nke0XJGx_F4OduTI4` for the code verifier and `j3wKnK2Fa_mc2tgdqa6GtUfCYjdWSA5S23JKTTtPF8Y` for the code challenge. These values will be used in subsequent procedures.

   The client is now ready to request an authorization code.

2. The client performs the steps in one of the following procedures to request an authorization code:

   * [Obtain an authorization code using a browser](#proc-auth-code-browser-pkce)

   * [Obtain an authorization code without using a browser](#proc-auth-code-no-browser-pkce)

## Obtain an authorization code using a browser

This procedure assumes the following configuration:

* AM is configured as an OAuth 2.0 authorization server. Ensure that:

  * The `code` plugin is configured in the Response Type Plugins field.

  * The `Authorization Code` grant type is configured in the Grant Types field.

  |   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
  | - | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  |   | The `Code Verifier Parameter Required` setting (Realms > *Realm Name* > Services > OAuth2 Provider > Advanced) specifies whether AM requires clients to include a code verifier in their calls. However, if a client makes a call to AM with the `code_challenge` parameter, AM will honor the code exchange regardless of the `Code Verifier Parameter Required` value. For more information, see [Authorization server configuration](oauth2-configure-authz.html). |

* A public client called `myClient` is registered in AM with the following configuration:

  * **Scopes**: `write`

  * **Response Types**: `code`

  * **Grant Types**: `Authorization Code`

For more information, see [Client registration](oauth2-register-client.html).

Perform the steps in this procedure to obtain an authorization code using a browser:

1. The client redirects the resource owner's user-agent to the authorization server's authorization endpoint specifying, at least, the following query parameters:

   * **client_id**=*your-client-id*

   * **response_type**=code

   * **redirect_uri**=*your-redirect-uri*

   * **code_challenge**=*your-code-challenge*

   * **code_challenge_method**=S256

   For information about the parameters supported by the `/oauth2/authorize` endpoint, see [/oauth2/authorize](oauth2-authorize-endpoint.html).

   If the OAuth 2.0 provider is configured for a subrealm rather than the Top Level Realm, you must specify it in the endpoint. For example, if the OAuth 2.0 provider is configured for the `/customers` realm, then use `/oauth2/realms/root/realms/customers/authorize`.

   For example:

   ```none
   https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/authorize \
   ?client_id=myClient \
   &response_type=code \
   &scope=write \
   &redirect_uri=https://www.example.com:443/callback \
   &code_challenge=j3wKnK2Fa_mc2tgdqa6GtUfCYjdWSA5S23JKTTtPF8Y \
   &code_challenge_method=S256 \
   &state=abc123
   ```

   Note that the URL is split and spaces have been added for readability purposes and that the `scope` and `state` parameters have been included. Scopes are not required, since they can be configured by default in the authorization server and the client, and have been added only as an example. The `state` parameter is added to protect against CSRF attacks.

2. The resource owner authenticates to the authorization server, for example, using the credentials of the `demo` user. In this case, they log in using the default chain or tree configured for the realm.

   After logging in, the authorization server presents the AM consent screen:

   ![The OAuth 2.0 AM user interface consent screen requesting access to the write scope.](_images/oauth2-authz-page-xui.png)Figure 2. OAuth 2.0 Consent Screen

3. The resource owner selects the `Allow` button to grant consent for the `write` scope.

   The authorization server redirects the resource owner to the URL specified in the `redirect_uri` parameter.

4. Inspect the URL in the browser.

   It contains a `code` parameter with the authorization code the authorization server has issued.

   For example:

   ```
   http://www.example.com/?code=ZNSDo8LrsI2w-6NOCYKQgvDPqtg&scope=write&iss=https%3A%2F%2Fopenam.example.com%3A8443%2Fopenam%2Foauth2&state=abc123&client_id=myClient
   ```

5. The client performs the steps in [Exchange an authorization code for an access token](#proc-auth-code-token-pkce) to exchange the authorization code for an access token.

## Obtain an authorization code without using a browser

This procedure assumes the following configuration:

* AM is configured as an OAuth 2.0 authorization server. Ensure that:

  * The `code` plugin is configured in the Response Type Plugins field.

  * The `Authorization Code` grant type is configured in the Grant Types field.

  |   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
  | - | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  |   | The `Code Verifier Parameter Required` setting (Realms > *Realm Name* > Services > OAuth2 Provider > Advanced) specifies whether AM requires clients to include a code verifier in their calls. However, if a client makes a call to AM with the `code_challenge` parameter, AM will honor the code exchange regardless of the `Code Verifier Parameter Required` value. For more information, see [Authorization server configuration](oauth2-configure-authz.html). |

* A public client called `myClient` is registered in AM with the following configuration:

  * **Scopes**: `write`

  * **Response Types**: `code`

  * **Grant Types**: `Authorization Code`

For more information, see [Client registration](oauth2-register-client.html).

Perform the steps in this procedure to obtain an authorization code:

1. The resource owner logs in to the authorization server, for example, using the credentials of the `demo` user.

   For example:

   ```
   $ curl \
   --request POST \
   --header "Content-Type: application/json" \
   --header "X-OpenAM-Username: demo" \
   --header "X-OpenAM-Password: Ch4ng31t" \
   --header "Accept-API-Version: resource=2.0, protocol=1.0" \
   'https://openam.example.com:8443/openam/json/realms/root/realms/alpha/authenticate'
   {
       "tokenId":"AQIC5wM…​TU3OQ*",
       "successUrl":"/openam/console",
       "realm":"/alpha"
   }
   ```

2. The client makes a POST call to the authorization server's authorization endpoint specifying in a cookie SSO token of the `demo` and, at least, the following parameters:

   * **client_id**=*your-client-id*

   * **response_type**=code

   * **redirect_uri**=*your-redirect-uri*

   * **decision**=allow

   * **csrf**=*demo-user-SSO-token*

   * **code_challenge**=*your-code-challenge*

   * **code_challenge_method**=S256

   For information about the parameters supported by the `/oauth2/authorize` endpoint, see [/oauth2/authorize](oauth2-authorize-endpoint.html).

   If the OAuth 2.0 provider is configured for a subrealm rather than the Top Level Realm, you must specify it in the endpoint. For example, if the OAuth 2.0 provider is configured for the `/customers` realm, then use `/oauth2/realms/root/realms/customers/authorize`.

   For example:

   ```bash
   $ curl --dump-header - \
   --request POST \
   --Cookie "iPlanetDirectoryPro=AQIC5wM…​TU3OQ*" \
   --data "redirect_uri=https://www.example.com:443/callback" \
   --data "scope=write" \
   --data "response_type=code" \
   --data "client_id=myClient" \
   --data "csrf=AQIC5wM…​TU3OQ*" \
   --data "state=abc123" \
   --data "decision=allow" \
   --data "code_challenge=j3wKnK2Fa_mc2tgdqa6GtUfCYjdWSA5S23JKTTtPF8Y" \
   --data "code_challenge_method=S256" \
   "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/authorize"
   ```

   Note that the `scope` and the `state` parameters have been included. Scopes are not required, since they can be configured by default in the authorization server and the client, and have been added only as an example. The `state` parameter is added to protect against CSRF attacks.

   If the authorization server is able to authenticate the user and the client, it returns an HTTP 302 response with the authorization code appended to the redirection URL:

   ```json
   HTTP/1.1 302 Found
   Server: Apache-Coyote/1.1
   X-Frame-Options: SAMEORIGIN
   Pragma: no-cache
   Cache-Control: no-store
   Date: Mon, 30 Jul 2018 11:42:37 GMT
   Accept-Ranges: bytes
   Location: http://www.example.com?code=g5B3qZ8rWzKIU2xodV_kkSIk0F4&scope=write&iss=https%3A%2F%2Fopenam.example.com%3A8443%2Fopenam%2Foauth2&state=abc123&client_id=myClient
   Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept
   Content-Length: 0
   ```

3. Perform the steps in [Exchange an authorization code for an access token](#proc-auth-code-token-pkce) to exchange the authorization code for an access token.

## Exchange an authorization code for an access token

Perform the steps in the following procedure to exchange an authorization code for an access token:

1. Ensure the client has obtained an authorization code by performing the steps in either:

   * [Obtain an authorization code using a browser](#proc-auth-code-browser-pkce)

     or

   * [Obtain an authorization code without using a browser](#proc-auth-code-no-browser-pkce).

2. The client creates a POST request to the token endpoint in the authorization server specifying, at least, the following parameters:

   * **grant_type**=authorization_code

   * **code**=*your-authorization-code*

   * **client_id**=*your-client-id*

   * **redirect_uri**=*your-redirect-uri*

   * **code_verifier**=*your-code-verifier*

   For information about the parameters supported by the `/oauth2/access_token` endpoint, see [/oauth2/access_token](oauth2-access_token-endpoint.html). For information about private client authentication methods, see [OAuth 2.0 client authentication](oauth2-client-auth.html).

   For example:

   ```bash
   $ curl \
   --request POST \
   --data "grant_type=authorization_code" \
   --data "code=g5B3qZ8rWzKIU2xodV_kkSIk0F4" \
   --data "client_id=myClient" \
   --data "redirect_uri=https://www.example.com:443/callback" \
   --data "code_verifier=ZpJiIM_G0SE9WlxzS69Cq0mQh8uyFaeEbILlW8tHs62SmEE6n7Nke0XJGx_F4OduTI4" \
   "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"
   ```

   The `client_id` and the `redirection_uri` parameters specified in this call must match those used as part of the authorization code request, or the authorization server will not validate the code.

   The authorization server returns an access token in the `access_token` property. For example:

   ```json
   {
     "access_token": "sbQZuveFumUDV5R1vVBl6QAGNB8",
     "scope": "write",
     "token_type": "Bearer",
     "expires_in": 3599
   }
   ```

   |   |                                                                                                                                                                               |
   | - | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
   |   | The authorization server can also issue refresh tokens at the same time the access tokens are issued. For more information, see [Refresh tokens](oauth2-refresh-tokens.html). |
