---
title: Authorization code grant with PAR
description: /oauth2/par
component: pingam
version: 7.2
page_id: pingam:oauth2-guide:oauth2-authz-grant-par
canonical_url: https://docs.pingidentity.com/pingam/8.1/am-oauth2/oauth2-authz-grant-par.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-par.html
section_ids:
  proc-par-requesturi: Get a PAR request URI
  proc-par-browser: Get an authorization code using a browser
  proc-par-no-browser: Get an authorization code using REST
  proc-par-token: Exchange an authorization code for an access token
---

# Authorization code grant with PAR

* Endpoints

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

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

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

The pushed authorization request (PAR) endpoint provides enhanced security and cryptographic integrity when used with the authorization code grant flow, and optionally, in conjunction with PKCE.

PAR lets the authorization server authenticate the client before making an authorization request to ensure early detection of invalid or illegal requests.

To further protect authorization details when passing through third-party applications, clients can use JWT-based request objects as defined by [RFC9101](https://www.rfc-editor.org/info/rfc9101), to wrap confidential and potentially complex request parameters.

In response to this pre-authorization backchannel request, the client receives a request URI that is used to reference the payload data in subsequent interactions with the server.

|   |                                                                                                                                                                                                                                                                                                                                                                                                            |
| - | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | The use of PAR is optional by default. To force clients to use the PAR endpoint to initiate authorization requests, configure the OAuth 2.0 provider [advanced settings](../reference/global-services-configuration.html#global-oauth-oidc-advanced). To configure the setting for a particular client only, see the [client settings](oauth2-register-client.html#configure-oauth2-oidc-client-advanced). |

![OAuth 2.0 Authorization Code Grant Flow](https://kroki.io/plantuml/svg/eNqFVMFu2zAMvesriPRQDEjircegCGAU21BgxYq03SlAoMh0rNWWPElO2n79KMl27DRFeygiiXx8fHx0csmA_m50_WrkrnBw9fXq24z-XcEPbXa40uIZ0oc5pGUJKx9hYYUWzR4zFlKfLILOwRXSgtAZgsF_jTRogdO5qtAIyUuwOncHbhBKKVBRzkG6YlwjwGkTX7QKsJLq8TyXpeQObaTRULYtOP3aIuCLKBsr91i-gm22f1G4gOM0HUXRl9uiOyAq4tlTQOAqO6EQch817FChoZLUhKV-UAmETPKd4RXkRlexX-KFU6iNFmhtSJUu0r8vuXJPd7-mUDhXL5Kk9hdNVc6tbozA3FedK3RJBz8vXFWyy4Qx3jitmmqLBibX2-XFxZcJYzU3TgpZEwpMaAIBBX4fiOZa-SGYWUqk3QS4jdfjlJtSdq_xZ6C71S8wSe8gbVyhjXzjTmoFD368ZhIiRiCjsHUf6EH901s8v8-jLhK6uE62y7VCldVatlzu09X39nw-jbcl8Uyyr_lJtvCT2Tj9jOoMwKO_HyHQsxflA7kH_XZ3bcuMJZcDCWbLMIIF3OYgDGakNy0BWZkWYM9LmU1pTTLaEuHmc3JdiJ4t42QWQHfBRXw0lrBd3rJ-w9C6TWMk-XytqNMOzd_5Rr2RItpsOdB4AT_RedE7DHha3bJBQM_hj2fpF0CE87DudK0MusYoCIV7Lr5uiKNrfKn9N2Ajg-ys59LKsho03_Y-dFBQgFYkCOC1E0GBGHo9W45C02OM__i0o9I-NLARWuXSVMenaAoaWc9qaCRPLkpzRv0wlVbws31HtTYyi20PgXtpV1G89_BHQiNjDhgF5hDsvFYfWISxUfbRVV3dwU4cK479fCzZqxarDQgwNs45GUsHEGJJs300lGfptZKK5lvFsbLR5pwyoRUalgX67sYV8ja0tSawwG2EeEqt0-BDMGgtTR9zR8bErO-c_QfvzoGb?id=figure-oauth2-authz-par)Figure 1. OAuth 2.0 Authorization Code Grant Flow

> **Collapse: Authorization code grant flow with PAR explained**
>
> 1. The client pushes a request to the PAR endpoint, providing both client and request details.
>
> 2. AM validates both client and request, and if successful, returns a request URI as a reference to the request payload and an expiry period for the request URI.
>
> 3. The client receives a request to access a protected resource. To access the resources, the client requires authorization from the resource owner.
>
> 4. The client redirects the resource owner's user-agent to the authorization server.
>
> 5. The authorization server authenticates the resource owner, confirms resource access, and gathers consent if not previously saved.
>
> 6. The client requests an authorization code, typically through a web browser, by passing in the request_uri and client_id.
>
> 7. The client_id is validated against the request, and if successful, the authorization code is returned to the client.
>
> 8. The client authenticates to the authorization server using the received code in exchange for an access token.
>
>    Note that this example assumes a confidential client. Public clients are not required to authenticate.
>
> 9. If the authorization code is valid, the authorization server returns an access token (and a refresh token, if configured) to the client.
>
> 10. The client requests access to the protected resources from the resource server.
>
> 11. The resource server contacts the authorization server to validate the access token.
>
> 12. The authorization server validates the token and responds to the resource server.
>
> 13. 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 a PAR request URI and an authorization code to exchange for an access token:

1. [Get a PAR request URI](#proc-par-requesturi)

2. [Get an authorization code using REST](#proc-par-no-browser) or [Get an authorization code using a browser](#proc-par-browser)

3. [Exchange an authorization code for an access token](#proc-par-token)

## Get a PAR request URI

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 `PAR Request URI Lifetime` attribute is set to a value sufficient to cover the duration of the PAR request.

    For more information, see [Authorization server configuration](oauth2-configure-authz.html).

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

  * **Client secret**: `forgerock`

  * **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 a request uri:

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

   For example:

   ```bash
   $ 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 request to the authorization server's PAR endpoint. Specify parameters directly in the request body, or for large or sensitive data, AM supports the JWT-Secured Authorization Request (JAR) standard for PAR, which lets you wrap parameters in a signed and encrypted JWT.

   Example parameters with a JWT:

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

   * **client_secret**=*your-client-secret*

   * **request**=*encoded signed JWT value*

   Example parameters without a JWT:

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

   * **client_secret**=*your-client-secret*

   * **redirect_uri**=*your-redirect-id*

   * **scope**=write

   * **response_type**=code",

   * **code_challenge**=QR1D-7w1-rOQvlFe1CeqZigqaIpmZXatDMVvZ50o

   * **code_challenge_method**=S256

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

   Example PAR request with a JWT:

   ```bash
   $ curl \
   --request POST \
   --data "client_id=myClient" \
   --data "client_secret=forgerock" \
   --data "request=eyJhbGciOiJIUzI1NiJ…​mnRTwgPGTqkp5UBTVWaA_CifxWx1ikcZofOas" \
   "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/par"
   ```

   Example PAR request without a JWT:

   ```bash
   $ curl \
   --request POST \
   --data "client_id=myClient" \
   --data "client_secret=forgerock" \
   --data "response_type=code" \
   --data "scope=write" \
   --data "code_challenge=QR1D-7w1-rOQvlFe1CeqZigqaIpmZXatDMVvZ50o" \
   --data "code_challenge_method=S256" \
   --data "redirect_uri=https://www.example.com:443" \
   "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/par"
   ```

   On success, AM returns the following JSON:

   ```bash
   ${
     "request_uri": "C2c3yhu2IApAELttmZtfPNPQaIJxvTCHk",
     "expires_in": 90
   }
   ```

   1. `request_uri`: A reference to the PAR request payload.

   2. `expires_in`: The validity period of the request URI in seconds.

## Get an authorization code using a browser

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

1. Ensure the client has retrieved a request URI by following the steps described in [Get a PAR request URI](#proc-par-requesturi).

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

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

   * **response_type**=code

   * **redirect_uri**=*your-redirect-id*

   * **request_uri**=*the-PAR-request-uri*

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

   For example:

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

   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.

3. 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.

4. On a successful login, the authorization server presents the AM consent screen. Click Allow to consent.

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

5. 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=g5B3qZ8rWzKIU2xodV_kkSIk0F4&scope=write&iss=https%3A%2F%2Fopenam.example.com%3A8443%2Fopenam%2Foauth2&state=abc123&client_id=myClient
   ```

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

## Get an authorization code using REST

Perform the steps in this procedure to obtain an authorization code without a browser.

1. Ensure the client has retrieved a request URI by following the steps described in [Get a PAR request URI](#proc-par-requesturi).

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

   For example:

   ```bash
   $ 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"
   }
   ```

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

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

   * **request_uri**=*the-PAR-request-uri*

   * **response_type**=code

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

   * **decision**=allow

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

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

   For example:

   ```bash
   $ curl --dump-header - \
   --request POST \
   --Cookie "iPlanetDirectoryPro=AQIC5wM…​TU3OQ*" \
   --data "request_uri=C2c3yhu2IApAELttmZtfPNPQaIJxvTCHk" \
   --data "client_id=myClient" \
   --data "scope=write" \
   --data "response_type=code" \
   --data "csrf=AQIC5wM…​TU3OQ*" \
   --data "redirect_uri=https://www.example.com:443/callback" \
   --data "state=abc123" \
   --data "decision=allow" \
   "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: https://www.example.com:443/callback?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
   ```

4. Perform the steps in [Exchange an authorization code for an access token](#proc-par-token) 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 [Get an authorization code using a browser](#proc-par-browser) or [Get an authorization code using REST](#proc-par-no-browser).

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*

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

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

   Confidential clients can authenticate to the OAuth 2.0 endpoints in several ways. This example uses the following form parameters:

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

   * **client_secret**=*your-client-secret*

   For more information, 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 "client_secret=forgerock" \
   --data "redirect_uri=https://www.example.com:443/callback" \
   "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"
   ```

   The `client_id` and the `redirect_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). |
