PingOne Advanced Identity Cloud

Authorization code grant with PAR

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 enable 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, to wrap confidential and potentially complex request parameters.

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

  • PAR is optional by default. To enforce the use of the PAR endpoint to initiate authorization requests, enable Require Pushed Authorization Requests under Native Consoles > Access Management:

    • To force all clients in a realm to use PAR, enable the setting on the OAuth 2.0 provider’s Advanced tab.

    • To force an individual client to use PAR, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID and enable the setting on the Advanced tab.

  • The PAR and JAR specifications indicate the following:

    • The authorization server should ignore authorize parameters outside the request_uri.

    • When sending a JWT-Secured Authorization Request (JAR), the request_uri must be an https URI.

    To enforce this behavior in Advanced Identity Cloud, create an ESV variable named esv.oauth2.request.object.restrictions.enforced and set its value to true.

The authorization code grant with PAR flow

OAuth 2.0 authorization code grant with PAR flow
Figure 1. OAuth 2.0 authorization code grant with PAR flow
  1. The client pushes a request to the PAR endpoint, providing both client and request details.

  2. Advanced Identity Cloud 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 resource, the client requires authorization from the resource owner.

  4. The client redirects the resource owner’s user-agent to Advanced Identity Cloud, the authorization server.

  5. Advanced Identity Cloud 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. Advanced Identity Cloud validates the client_id against the request and, if successful, returns the authorization code to the client.

  8. The client authenticates to Advanced Identity Cloud using the received code in exchange for an access token.

    This example assumes a confidential client. Public clients aren’t required to authenticate.
  9. If the authorization code is valid, Advanced Identity Cloud 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 Advanced Identity Cloud to validate the access token.

  12. Advanced Identity Cloud 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 resource.

Demonstrate the authorization code grant with PAR flow

Follow these steps to get a PAR request URI and an authorization code to exchange for an access token:

Prepare the demonstration

Complete these steps to prepare the authorization code grant with PAR flow demonstration:

  1. Create an application owner profile and record the username and password.

  2. Register a client application.

    1. In the Advanced Identity Cloud admin console, go to Applications and select + Custom Application.

    2. Select the sign-in method as OIDC - OpenId Connect and application type as Web.

    3. Create the application, providing the following details:

      Name

      myClient

      Owners

      application-owner

      Client ID

      myClient

      Client Secret

      mySecret

    4. Switch to the Sign On tab and under General Settings, set these fields to the following values:

      Sign-in URLs

      https://www.example.com:443/callback

      Scopes

      write

    5. Save your changes.

  3. Configure the duration of the request URI:

    1. Under Native Consoles > Access Management, go to Services > OAuth2 Provider and switch to the Advanced tab.

    2. Set PAR Request URI Lifetime to a value sufficient to cover the duration of the PAR request.

      For more information, refer to PAR Request URI Lifetime.

    3. Save your changes.

  4. Create a resource owner profile and record the username and password.

Get a PAR request URI

As the client, call Advanced Identity Cloud’s /oauth2/par endpoint. Specify parameters directly in the request body. Alternatively, for large or sensitive data, Advanced Identity Cloud 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: myClient

  • client_secret: mySecret

  • request: signed-encrypted-jwt-value

Example parameters without a JWT:

  • client_id: myClient

  • client_secret: mySecret

  • redirect_uri: https://www.example.com:443/callback

  • scope: write

  • response_type: code

  • code_challenge: code_challenge

  • code_challenge_method: S256

For information about required parameters and an example JWT request object, refer to /oauth2/par.

Example PAR request with a JWT:

$ curl --request POST \
--data "client_id=myClient" \
--data "client_secret=forgerock" \
--data "request=signed-encrypted-jwt-value" \
"https://<tenant-env-fqdn>/am/oauth2/realms/root/realms/alpha/par"

Example PAR request without a JWT:

$ curl --request POST \
--data "client_id=myClient" \
--data "client_secret=forgerock" \
--data "response_type=code" \
--data "scope=write" \
--data "code_challenge=code_challenge" \
--data "code_challenge_method=S256" \
--data "redirect_uri=https://www.example.com:443/callback" \
"https://<tenant-env-fqdn>/am/oauth2/realms/root/realms/alpha/par"

