PingAM 7.5.1

JWT profile for authorization

RFC 7523 JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants defines the use of JWT bearer tokens for requesting access tokens and for client authentication. This page describes how to exchange a JWT bearer token for an access token. For client authentication, refer to JWT profile.

In this profile, the client or another issuer authenticates the resource owner, obtains authorization, and prepares a signed JWT bearer token to use the AM REST APIs. AM does not interact with the resource owner in this grant flow.

You configure AM to trust the issuer with a trusted JWT issuer profile to access the issuer’s public keys. AM supports only asymmetric (public-private key) signing algorithms; HMAC-based signing is not supported. AM validates the JWT signature and content using the trusted JWT issuer profile.

JWT for authorization flow

oauth2-jwt-bearer-authz
  1. The client directs the resource owner to the issuer for authentication and to obtain authorization.

  2. The issuer authenticates the resource owner and obtains consent.

  3. On success, the issuer supplies a signed JWT.

  4. The issuer redirects the resource owner to the client with the JWT.

  5. The client makes a request to exchange the JWT for an access token.

  6. AM validates the JWT according to RFC 7523, section 3 with the following additional checks:

    • Match the iss claim with the trusted JWT issuer JWT Issuer setting.

    • Validate the JWT signature with the trusted JWT issuer’s public key.

    AM returns an error if it can’t validate the JWT.

  7. As authorization server, AM issues an access token to the client.

  8. The client uses the token when requesting access to the protected resource.

  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 grants the client access to the protected resource.

Demonstrate JWT for authorization flow

Set up a trusted JWT issuer profile

  1. In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Trusted JWT Issuer.

  2. Click + Add Trusted JWT Issuer Agent, provide the following settings, and then click Create:

    Agent ID

    An identifier for the profile.

    JWT Issuer

    The URI to uniquely identify the issuer; this must match the iss claim in the JWT.

  3. Configure at least the issuer’s public keys by setting either of these fields:

    JWKs URI

    The URL to the issuer’s JSON Web Key (JWK) set; for example: https://www.example.com/issuer/jwk_uri. Use this setting to simplify the process of key rotation.

    If you configure this field, also check and update the JWKs URI content cache timeout in ms and JWKs URI content cache miss cache time as necessary.

    JWK Set

    The issuer’s JWK set; for example:

    {
      "keys": [{
        "kty": "RSA",
        "e": "AQAB",
        "kid": "example",
        "alg": "RS256",
        "n": "uzfshBc3malq8JYIyskEKV6e0X42oAboChGEMKCld92YRsVpiPWc4LpFw2lFhOGy6v5qxnkEsLJf-aMQNSMFkux0356PBGWWWJO1_IlC6EjMJMMvKaCjzZLpEVXEtKj0VjXZl07kQQ8F8SGc_tzp6Sgd-R3nR-tC1HpVAar_DFhISikwm1NyupEhI05sxhyiC_09f5xwY23wwpXx4qrGETsogP8k4FE9jgCiyhafhj9qMHI6skGoLyQgQkqFRn5Krfg6UdPvnEwF5sK3GATWk7sUKR62-ia_986Em0ObSP5230WS8hJO__o3MN-b6qN3o-mdO-a1_E1PRLRY03GHHQ"
      }]
    }
  4. Configure additional settings as necessary:

    Consented Scopes Claim

    A JWT claim specifying an array or space-separated allowlist of scopes.

    Resource Owner Identity Claim

    The JWT claim holding the AM identifier for the resource owner.

    When you configure an alternative identifier, the JWT must still include a sub claim.

    Allowed Subjects

    Optionally restrict the subjects to the resource owners specified here.

  5. Save your changes.

Set up an OAuth 2.0 client

  1. Create a confidential OAuth 2.0 client account to get an original token for the subject.

    In the AM admin UI, select Realm > Realm Name > Applications > OAuth 2.0 > Clients > + Add Client, and create a new confidential client with the following settings:

    Client ID

    myClient

    Client secret

    forgerock

    Redirection URIs

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

  2. Switch to the Advanced tab, add the following setting, and save your work:

    Grant Types

    Add JWT Bearer

  3. Save your changes.

Set up a resource owner profile

  1. In the AM admin UI, select Realms > Realm Name > Identities > + Add Identity and fill the required fields.

  2. Record the identifier of the profile to use as the sub claim in the JWT.

Issue a signed JWT

As the issuer, prepare and sign the JWT for the client.

The JWT is signed using the issuer’s asymmetric key pair and includes at least the following claims:

