PingOne Advanced Identity Cloud

Hybrid grant

OpenID Connect (OIDC) authentication using the hybrid flow lets a relying party (RP) choose when to request access and ID tokens.

The hybrid grant flow is a two-step process:

  1. The RP first requests a code and tokens by setting the response type:

    Response type OpenID provider (OP) returns

    code id_token

    An authorization code and an ID token

    code token

    An authorization code and an access token

    code token id_token

    An authorization code, and access token, and an ID token

    PingOne Advanced Identity Cloud returns the code and the requested tokens in the fragment of the redirection URL.

  2. After the first request but before the authorization code expires (default: 120 seconds), the RP makes a second request to exchange the authorization code for additional tokens.

Follow these security recommendations when implementing the hybrid flow:

  • Avoid requesting access tokens with the first request.

  • Protect against cross-site scripting (XSS) attacks, which could leak tokens in the redirection URL fragment to other systems.

  • Implement Cross-Origin Resource Sharing (CORS) to make OIDC requests across domains.

  • For public client RPs, use PKCE to mitigate against interception attacks.

Hybrid flow
Figure 1. Hybrid flow
  1. The end user wants to access services the RP provides. The RP requires an account to provide access to the services.

    The end user makes a request to the RP to access their information stored at the OP.

  2. To access the end user’s information at the OP, the RP needs authorization from the end user. The RP redirects the end user’s browser...

  3. ...to the OP.

  4. The OP authenticates the end user, confirms resource access, and gathers consent if necessary.

  5. On success, the OP redirects the end user to the RP.

  6. The OP appends an authorization code and tokens to the URL fragment.

  7. The RP stores the authorization code for future use and validates the ID token to get the subject ID.

  8. With the ID token, the RP provides services to the end user.

  9. Before the authorization code expires, the RP exchanges it for an access token, which the RP can use to get more information about the end user.

  10. PingOne Advanced Identity Cloud returns an access token.

  11. The RP sends a request to the /oauth2/userinfo endpoint with the access token for authorization.

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

Demonstrate the flow

Prepare the demonstration

Complete these steps to prepare the hybrid 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 UI, 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

      forgerock

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

      Sign-in URLs

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

      Scopes

      openid
      profile

      Grant Types

      Authorization Code
      Implicit

    5. Click Show advanced settings and under Access, add these settings:

      Response Types

      code id_token
      code token
      code token id_token

    6. Under Token Lifetimes, update this setting as appropriate for your use case:

      Authorization code lifetime (seconds)

      Default: 120

    7. Save your changes.

  3. Create an end user profile and record the username and password.

Get a code and an ID token using a browser

  1. As RP, browse to the /oauth2/authorize endpoint with at least the following parameters:

    • client_id: myClient

    • response_type: code id_token

    • scope: openid profile

    • 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%20id_token \
    &scope=openid%20profile \
    &state=abc123 \
    &nonce=123abc \
    &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.

    The state and nonce parameters are optional and included to protect against CSRF attacks.

  2. Sign in as the end user and grant consent if necessary.

    PingOne Advanced Identity Cloud redirects to the redirect_uri.

  3. Inspect the URL in the browser:

    https://www.example.com:443/callback#code=<authorization-code>&id_token=<id-token>...

Get a code and an ID token using REST

  1. Authenticate as the end user:

    $ curl \
    -i \
    --request POST \
    --header "Content-Type: application/json" \
    --header "X-OpenAM-Username: <end-user-id>" \
    --header "X-OpenAM-Password: <end-user-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"}
  2. As RP, make an HTTP POST request to the /oauth2/authorize endpoint with the following parameters:

    • scope: openid profile

    • response_type: code id_token

    • client_id: myClient

    • csrf: <tokenId>

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

    • decision: allow

    For example:

    $ curl \
    --dump-header - \
    --request POST \
    --cookie "<session-cookie-name>=<tokenId>" \
    --data "scope=openid profile" \
    --data "response_type=code id_token" \
    --data "client_id=myClient" \
    --data "csrf=<tokenId>" \
    --data "redirect_uri=https://www.example.com:443/callback" \
    --data "state=abc123" \
    --data "nonce=123abc" \
    --data "decision=allow" \
    "https://<tenant-env-fqdn>/am/oauth2/realms/root/realms/alpha/authorize"

    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.

    The state and nonce parameters are optional and included to protect against CSRF attacks.

    PingOne Advanced Identity Cloud returns an HTTP 302 response with the code and ID token in the redirection URL fragment:

    HTTP/1.1 302 Found
    ...
    Location: https://www.example.com:443/callback#code=<authorization-code>&id_token=<id-token>...
    ...

Exchange the code for an access token

Choose one of the following options:

Additional OIDC claims

An RP can request additional claims about the end user with the access token at the /oauth2/userinfo endpoint:

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