---
title: Backchannel request grant
description: /oauth2/bc-authorize
component: pingoneaic
page_id: pingoneaic:am-oidc1:openid-connect-backchannel-request-flow
canonical_url: https://docs.pingidentity.com/pingoneaic/am-oidc1/openid-connect-backchannel-request-flow.html
keywords: ["OpenID Connect (OIDC)", "Standards"]
page_aliases: ["oidc1-guide:openid-connect-backchannel-request-flow.adoc"]
section_ids:
  the_backchannel_flow: The backchannel flow
  proc-prepare-for-ciba: Prepare for CIBA
  configure_the_service: Configure the service
  generate-jwks: Generate JWKs
  register_an_rp: Register an RP
  proc-auth-id-ciba: Get an auth request ID
  proc-auth-req-id-token-ciba: Exchange an auth request ID for tokens
  additional_oidc_claims: Additional OIDC claims
---

# Backchannel request grant

* Endpoints

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

  * [/oauth2/access\_token](../am-oauth2/oauth2-access_token-endpoint.html)

  * [/oauth2/userinfo](rest-api-oidc-userinfo-endpoint.html)

Use the backchannel request grant for [client-initiated backchannel authentication](https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0.html) (CIBA).

CIBA lets a relying party (RP), the *consumption device*, get an end user's consent without redirection through the end user's browser. Instead, the end user authenticates and grants consent through an *authentication device* such as an authenticator application or a mobile banking application on the user's mobile phone.