Claim Description

aud

A string or array of strings for the intended audience(s), the AM access token endpoint(s).

Example: "aud": "https://openam.example.com:8443/openam/am/oauth2/realms/root/realms/alpha/access_token"

Notice the port number in the URL.

exp

Expiration time in seconds since Jan 1, 1970, UTC.

Example: "exp": 1680855108

iss

The JWT issuer’s unique identifier.

Example: "iss": "https://www.example.com/issuer"

sub

The AM identifier for the resource owner.

Example: "sub": "a0325ea4-9d9b-4056-931b-ab64704cc3da"

Request an access token

As the client, exchange the JWT for an access token:

$ curl \
--request POST \
--user 'myClient:forgerock' \
--data 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer' \
--data 'assertion=<jwt-from-issuer>' \
--data 'redirect_uri=https://www.example.com:443/callback' \
--data 'scope=openid' \
'https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token'
{
  "access_token": "<access-token>",
  "refresh_token": "<refresh-token>",
  "scope": "openid",
  "id_token": "<id-token>",
  "token_type": "Bearer",
  "expires_in": 3599
}

As shown in the example, the request includes these parameters:

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer

Required for this grant.

assertion=<jwt-from-issuer>

The signed JWT.

scope=openid

Required if the scopes are not in the JWT and no default scopes are set for the client.

Configure a scripted JWT issuer

Use a script to configure a trusted JWT issuer so that AM can dynamically retrieve the details of an issuer during the JWT profile for authorization grant.

This lets a scripted JWT issuer represent an existing entity in an external system.

For example, if an administrative user creates a service account in IDM, a reference to that service account is provided in the JWT so that the identity can be retrieved and verified by the scripted JWT issuer. The issuer then sends the signed JWT to AM to obtain an access token using the JWT profile for authorization grant.

To configure a scripted JWT issuer, follow these steps:

The examples used in these steps assume an administrator has already created a managed object representing a service account in IDM.

  1. Create a trusted JWT issuer script.

    1. In the AM admin UI, go to Realms > Realm Name > Scripts and click New Script.

    2. Enter a unique name for your script and select OAuth2 Trusted JWT Issuer from the Script Type drop-down list. Click Create.

    3. Write a script that returns an org.forgerock.oauth2.core.TrustedJwtIssuerConfig object.

      The TrustedJwtIssuerConfig object should contain the details of the issuer, the JWK set, and where to locate the subject and scope in the original JWT.

      Note that scripted JWT issuer scripts can currently only access secrets with IDs that have a prefix of scripted.jwtissuer.

      Example script
      ( function() {
          var fr = JavaImporter(
              org.forgerock.oauth2.core.TrustedJwtIssuerConfig,
              java.util.HashSet
          );
          var iss = idRepository.getIdentity(issuer);
          if (iss == null) {
              logger.message('No issuer found for: ' + issuer);
              return null;
          }
          logger.message('Found for: ' + iss);
          var jwksAttrs = iss.getAttributeValues('fr-attr-jwks');
          if (!jwksAttrs || jwksAttrs.length === 0) {
              logger.message('No jwk attributes in issuer');
              return null;
          }
          var jwkSet = jwksAttrs[0];
          if (!jwkSet) {
              logger.message('No jwk set in issuer');
              return null;
          }
          var config = new fr.TrustedJwtIssuerConfig(
              issuer,
              'sub',
              'scope',
              new fr.HashSet([issuer]),
              jwkSet,
              null, null, null
          );
          return config;
      }());
    4. Click Save Changes.

  2. Configure AM to use the script.

    1. In the AM admin UI, go to Realms > Realm Name > Services > OAuth2 Provider > Secondary Configurations to configure the OAuth 2.0 provider for the realm.

    2. Click Add a Secondary Configuration.

    3. Provide a name, select the name of the script you created from the drop-down list, and click Create.

The scripted JWT issuer is ready for use.

To reference the external entity to be retrieved by the scripted JWT issuer, the provided JWT must contain iss and sub claims set to the entity identifier.

For example, this JWT references a service account with the identifier e0c47854-b0cf-4512-9aec-1ae6ada6d521:

{
    "iss": "e0c47854-b0cf-4512-9aec-1ae6ada6d521",
    "sub": "e0c47854-b0cf-4512-9aec-1ae6ada6d521",
    "aud": "https://:443/am/oauth2/access_token",
    "exp": 1555530663,
    "jti": "pwgb48EzRrnN4VaI55H+0g=="
}