On success, the authorization server returns the following JSON:

{
  "request_uri": "zizBvZPwAmzfcDOMKTPv0QTaRA8", (1)
  "expires_in": 90 (2)
}
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

  1. Ensure the client has retrieved a request URI by following the steps described in Get a PAR request URI.

  2. The client redirects the resource owner’s user-agent to Advanced Identity Cloud’s /oauth2/authorize endpoint including the following parameters:

    • client_id: myClient

    • response_type: code

    • request_uri: par_request_uri

    • redirect_uri: https://www.example.com:443/callback

    For example:

    https://<tenant-env-fqdn>/am/oauth2/realms/root/realms/alpha/authorize \
    ?client_id=myClient \
    &response_type=code \
    &request_uri=zizBvZPwAmzfcDOMKTPv0QTaRA8 \
    &scope=write \
    &redirect_uri=https://www.example.com:443/callback
    • The URL is split and spaces added for readability purposes.

    • The scope parameter is optional if default values are configured in the authorization server or the client.

  3. The resource owner authenticates to Advanced Identity Cloud. In this demonstration, they log in using the default journey configured for the realm.

    By default, client applications in Advanced Identity Cloud use implied consent. If Advanced Identity Cloud is configured to require explicit consent, the authorization server presents the resource owner with a consent screen. To continue the flow, the resource owner must select Allow to grant consent.

    Advanced Identity Cloud 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 Advanced Identity Cloud issued.

    For example:

    https://www.example.com/callback?code=authorization-code&iss...

  5. Follow the steps to get an access token.

Get an authorization code using REST

  1. Ensure the client has retrieved a request URI by following the steps in Get a PAR request URI.

  2. Authenticate as the resource owner.

    For example:

    $ curl \
    -i \
    --request POST \
    --header "Content-Type: application/json" \
    --header 'X-OpenAM-Username: resource-owner-username' \
    --header 'X-OpenAM-Password: resource-owner-password' \
    --header "Accept-API-Version: resource=2.0, protocol=1.0" \
    'https://<tenant-env-fqdn>/am/json/realms/root/realms/alpha/authenticate'
    {
      "tokenId": "tokenId",
      "successUrl": "/enduser/?realm=/alpha",
      "realm": "/alpha"
    }
  3. As the client, call the /oauth2/authorize endpoint to request the authorization code. Provide the resource owner’s SSO token in a cookie and the following parameters:

    • client_id: myClient

    • request_uri: par_request_uri

    • csrf: tokenId

    • decision: allow

    Find more information on the parameters supported by this endpoint in /oauth2/authorize.

    For example:

    $ curl --dump-header - \
    --request POST \
    --cookie "<session-cookie-name>=tokenId" \
    --data "client_id=myClient" \
    --data "request_uri=par_request_uri" \
    --data "csrf=tokenId" \
    --data "decision=allow" \
    "https://<tenant-env-fqdn>/am/oauth2/realms/root/realms/alpha/authorize"

    If Advanced Identity Cloud can authenticate the user and the client, it returns an HTTP 302 response with the authorization code appended to the redirection URL:

    HTTP/2 302
    ...
    location: https://www.example.com:443/callback?code=authorization-code&iss...
    ...
  4. Perform the steps in Exchange an authorization code for an access token to get an access token.

Exchange an authorization code for an access token

As the client, call the /oauth2/access_token endpoint to exchange the authorization code for an access token. Provide the following parameters:

  • myClient:mySecret

  • grant_type: authorization_code

  • code: authorization-code

  • redirect_uri: https://www.example.com:443/callback

  • code_verifier: code-verifier

For example:

$ curl \
--request POST \
--user 'myClient:forgerock' \
--data "grant_type=authorization_code" \
--data "code=authorization-code" \
--data "redirect_uri=https://www.example.com:443/callback" \
--data "code_verifier=code-verifier" \
"https://<tenant-env-fqdn>/am/oauth2/realms/root/realms/alpha/access_token"

The redirect_uri and client 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, for example:

{
  "access_token": "access-token",
  "refresh_token":"refresh-token",
  "scope": "write",
  "token_type": "Bearer",
  "expires_in": 3599
}

By default, the authorization server also issues a refresh token whenever it issues access tokens.