Advanced Identity Cloud applies the guidelines suggested by the OpenID [Financial-grade API (FAPI) Working Group](https://openid.net/wg/fapi/) to implement CIBA.

## The backchannel flow

![Advanced Identity Cloud supports the backchannel grant flow.](_images/oidc-ciba.svg)

1. The RP has a user identifier and requires the end user's consent. It prepares a signed Json Web Token (JWT).

2. The RP sends an HTTP POST request with the signed JWT to Advanced Identity Cloud, the OpenID provider (OP).

3. The OP validates the signature using the RP's public key and verifies the JWT. If the JWT is valid, the OP returns an `auth_req_id` and a polling interval.

4. The RP polls the OP with the `auth_req_id`, waiting for the end user's authorization. If the RP does not respect the polling interval, the OP returns an error.

5. The OP sends a push notification with the `binding_message` to request the end user's authorization.

6. The end user authorizes the request with the authorization gesture on their authentication device; for example, the user clicks a button in their authenticator application or provides their fingerprint.

7. The OP returns an access token and an ID token to the RP.

   The RP can use the ID token subject ID claim as the end user's identity.

8. If the RP requires additional claims, it sends a request to the [/oauth2/userinfo](rest-api-oidc-userinfo-endpoint.html) endpoint with the access token for authorization.

9. If the access token is valid, the `/oauth2/userinfo` endpoint returns any additional claims.

   The RP can use the subject ID and the additional claims to identify the end user.

## Prepare for CIBA

### Configure the service

1. In the Advanced Identity Cloud admin console, go to Journeys and create a journey such as the following:

   ![The journey requires specific authentication nodes for CIBA.](_images/ciba-push-journey.png)

   The journey uses these nodes:

   * [Platform Username node](https://docs.pingidentity.com/auth-node-ref/latest/platform-username.html)

   * [Push Sender node](https://docs.pingidentity.com/auth-node-ref/latest/push-sender.html)

   * [Push Result Verifier node](https://docs.pingidentity.com/auth-node-ref/latest/push-result-verifier.html)

   * [Polling Wait node](https://docs.pingidentity.com/auth-node-ref/latest/polling-wait.html)

   For details, refer to [Push authentication journeys](../am-authentication/push-authentication-journeys.html).

2. Save the journey with a name such as `CIBA Push Journey`.

3. Under Native Consoles > Access Management, go to Realms > *Realm Name* > Services > OAuth2 Provider > Advanced and make sure the Grant Types field includes `Back Channel Request`.

   Save any changes you make.

4. Associate the journey with incoming `acr_values`:

   1. Switch to the Advanced OpenID Connect tab of the OAuth 2.0 provider configuration.

   2. In the OpenID Connect acr\_values to Auth Chain Mapping box:

      1. Set the Key to the value that will be passed in through the `acr_values` claim of the incoming CIBA request. For example, `push`.

      2. Click Add. The Value field changes from a text input to a list of journeys available in the tenant.

      3. In the Value field, select the name of your journey. For example, `CIBA Push Journey`.

   3. Save your changes.

   For more information, refer to [The `acr` claim](oidc-authentication-requirements.html#acr-claim).

### Generate JWKs

You'll need a JWK public and private key pair to sign JWTs for CIBA requests. You'll also need the JWK public key so that Advanced Identity Cloud can verify the JWT signatures.

1. Generate a JWK public and private key pair:

   * Use [jose](https://command-not-found.com/jose) to run a command similar to the following:

     ```console
     $ jose jwk gen \
     --input '{"kty":"EC", "use": "sig", "crv":"P-256", "kid": "myCIBAKey", "alg":"ES256"}' \
     --output public-private-key-pair.jwk
     ```

   * A file named `public-private-key-pair.jwk` now contains a newly generated public and private key pair.

     ```json
     {
       "kty": "EC",
       "use": "sig",
       "crv": "P-256",
       "d": "m0CkLGYvqZM124-c4he9etz7qIt45q6oZ8ulyKw2t9Y",
       "kid": "myCIBAKey",
       "x": "m0CkpWpZyGu-FLRLjCGBVGC7Fwm5vGt8Lm3HhYU4ylg",
       "y": "U8NMtO-C2c3yhu2I_ApAELttmaittfPNPQaIJxvTCHk",
       "alg": "ES256",
     }
     ```

     Use this key pair to sign JWTs for CIBA requests.

2. Extract the JWK public key:

   * Run the following command:

     ```console
     $ jose jwk pub \
     --input public-private-key-pair.jwk \
     --output public-key.jwk
     ```

   * A file named `public-key.jwk` now contains only the public key:

     ```json
     {
       "kty": "EC",
       "use": "sig",
       "crv": "P-256",
       "kid": "myCIBAKey",
       "x": "m0CkpWpZyGu-FLRLjCGBVGC7Fwm5vGt8Lm3HhYU4ylg",
       "y": "U8NMtO-C2c3yhu2I_ApAELttmaittfPNPQaIJxvTCHk",
       "alg": "ES256",
     }
     ```

     Use this public key to configure the OIDC application in Advanced Identity Cloud.

### Register an RP

1. In the Advanced Identity Cloud admin console, [create an application owner profile](../identities/manage-identities.html#create_a_user_profile) and record the username and password.

2. Register the RP as a client application.

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

   2. Select the sign-on method as OIDC - OpenId Connect then click Next.

   3. Select the application type as Web then click Next.

   4. Enter a human-readable Name for your application, such as `My CIBA Application`.

   5. In the Owners list, select the application owner identity you created in step 1. Click Next.

   6. Enter a Client ID, such as `myCIBAClient`, and a Client Secret, and save them for later.

   7. Switch to the Sign On tab and under General Settings set the Scopes `openid` and `profile`.

   8. Save your changes.

3. Configure access to the RP's public keys so Advanced Identity Cloud can verify JWT signatures. Advanced Identity Cloud ignores keys specified in JWT headers, such as `jku` and `jwe` and uses the keys specified in the RP profile to verify the JWT signature.

   1. Under Show advanced settings > Signing and Encryption, choose the Public key selector.

   2. Depending on the Public key selector value you chose, set one of the other fields appropriately.

      For example:

      * Set Public key selector `JWKs_URI` and Json Web Key URI to the URL where the RP publishes its public keys.

        This method simplifies key rotation as Advanced Identity Cloud rereads the keys periodically.

      * Set Public key selector to `JWKs` and manually input Json Web Key with a [JWK](https://www.rfc-editor.org/info/rfc7517) set of one or more public keys. To create a JWK set, enclose one or more JWKs in a `keys` array, such as in the following examples, which use the public key created in step 2 of [Generate JWKs](#generate-jwks).

        | JWK example                                                                                                                                                                                                          | JWK set example                                                                                                                                                                                                                                                             |
        | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
        | ```json
        {
          "kty": "EC",
          "use": "sig",
          "crv": "P-256",
          "kid": "myCIBAKey",
          "x": "m0CkpWpZyGu-FLRLjCGBVGC7Fwm5vGt8Lm3HhYU4ylg",
          "y": "U8NMtO-C2c3yhu2I_ApAELttmaittfPNPQaIJxvTCHk",
          "alg": "ES256",
        }
        ``` | ```json
        {
          "keys": [
            {
              "kty": "EC",
              "use": "sig",
              "crv": "P-256",
              "kid": "myCIBAKey",
              "x": "m0CkpWpZyGu-FLRLjCGBVGC7Fwm5vGt8Lm3HhYU4ylg",
              "y": "U8NMtO-C2c3yhu2I_ApAELttmaittfPNPQaIJxvTCHk",
              "alg": "ES256"
            }
          ]
        }
        ``` |

   3. Save your changes.

## Get an auth request ID

Follow these steps as RP to get a CIBA authentication request ID:

1. Prepare a payload of required claims:

   | Claim             | Description                                                                                                                                                                                                                                    | Example                                                                                                                                                                              |
   | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
   | `acr_values`      | A string identifying the mechanism for the end user to provide authorization.                                                                                                                                                                  | `"acr_values": "push"`                                                                                                                                                               |
   | `aud`             | A string or array of strings indicating the intended audience of the JWT. Must include the authorization server OAuth 2.0 endpoint including port number 443.                                                                                  | `"aud": "https://<tenant-env-fqdn>:443/am/oauth2/realms/root/realms/alpha"`                                                                                                          |
   | `binding_message` | A short (100 character max.) string message to display to the user when obtaining authorization.For push notification, messages must:- Begin with a letter, number, or punctuation mark.

   - **Not** include line breaks or control characters. | `"binding_message": "Allow ExampleBank to transfer £50 from 'Main' to 'Savings'? (EB-0246326)"`                                                                                      |
   | `exp`             | The expiration time in seconds since January 1, 1970 UTC. An expiration time more than 30 minutes in the future causes a `JWT expiration time is unreasonable` error message.                                                                  | `"exp": 1761066489`&#xA;&#xA;To generate a value just under 30 minutes in the future, run the following command in a Unix or Linux shell:&#xA;&#xA;$ echo $(($(date -u +%s) + 1799)) |
   | `iss`             | The unique identifier of the JWT issuer; must match the client ID in the application profile.                                                                                                                                                  | `"iss": "myCIBAClient"`                                                                                                                                                              |
   | `login_hint`      | A string identifying the principal and subject of the JWT (the end user).                                                                                                                                                                      | `"login_hint": "a0325ea4-9d9b-4056-931b-ab64704cc3da"`                                                                                                                               |
   | `scope`           | A string holding a space-separated list of the requested scopes; must include `openid`.                                                                                                                                                        | `"scope": "openid profile"`                                                                                                                                                          |

   An example payload of claims looks like the following:

   ```json
   {
     "aud": "https://openam-mycompany.forgeblocks.com:443/am/oauth2/realms/root/realms/alpha",
     "binding_message": "Allow ExampleBank to transfer £50 from 'Main' to 'Savings'? (EB-0246326)",
     "acr_values": "push",
     "exp": 1761066489,
     "iss": "myCIBAClient",
     "login_hint": "a0325ea4-9d9b-4056-931b-ab64704cc3da",
     "scope": "openid profile"
   }
   ```

2. Create a signed JWT:

   * Use [jose](https://command-not-found.com/jose) to run a command similar to the following:

     ```console
     $ jose jws sig \
     -I payload.json \(1)
     -k public-private-key-pair.jwk \(2)
     -s '{"alg":"ES256"}' -c
     ```

     |       |                                                                                                                                                   |
     | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
     | **1** | `payload.json` should contain the claims prepared in the previous step.                                                                           |
     | **2** | `public-private-key-pair.jwk` should contain a JWK public and private key pair like the one created in step 1 of [Generate JWKs](#generate-jwks). |

   * An example signed JWT looks like the following:

     ```text
     eyJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL29wZW5hbS1teWNvbXBhbnkuZm9yZ2VibG9ja3
     MuY29tOjQ0My9hbS9vYXV0aDIvcmVhbG1zL3Jvb3QvcmVhbG1zL2FscGhhIiwiYmluZGluZ19tZXNzY
     WdlIjoiQWxsb3cgRXhhbXBsZUJhbmsgdG8gdHJhbnNmZXIgwqM1MCBmcm9tICdNYWluJyB0byAnU2F2
     aW5ncyc_IChFQi0wMjQ2MzI2KSIsImFjcl92YWx1ZXMiOiJwdXNoIiwiZXhwIjoxNzU5OTQzODM5LCJ
     pc3MiOiJteUNJQkFDbGllbnQiLCJsb2dpbl9oaW50IjoiYTAzMjVlYTQtOWQ5Yi00MDU2LTkzMWItYW
     I2NDcwNGNjM2RhIiwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSJ9.m0CkAdmfjmm2PehE7cUG6NBCE3sN
     puo4EvsruZgARdsDtdubLg9dWBNUhpETtwW-_ZXLPQKs0ZnQHEfMc_9pqA
     ```

3. Send an HTTP POST to the [/oauth2/bc-authorize](../am-oauth2/oauth2-bc-authorize-endpoint.html) endpoint with the signed JWT in a data parameter named `request`:

   ```bash
   $ curl \
   --request POST \
   --user '<rp-client-id>:<rp-client-secret>' \(1)(2)
   --data 'request=<signed-jwt>' \(3)
   'https://<tenant-env-fqdn>/am/oauth2/realms/root/realms/alpha/bc-authorize'(4)
   ```

   |       |                                                                                         |
   | ----- | --------------------------------------------------------------------------------------- |
   | **1** | Replace \<rp-client-id> with the client ID of your RP. For example, `myCIBAClient`.     |
   | **2** | Replace \<rp-client-secret> with the client secret of your RP.                          |
   | **3** | Replace \<signed-jwt> with the signed JWT you created in the previous step.             |
   | **4** | Replace \<tenant-env-fqdn> with the host name of your Advanced Identity Cloud instance. |

   Advanced Identity Cloud returns a JSON object with the `auth_req_id` value:

   ```json
   {
     "auth_req_id": "<auth-req-id>",
     "expires_in": 600,
     "interval": 2
   }
   ```

   Advanced Identity Cloud sends a push notification with the `binding_message` to the end user.

## Exchange an auth request ID for tokens

To get an access token and ID token as the RP, poll the [/oauth2/access\_token](../am-oauth2/oauth2-access_token-endpoint.html) endpoint with HTTP POST requests having the following parameters:

* `grant_type=urn:openid:params:grant-type:ciba`

* `auth_req_id=<auth-req-id>`

For example:

```bash
$ curl \
--request POST \
--user '<rp-client-id>:<rp-client-secret>' \
--data 'grant_type=urn:openid:params:grant-type:ciba' \
--data 'auth_req_id=<auth-req-id>' \
'https://<tenant-env-fqdn>/am/oauth2/realms/root/realms/alpha/access_token'
```

The response depends on the end user and the polling interval:

* After the end user has authorized the operation, Advanced Identity Cloud returns an ID token and an access token:

  ```json
  {
    "access_token": "<access-token>",
    "refresh_token": "<refresh-token>",
    "scope": "openid profile",
    "id_token": "<id-token>",
    "token_type": "Bearer",
    "expires_in": 3599
  }
  ```

* Before the end user authorizes the operation, Advanced Identity Cloud returns an HTTP 400 Bad Request status:

  ```
  {
    "error_description": "End user has not yet been authenticated",
    "error": "authorization_pending"
  }
  ```

* The auth ID response includes a polling `interval`. The RP must wait `interval` seconds before retrying the request (default: two seconds). If the RP does not wait long enough between retries, Advanced Identity Cloud returns an HTTP 400 Bad Request status:

  ```
  {
    "error_description": "The polling interval has not elapsed since the last request",
    "error": "slow_down"
  }
  ```

## Additional OIDC claims

An RP can request additional claims about the end user with the access token at the [/oauth2/userinfo](rest-api-oidc-userinfo-endpoint.html) endpoint:

```bash
$ curl \
--request GET \
--header "Authorization Bearer <access-token>" \
"https://<tenant-env-fqdn>/am/oauth2/realms/root/realms/alpha/userinfo"
{
  "name": "<end-user-display-name>",
  "family_name": "<end-user-family-name>",
  "given_name": "<end-user-given-name>",
  "sub": "<end-user-id>",
  "subname": "<end-user-id>"
}
```
