Access Management 7.3.1

OAuth 2.0

This guide covers concepts, configuration, and usage procedures for working with OAuth 2.0 and ForgeRock Access Management.

ForgeRock® Identity Platform serves as the basis for our simple and comprehensive Identity and Access Management solution. We help our customers deepen their relationships with their customers, and improve the productivity and connectivity of their employees and partners. For more information about ForgeRock and about the platform, see https://www.forgerock.com.

AM as the authorization server

As an authorization server, AM authenticates resource owners and obtains their authorization to return access tokens to clients.

Before you configure OAuth 2.0 in your environment, familiarize yourself with the OAuth 2.0 authorization framework and the RFCs, Internet-Drafts, and standards that AM supports relating to OAuth 2.0.

OAuth 2.0 concepts

RFC 6749, the OAuth 2.0 authorization framework lets a third-party application obtain limited access to a resource (usually user data) on behalf of the resource owner or the application itself.

The main actors in the OAuth 2.0 authorization framework are the following:

OAuth 2.0 framework actors
Actor Description

Resource owner (RO)

The owner of the resource. For example, a user who stores their photos in a photo-sharing service.

The resource owner uses a user-agent, usually a web-browser, to communicate with the client.

Client

The third-party application that wants to access the resource. The client makes requests on behalf of the resource owner and with their authorization. For example, a printing service that needs to access the resource owner’s photos to print them.

AM can act as a client.

Authorization server (AS)

The authorization service that authenticates the resource owner and/or the client, issues access tokens to the client, and tracks their validity. Access tokens prove that the resource owner authorizes the client to act on their behalf over specific resources for a limited period of time.

AM can act as the authorization server.

Resource server (RS)

The service hosting the protected resources. For example, a photo-sharing service. The resource server must be able to validate the tokens issued by the authorization server.

A website protected by a web or a Java agent can act as the resource server.

The following sequence diagram demonstrates the basic OAuth 2.0 flow:

OAuth 2.0 protocol flow
Figure 1. OAuth 2.0 protocol flow

To use AM as an authorization server, register an OAuth 2.0 client in the AM admin UI. Clients can also register themselves dynamically. For details, refer to Client application registration.

Supported OAuth 2.0 features

As an authorization server, AM supports the following features:

OAuth 2.0 Features
Feature Details

Grant types

  • Authorization code

  • Implicit

  • Resource owner password credentials

  • Client credentials

  • Device flow

  • SAML v2.0 profile for authorization grant

  • JWT profile for OAuth 2.0 authorization grants

Client authentication standards

  • JWT profile for OAuth 2.0 client authentication

  • Mutual TLS

Token exchange standards.

OAuth 2.0 token exchange

Other OAuth 2.0 standards

Remote consent services

Delegates the consent-gathering part of an OAuth 2.0 flow to a separate service.

Customizable scope grants

You can customize how scopes are granted to the client, regardless of the grant flow used.

AM can grant scopes statically or dynamically:

  • Statically (default)

    Configure several OAuth 2.0 clients with different subsets of scopes. Resource owners are redirected to a specific client, depending on the scopes required. As long as the resource owner can authenticate and the client can deliver the same or a subset of the requested scopes, AM issues the token with the scopes requested. Two different users requesting scopes A and B from the same client will always receive scopes A and B.

  • Dynamically

    Configure an OAuth 2.0 client with a comprehensive list of scopes. Resource owners authenticate against that client. When AM receives a request for scopes, the authorization service grants or denies access scopes dynamically by evaluating authorization policies. Two different users requesting scopes A and B from the same client can receive different scopes, based on policy conditions.

Security considerations

OAuth 2.0 messages involve credentials and access tokens that allow the bearer to retrieve protected resources. You must protect the messages going across the network and prevent attackers from capturing requests or responses.

RFC 6749 includes a number of security considerations and requires Transport Layer Security (TLS) to protect sensitive messages. Make sure you read these security considerations and implement them in your deployment.

When you are deploying a combination of other clients and resource servers, pay special attention to the OAuth 2.0 threat model and security considerations before putting your service into production.

OAuth 2.0 sample mobile applications

To try the capabilities of AM as an authorization server, you can download the sample mobile application.

For access to the source code, refer to How do I access and build the sample code provided for AM/OpenAM (All versions)? in the ForgeRock Knowledge Base.

Token storage location

AM OAuth 2.0-related services are stateless unless otherwise indicated; they do not hold any token information local to the AM instances. Instead, they either cache the OAuth 2.0/OpenID Connect tokens in the Core Token Service (CTS) token store (server-side), or present them to the client (client-side). This architecture lets you scale your AM infrastructure horizontally, because any server in the deployment can satisfy any token request.

The OAuth 2.0 token storage location is a property of the OAuth 2.0 service, configured by realm.

By default, OAuth 2.0 tokens are configured for server-side storage. You can update the token storage location for the realm by setting the Use Client-Side Access & Refresh Tokens property in the AM admin UI:

  • On the OAuth 2.0 provider:

    Go to Realms > Realm Name > Services > OAuth2 Provider.

  • To override provider settings on the client:

    Go to Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > OAuth2 Provider Overrides.

    Note that Enable OAuth2 Provider Overrides must be enabled for the setting to apply.

For information about configuring client-side OAuth 2.0, refer to Configure AM for client-side OAuth 2.0 tokens.

Both server-side and client-side token configurations support all of AM’s OAuth 2.0 features.

Server-side OAuth 2.0 tokens

  • The CTS token store is the authoritative source for the tokens. AM returns a reference to the token to the client, which does not contain any of the token information. In this example, the reference is stored in the access_token property:

    {
      "access_token": "sbQZuveFumUDV5R1vVBl6QAGNB8",
      "scope": "write",
      "token_type": "Bearer",
      "expires_in": 3599
    }
  • Clients cannot access the tokens other than to introspect them, making tokens less vulnerable to tampering attacks.

  • AM does not cache server-side tokens in memory. Each time a client presents a token ID in a request, AM checks if the token exists in the CTS token store (in case it has been revoked) and, if available, retrieves its information.

    Reading from and writing to the CTS token store incurs overhead for the CTS DS instances.

  • If you need to add a layer of security for the stored tokens, consider one of the following options:

    • Configure AM to encrypt the tokens before storing them in the CTS token store.

    • Configure DS to encrypt the CTS token store data.

    For more information, refer to Manage CTS tokens.

  • Tokens can only be introspected using a call to the authorization server.

Client-side OAuth 2.0 tokens
  • AM returns the token to the client after successfully completing one of the grant flows.

    In this example, the token is stored in the access_token property:

    {
       "access_token":"eyJ0eXAiOiJKV1QiLOT05FIiwiYWxnQY1lIjoxNTM5MDEzMzYyLsbSI6Ii8iLCj…​.",
       "scope":"write",
       "token_type":"Bearer",
       "expires_in":3599
    }

    A decoded access token produces JSON structures similar to the following:

    {
         typ: "JWT",
         zip: "NONE",
         alg: "HS256"
    }
    {
         sub: "(usr!myClient)",
         subname" "myClient",
         cts: "OAUTH2_STATELESS_GRANT",
         auditTrackingId: "f20f4099-5248-4399-a7f0-2d54d4020099-108676",
         iss: "https://openam.example.com:8443/openam/oauth2",
         tokenName: "access_token",
         token_type: "Bearer",
         authGrantId: "1LUgI8zcDWqcfEnnLdZDnNqA2wc",
         aud: "myClient",
         nbf: 1539075967,
         grant_type: "client_credentials",
         scope: [
          "write"
         ],
         auth_time: 1539075967,
         realm: "/alpha",
         exp: 1539079567,
         iat: 1539075967,
         expires_in: 3600,
         jti: "FTQT6eZkDhm6PHEaSthORoTLB80"
    }
    [signature]
  • Client-side tokens are larger than the reference returned for server-side tokens, so consider their size if they must be sent in a header. You must ensure the size of the token does not exceed the maximum header size allowed by your end users' browsers.

  • The size of client-side tokens also increases when you customize AM to store additional attributes in the tokens.

  • Tokens are presented to the client after successfully completing an OAuth 2.0 grant flow; therefore, tokens are vulnerable to tampering attacks and you should configure AM to sign and encrypt them.

  • Clients can introspect tokens without calling the authorization server.

  • AM does not store the decrypt sequence of the token in memory, so decrypting and verifying tokens incurs overhead for the AM instances.

  • Token denylisting is a feature that maintains a list of revoked tokens and authorization codes stored in the CTS token store. This feature protects against replay attacks, and it is always enabled for client-side tokens.

    Each time a client presents a client-side token in a request, AM checks the CTS token store to see whether the token has been denylisted (revoked). If it has not been denylisted, AM decrypts the token to retrieve its information.

    Client-side refresh tokens have corresponding entries in a CTS allowlist, rather than a denylist. When presenting a client-side refresh token, AM checks that a matching entry is found in the CTS allowlist, and prevents reissue if the record does not exist.

    Adding a client-side OAuth 2.0 token to the denylist removes the associated refresh token from the allowlist.

AM as client and resource server

When AM functions as an OAuth 2.0 client, it provides a session after successfully authenticating the resource owner and obtaining authorization. The client can then access resources protected by agents.

To configure AM as an OAuth 2.0 client, use a Social Provider Handler node or a social authentication module as part of the authentication journey.

The following sequence diagram shows how the client gains access to protected resources in the scenario where AM functions as both authorization server and client:

OAuth 2.0 client and authorization server
Figure 2. OAuth 2.0 client and authorization server

Because the OAuth 2.0 client functionality is implemented as an AM authentication module or node, you do not need to deploy your own resource server implementation when using AM as an OAuth 2.0 client. Use web or Java agents or IG to protect resources.

For more information about configuring AM as an OAuth 2.0 client, refer to Social authentication.

To use your own client and resource server, make sure the resource server implements the logic for handling access tokens and refresh tokens.

The resource server can use the /oauth2/introspect endpoint to determine whether the access token is still valid, and to retrieve the scopes associated with the access token.

To design your own scopes implementation, refer to Customize OAuth 2.0.

AM as client and authorization server

This section describes the steps required to set up AM both as an OAuth 2.0 authorization server and as an OAuth 2.0 client, to protect resources on a resource server by using an AM web agent.

This example uses an authorization server, a client, and a resource server protected with a web agent.
Figure 3. Authorization server, client, and resource server

The example uses three servers:

  • http://authz.example.com:8080/openam as the OAuth 2.0 authorization server

  • http://client.example.com:8080/openam as the OAuth 2.0 client, which also handles policy

  • http://www.example.com:8080/ as the OAuth 2.0 resource server protected with an AM web agent, where the resources to protect are deployed in Apache Tomcat

The two AM servers communicate using OAuth 2.0. The web agent on the resource server communicates with AM as agents normally do, using AM specific requests. The resource server in this example does not need to support OAuth 2.0.

The high-level configuration steps are as follows:

  1. On the AM server that you will configure to act as an OAuth 2.0 client, configure an agent profile, and the policy used to protect the resources.

    On the web server or application container that will act as an OAuth 2.0 resource server, install and configure an AM web agent.

    Make sure that you can access the resources when you log in through an authentication module that you know is working, such as the default DataStore authentication module.

    In this example, you would try to access http://www.example.com:8080/examples/. The web agent should redirect you to the AM login page. After you log in successfully as a user with access rights to the resource, AM should redirect you back to http://www.example.com:8080/examples/, and the web agent should allow access.

    Fix any problems you have in accessing the resources before you try to set up access through an OAuth 2.0 or OpenID Connect authentication module.

  2. Configure one AM server as an OAuth 2.0 authorization service, which is described in Authorization server configuration.

  3. Configure the other AM server, the one with the agent profile and policy, as an OAuth 2.0 client, by setting up an OAuth 2.0 or OpenID Connect authentication module according to social authentication modules.

  4. On the authorization server, register the OAuth 2.0 or OpenID Connect authentication module as an OAuth 2.0 client, which is described in Client application registration.

  5. Log out and access the protected resources to see the process in action.

Example: Protecting a website with OAuth 2.0

This example pulls everything together (except security considerations), using AM servers both as the OAuth 2.0 authorization server, and also as the OAuth 2.0 client, with an AM web or Java agent on the resource server requesting policy decisions from AM as OAuth 2.0 client. In this way, any server protected by an agent that is connected to an AM OAuth 2.0 client can act as an OAuth 2.0 resource server:

  1. On the AM server that will be configured as an OAuth 2.0 client, set up an AM web or Java agent and policy in the Top Level Realm, /, to protect resources.

    See the Web agents documentation or the Java agents documentation for instructions on installing an agent. This example relies on the Tomcat Java agent, configured to protect resources in Apache Tomcat (Tomcat) at http://www.example.com:8080/.

    The policies for this example protect the Tomcat examples under http://www.example.com:8080/examples/, allowing GET and POST operations by all authenticated users. For more information, see Dynamic OAuth 2.0 authorization.

    After setting up the web or Java agent and the policy, you can make sure everything is working by attempting to access a protected resource, in this case, http://www.example.com:8080/examples/. The agent should redirect you to AM to authenticate with the default authentication module, where you can login as user demo password Ch4ng31t. After successful authentication, AM redirects your browser back to the protected resource and the Java agent lets you get the protected resource, in this case, the Tomcat examples top page.

    You should get HTTP 200 and the Apache Tomcat examples page.
    Figure 4. Accessing the Apache Tomcat examples
  2. On the AM server to be configured as an OAuth 2.0 authorization server, configure AM’s OAuth 2.0 authorization service as described in Authorization server configuration.

    The authorization endpoint to protect in this example is at http://authz.example.com:8080/openam/oauth2/realms/root/authorize.

  3. On the AM server to be configured as an OAuth 2.0 client, configure an AM OAuth 2.0 or OpenID Connect social authentication module instance for the Top Level Realm:

    Under Realms > Top Level Realm > Authentication > Modules, click Add Module. Name the module OAuth2, and select the Social Auth OAuth2 type, then click Create.

    The key settings for this example are the following:

    Client Id

    This is the client identifier used to register your client with AM’s authorization server, and then used when your client must authenticate to AM.

    Set this to myClientID for this example.

    Client Secret

    This is the client password used to register your client with AM’s authorization server, and then used when your client must authenticate to AM.

    Set this to password for this example. Make sure you use strong passwords when you actually deploy OAuth 2.0.

    Authentication Endpoint URL

    In this example, http://authz.example.com:8080/openam/oauth2/realms/root/authorize.

    This AM endpoint can take additional parameters. In particular, you must specify the realm if the AM OAuth 2.0 provider is configured for a subrealm rather than for the Top Level Realm.

When making a REST API call, specify the realm in the path component of the endpoint. You must specify the entire hierarchy of the realm, starting at the Top Level Realm. Prefix each realm in the hierarchy with the realms/ keyword. For example, /realms/root/realms/customers/realms/europe.

+ For example, if the OAuth 2.0 provider is configured for the realm customers within the Top Level Realm, then use the following URL: http://authz.example.com:8080/openam/oauth2/realms/root/realms/customers/authorize.

+ The /oauth2/authorize endpoint can also take module and service parameters. Use either as described in Authenticate with a browser, where module specifies the authentication module instance to use or service specifies the authentication chain to use when authenticating the resource owner.

Access Token Endpoint URL

In this example, http://authz.example.com:8080/openam/oauth2/realms/root/access_token.

This AM endpoint can take additional parameters. In particular, you must specify the realm if the AM OAuth 2.0 provider is configured for a subrealm rather than the Top Level Realm (/).

When making a REST API call, specify the realm in the path component of the endpoint. You must specify the entire hierarchy of the realm, starting at the Top Level Realm. Prefix each realm in the hierarchy with the realms/ keyword. For example, /realms/root/realms/customers/realms/europe.

+ For example, if the OAuth 2.0 provider is configured for the realm /customers, use the following URL: http://authz.example.com:8080/openam/oauth2/realms/root/realms/customers/access_token.

User Profile Service URL

In this example, http://authz.example.com:8080/openam/oauth2/realms/root/tokeninfo.

Scope

In this example, cn.

The demo user has common name demo by default, so by setting this to cn|Read your user name, AM can get the value of the attribute without the need to create additional identities, or to update existing identities. The description, Read your user name, is shown to the resource owner in the consent page.

Subject Property

In this example, cn.

Proxy URL

The client redirect URL, which in this example is http://client.example.com:8080/openam/oauth2c/OAuthProxy.jsp.

Account Mapper

In this example, org.forgerock.openam.authentication.modules.common.mapping.JsonAttributeMapper.

Account Mapper Configuration

In this example, cn=cn.

Attribute Mapper

In this example, org.forgerock.openam.authentication.modules.common.mapping.JsonAttributeMapper.

Attribute Mapper Configuration

In this example, cn=cn.

Create account if it does not exist

In this example, disable this functionality.

AM can create local accounts based on the account information returned by the authorization server.

  1. On the AM server configured to act as an OAuth 2.0 authorization server, register the Social Auth OAuth2 authentication module as an OAuth 2.0 confidential client, which is described in Client application registration.

    Under Realms > Top Level Realm > Applications > OAuth 2.0 > myClientID, adjust the following settings:

Client type

In this example, confidential. AM protects its credentials as an OAuth 2.0 client.

Redirection URIs

In this example, http://client.example.com:8080/openam/oauth2c/OAuthProxy.jsp.

If any Redirection URI scheme, host, or port differs from that of AM, add it to the global validation service to ensure that it is pre-approved, as described in Success and failure redirection URLs. Otherwise, AM rejects the redirection URI, even if it matches the client profile, and redirection fails.

Scopes

In this example, cn.

  1. Before you try it out, on the AM server configured to act as an OAuth 2.0 client, you must make the following additional change to the configuration.

    Your AM OAuth 2.0 client authentication module is not part of the default chain, and therefore AM does not call it unless you specifically request the OAuth 2.0 client authentication module.

    To cause the Java agent to request your OAuth 2.0 client authentication module explicitly, go to your agent profile configuration, in this case Realms > Top Level Realm > Applications > Agents > Java > Agent Name > AM Services > AM Login URL, and add http://client.example.com:8080/openam/XUI/?realm=/&module=OAuth2, moving it to the top of the list.

    Save your work.

    This ensures that the Java agent directs the resource owner to AM with the instructions to authenticate using the OAuth2 authentication module.

  2. Try it out.

    First, make sure you are logged out of AM. For example, by browsing to the logout URL, in this case http://client.example.com:8080/openam/XUI/?realm=/#logout.

    Next attempt to access the protected resource, in this case http://www.example.com:8080/examples/.

    If everything is set up properly, the Java agent redirects your browser to the login page of AM with module=OAuth2 among other query string parameters. After you authenticate (for example, as user demo, password Ch4ng31t), AM displays an authorization decision page.

    The resource owner decide to authorize the client to access the protected resource.
    Figure 5. The authorization decision page displayed to the resource owner

    When you click Allow, the authorization service creates an SSO session, and redirects the client back to the resource, thus letting the client access the protected resource. If you configured an attribute to store the saved consent decision, and you choose to save the consent decision for this authorization, AM can use that saved decision to avoid prompting you for authorization next time the client accesses the resource, but only ensure that you have authenticated and have a valid session.

    You should end up with HTTP 200 and the Apache Tomcat examples page.
    Figure 6. Successfully accessing the Apache Tomcat examples

Authorization server configuration

Configure the OAuth2 Provider service in a realm to expose the OAuth 2.0 endpoints and OAuth 2.0 administration REST endpoints.

  1. In the AM admin UI, go to Realms > Realm Name > Services, and click Add a Service.

  2. From the drop-down list, select the OAuth2 Provider service, leave the remaining fields empty, and click Create.

  3. On the OAuth 2.0 provider page, select the Advanced tab.

  4. Configure the Grant Types that clients will be able to use to request access, refresh, and ID tokens.

    Grant types reference
    Implicit
    SAML2
    Refresh Token
    Resource Owner Password Credentials
    Client Credentials
    Device Code
    Authorization Code
    Back Channel Request
    UMA
    JWT Bearer
    Token Exchange

    Related information:

  5. Configure the Response Type Plugins you need in your environment, based on the grant type flows that you will allow.

    Response plugins let the provider issue access tokens, ID tokens, authorization codes, and others, when the client requests a flow that interacts with the /oauth2/authorize endpoint.

    Response type plugin reference
    code|org.forgerock.oauth2.core.AuthorizationCodeResponseTypeHandler
    id_token|org.forgerock.openidconnect.IdTokenResponseTypeHandler
    device_code|org.forgerock.oauth2.core.TokenResponseTypeHandler
    token|org.forgerock.oauth2.core.TokenResponseTypeHandler
    none|org.forgerock.oauth2.core.NoneResponseTypeHandler
    • The id_token and none response types are used in OpenID Connect flows.

    • The code response type is used in the OAuth 2.0 and OpenID Connect Authorization Code grant flows.

    • The device_code response type was used for the Device grant flow, but it is not required in the current implementation and will be removed in a future release of AM.

    • The token response type is used in the OAuth 2.0 and OpenID Connect Implicit flows.

  6. Configure Persistent Claims

    Persistence lets you retain custom claims when you refresh an access token.

    In the Persistent Claims field, enter the claims that must be persisted between tokens. When an access token is refreshed, any claims that are listed here will be on the new token.

    • These claims are added before the access token modification script, allowing you to manipulate them in the modification script. For example, if a token has a claim called hostname that you want to be persisted when the token is refreshed, you could add that claim to the Persistent Claims list. You could then modify the script to persist that hostname in the new token, if it exists, or to add a hostname to the new token, if it does not exist.

    • Only custom, non-standard claims can be persisted. Standard claims such as scope (defined in the OAuth2 specification) and auditTrackingId (defined by default in AM) cannot be persisted.

  7. For other configuration options, see Additional configuration.

Additional configuration

The OAuth 2.0 provider is highly configurable:

  • To configure the OAuth 2.0 provider in the AM admin UI, go to Realms > Realm Name > Services, and select OAuth2 Provider.

  • To adjust global OAuth 2.0 provider defaults, go to Configure > Global Services, and click OAuth2 Provider.

See the OAuth2 Provider reference section for details on each of the fields in the provider.

OAuth 2.0 Provider Configuration Options
Task Resources

Configure the authorization server to issue refresh tokens

Learn why refresh tokens are useful in your environment, how to configure AM to issue them, and how to request them.

Adjust the lifetimes of tokens and codes

If necessary, adjust the lifetimes for authorization codes (a lifetime of 10 minutes or less is recommended in RFC 6749), access tokens, and refresh tokens.

Configure them on the Core tab of the provider.

N/A

Configure OAuth 2.0 server behavior

AM provides plugin points that let you extend default OAuth 2.0 server behavior. Use these extension points to customize:

  • The content of OAuth 2.0 access tokens

  • The validation of requested scopes

  • The resource owner information retrieved based on an issued access token

  • Scope values that are returned for an access token

  • Data that is returned from an authorization request

Configure the OAuth 2.0 provider for token exchange

Following the OAuth 2.0 Token Exchange specification, the provider can let your clients exchange tokens.

Configure the OAuth 2.0 service to provide scopes dynamically

The OAuth 2.0 provider can leverage the AM Authorization service to grant or deny scopes dynamically.

Configure a custom response plugin

To configure a custom response type plugin, add it to the AM classpath, and add the custom response types and the plugin class names to the list of Response Type Plugins field, on the Advanced tab.

N/A

Decide how scopes appear in the consent pages

To change how scopes appear, configure the Client Registration Scope Allowlist field on the Advanced tab of the OAuth 2.0 provider.

Scopes may be entered as simple strings or pipe-separated strings representing the internal scope name, locale, and localized description. For example: read|en|Permission to view email messages in your account.

Decide how to manage consent

You can:

  • Allow users to save consent so the OAuth 2.0 provider remembers their consented scopes.

  • Allow clients to skip consent so no consent page is displayed to the resource owners.

  • Allow clients to revoke consent.

Configure a remote consent server

This is useful, for example, when your environment must hand off the consent-gathering part of the OAuth 2.0 flows to a separate service.

Configure the attribute AM uses to retrieve the user profile

This is useful, for example, in cases where the resource owner should log in with their email address instead of with a username.

Configure client-side tokens

Configure client-side tokens so that resource servers can directly introspect the tokens without making a call to AM.

Configure OpenID-Connect specific options

UMA providers also use these options.

Change the attribute used to find the user profile

If you use an external identity repository, and users log in with an attribute other than their user ID (such as an email address), you must configure AM authentication to allow this.

For example, to let resource owners log in using an email address, stored in the LDAP mail attribute, follow these steps:

  1. On the OAuth2 provider Advanced tab, add the LDAP profile attribute to the User Profile Attribute(s) the Resource Owner is Authenticated On list, and save your changes.

  2. Go to Realms > Realm Name > Identity Stores > Identity Store Name > Authentication Configuration.

  3. Set the value of the Authentication Naming Attribute field to the LDAP attribute required.

    For example, mail.

    If you change the value of Authentication Naming Attribute after you have deployed and configured AM, you must update or recreate all existing identities to refresh user DNs.

    Failure to do so could result in unsuccessful authentication or risk of impersonation attacks.

  4. Create an LDAP authentication module or an LDAP decision node to use with the identity repository.

    Configure the following fields:

    • In the Attribute Used to Retrieve User Profile field, set the attribute to mail.

    • In the Attributes Used to Search for a User to be Authenticated list, add the mail attribute.

    • Save your changes.

  5. Ensure the resource owners use the authentication mechanism you configured.

    Specify the tree or chain by using one or more of the methods below. AM checks for the configured value in the following order, using the first value found:

    1. For a specific access token REST request.

      Set the auth_chain parameter.

    2. Individually for a realm, overriding the realm-level setting below.

      Go to Realms > Realm Name > Services > OAuth2 Provider > Advanced, and set the Password Grant Authentication Service property.

    3. Individually for a realm.

      Go to Realms > Realm Name > Authentication > Settings > Core, and set the Organization Authentication Configuration property.

    4. Globally, for all realms.

      Go to Configure > Authentication > Core Attributes > Core, and set the Organization Authentication Configuration property.

For more information, see Configure AM for authentication.

Configure AM for client-side OAuth 2.0 tokens

When configured for client-side tokens, AM returns a token (instead of the token reference it returns when configured for server-side tokens) to the client after successfully completing one of the grant flows. For more information about client-side and server-side tokens, see Token storage location.

Enable client-side OAuth 2.0 tokens

These steps configure AM to issue client-side access and refresh tokens:

  1. In the AM admin UI, go to Realms > Realm Name > Services > OAuth2 Provider.

  2. On the Core tab, enable Use Client-Side Access & Refresh Tokens.

  3. Enable Issue Refresh Tokens and/or Issue Refresh Tokens on Refreshing Access Tokens.

  4. Save your changes.

  5. Configure client-side token denylisting.

    For more information, see Client-side OAuth 2.0 token denylist.

  6. Configure either client-side token signature or client-side token encryption.

    Token signature is enabled by default when client-side tokens are enabled. By default, token signature is configured using a demo key that you must change in production environments.

    If you enable token encryption, token signature is disabled, because encryption is performed using direct symmetric encryption.

Client-side OAuth 2.0 token denylist

Adding tokens to the denylist prevents client-side tokens from being reused if the authorization code has been replayed, or if tokens have been revoked by either the client or the resource owner.

Client-side refresh tokens have corresponding entries in a CTS allowlist, rather than a denylist. When presenting a client-side refresh token, AM checks that a matching entry is found in the CTS allowlist, and prevents reissue if the record does not exist.

Adding a client-side OAuth 2.0 token to the denylist also removes associated refresh tokens from the allowlist.

  1. In the AM admin UI, go to Configure > Global Services > OAuth2 Provider.

  2. Under Global Attributes, enter the number of denylisted tokens in the Token Denylist Cache Size field.

    This cache size determines the number of denylisted tokens to cache in memory, to speed up denylist checks. Enter a number based on the estimated number of token revocations that a client will issue (for example, when the user gives up access or when an administrator revokes a client’s access).

    Default: 10000

  3. In the Denylist Poll Interval field, enter the interval in seconds for AM to check for token denylist changes from the CTS data store.

    The longer the polling interval, the more time a malicious user has to connect to other AM servers in a cluster and make use of a stolen OAuth v2.0 access token. Shortening the polling interval improves the security for revoked tokens but might incur a minimal decrease in overall AM performance due to increased network activity.

    Default: 60 seconds

  4. In the Denylist Purge Delay field, enter the length of time, in minutes, that denylist tokens can exist before being purged beyond their expiration time.

    When client-side token denylisting is enabled, AM tracks OAuth v2.0 access tokens over the configured lifetime of those tokens plus the denylist purge delay. For example, if the access token lifetime is set to 6000 seconds and the denylist purge delay is one minute, then AM tracks the access token for 101 minutes. You can increase the denylist purge delay if you expect system clock skews in an AM server cluster to be greater than one minute. There is no need to increase the denylist purge delay for servers running a clock synchronization protocol, such as Network Time Protocol.

    Default: 1 minute

  5. Save your changes.

Client-side OAuth 2.0 token encryption

To protect OAuth 2.0 client-side access and refresh tokens, AM supports encrypting their JWTs using AES authenticated encryption. Because this encryption also protects the integrity of the JWT, you only need to configure AM to sign OAuth 2.0 client-side tokens if token encryption is disabled.

  1. Go to Realms > Realm Name > Services > OAuth2 Provider.

  2. On the Core tab, enable Use Client-Side Access & Refresh Tokens.

  3. On the Advanced tab, enable Client-Side Token Encryption.

    The alias mapped to the algorithm is defined in the secret stores, as shown in the table below:

    Secret ID mappings for encrypting client-side OAuth 2.0 tokens

    This table shows the secret ID mapping used to encrypt client-side access tokens:

    Secret ID Default alias Algorithms

    am.services.oauth2.stateless.token.encryption

    directentest

    A128CBC-HS256

    By default, secret IDs are mapped to demo keys contained in the default keystore provided with AM and mapped to the default-keystore keystore secret store. Use these keys for demo and test purposes only. For production environments, replace the secrets as required and create mappings for them in a secret store configured in AM.

    For more information about managing secret stores and mapping secret IDs to aliases, see Secrets, certificates, and keys.

  4. Save your changes.

    Client-side OAuth 2.0 access and refresh tokens will now be encrypted.

Client-side OAuth 2.0 token digital signatures

AM supports digital signature algorithms that secure the integrity of client-side tokens.

Client-side tokens must be signed and/or encrypted for security reasons. If your environment does not support encrypting OAuth 2.0 tokens, you must configure signing to protect them against tampering.

AM exposes the public key to validate client-side token signatures in its JWK URI. See /oauth2/connect/jwk_uri.

These steps configure the OAuth 2.0 provider to sign client-side tokens:

  1. Go to Realms > Realm Name > Services, and click OAuth2 Provider.

  2. On the Advanced tab, in the OAuth2 Token Signing Algorithm list, select the signing algorithm to use for signing client-side tokens.

    The alias mapped to the algorithm is defined in the secret stores, as shown in the table below:

    Secret ID mappings for signing client-side OAuth 2.0 tokens

    This table shows the secret ID mappings used to sign client-side access tokens:

    Secret ID Default alias Algorithms

    am.services.oauth2.stateless.signing.ES256

    es256test

    ES256

    am.services.oauth2.stateless.signing.ES384

    es384test

    ES384

    am.services.oauth2.stateless.signing.ES512

    es512test

    ES512

    am.services.oauth2.stateless.signing.HMAC

    hmacsigningtest

    HS256
    HS384
    HS512

    am.services.oauth2.stateless.signing.RSA

    rsajwtsigningkey

    PS256
    PS384
    PS512
    RS256
    RS384
    RS512

    By default, secret IDs are mapped to demo keys contained in AM’s default keystore and mapped to the default-keystore secret store. Use these keys for demo and test purposes only. In production environments, replace the secrets as required and create mappings for them in a secret store configured in AM.

    For more information about managing secret stores and mapping secret IDs to aliases, see Secrets, certificates, and keys.

  3. Save your changes.

    Client-side OAuth 2.0 access and refresh tokens will now be signed.

OAuth 2.0 scopes

OAuth 2.0 flows require scopes to limit the client’s access to the resource owner’s resources.

What are scopes?

Scopes are a way to restrict client access to the resource owner’s resources, as defined in the OAuth 2.0 Authorization Framework.

Scopes are not associated with data and, in practice, they are just concepts specified as strings that the resource server must interpret in order to provide the required access or resources to the client. The OAuth 2.0 framework does not define any particular value for scopes since they are dependent on the architecture of your environment.

For example, a client may request the write scope, which the resource server may interpret as that the client wants to save some new information in the user’s account, such as images or documents.

A client can request one or more scopes, which AM may display in the consent screen. If the resource owner agrees to share access to their resources, scopes are included in the access token.

For security reasons, AM only accepts the scopes set in the Scope(s) or Default Scope(s) fields in the client profile (Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Core).

If the client requests scopes, AM checks them against the Scope(s) field in the client profile. If the client requests a scope that is not configured, AM returns an Unknown/invalid scope(s) error.

If the client does not request any scopes, AM uses the scopes in the Default Scope(s) field of the client profile. If no default scopes are set in the client profile, AM uses the scopes set in the Default Scope(s) field of the OAuth 2.0 provider.

If no scopes are configured by default, AM returns a No scope requested error. AM does not use the default scopes in any other circumstance.

You can use an access token modification script to override the allowed scopes specified at the OAuth 2.0 client level.

The Client Registration Scope Allowlist field of the OAuth 2.0 provider restricts the scopes with which a client can register. In this sense, this field is used for OpenID Connect discovery and dynamic client registration only.

You can also use this field to configure how AM presents the scopes on the AM consent screen. Scopes are not displayed on the consent screen by default. You can either configure clients to use implied consent, or configure the scopes that should be displayed.

Because scope names are arbitrary, they might not be descriptive enough for the resource owner to understand their purpose. In addition, you might not want resource owners to see a particular scope that is for internal use only.

Display scopes in the consent screen

You can configure the AM consent screen to show, for each scope, one of the following options:

The scope itself A localized description Neither the scope nor a description
The OAuth 2.0 AM user interface consent screen requesting access to the write scope.
The OAuth 2.0 AM user interface consent screen showing the English description of a scope.
The OAuth 2.0 AM user interface consent screen not showing scopes or descriptions

Configure how scopes appear in the consent screen by client or by realm (in the OAuth 2.0 provider service).

For examples, refer to the Client Registration Scope Allowlist field in the provider’s Advanced reference section or the Scope(s) field in Core Properties.

Client-level configuration overrides the configuration set at the provider level.

Special scopes

AM reserves the following special scopes that cannot be added during dynamic client registration:

am-introspect-all-tokens

Add this scope to the Scopes(s) field in a client profile to let the client introspect tokens issued to other clients, as long as all clients are registered in the same realm.

For example:

  1. Client A is registered in the /customers/NA realm, and it is issued a token there.

  2. Client B is registered in the /customers realm. It cannot introspect Client A’s token because they are not in the same realm. Client B can only introspect tokens from other clients registered in the /customers realm.

am-introspect-all-tokens-any-realm

Add this scope to the Scopes(s) field in a client profile to let the client introspect tokens issued to other clients, as long as they are registered in the realm of the introspecting client, or in a subrealm of it.

For example:

  1. Client A is registered in the /customers/NA realm, and it is issued a token there.

  2. Client B is registered in the /customers realm. It can introspect Client A’s token because the /customers/NA realm is a subrealm of the /customers realm.

    Client B can introspect tokens for any client registered in the /customer realm, or any subrealm of it.

For security reasons, give these scopes only to the clients that need them.

Related information:

Many OAuth 2.0 and OIDC flows require user consent to grant the client access to the user’s resources.

OAuth 2.0 and OIDC client applications can use implied consent. With implied consent, AM does not prompt for consent during authorization flows. This simplifies the flows. The user has only to sign on to grant the client access to protected resources.

To enable implied consent, follow these steps:

  1. In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Advanced.

  2. Select Implied Consent.

  3. Save your changes.

  4. Make sure AM lets users skip granting consent.

    By default, this is enabled in the OAuth 2.0 provider configuration, Realms > Realm Name > Services > OAuth2 Provider > Consent > Allow Clients to Skip Consent.

    If that is disabled for your deployment, switch to the OAuth2 Provider Overrides tab in the client profile, make the following changes to the settings, and save your work:

    Enable OAuth2 Provider Overrides

    Enabled

    Allow Clients to Skip Consent

    Enabled

To disable implied consent and force users to grant consent during authorization flows, disable the settings described in the previous steps.

Configure how the client application appears to the user. The following alternatives are available:

  • Customize the built-in consent screen:

    1. In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID.

      Edit the following settings under the Advanced tab, then save your work:

      Display name

      Display this name to the user when prompting for consent.

      Display description

      Explain the decision to the user when prompting for consent.

      Privacy Policy URI

      Add for the client applications privacy policy.

    2. Configure how scopes display.

      Users grant consent based on scopes. Scopes restrict what is shared with the client and limit what the client can do with the user’s data. In OAuth 2.0, the meanings of scopes depend on the implementation. In OpenID Connect, scopes map to standard user data claims; for example, the profile scope requests access to the user’s default profile claims.

      For details, refer to Display scopes in the consent screen.

  • Delegate consent gathering to another service.

    For details, refer to Remote consent.

AM can store the consent decisions in the user profile. This minimizes redundant prompts and improves the user experience.

When an OAuth 2.0 client application requests scopes, AM checks the user profile for scopes the user has already consented to. AM does not prompt the user to consent again to the same scopes, only scopes the user has not consented to.

To save consent:

  1. Add a multivalued string syntax attribute, such as custom_consent, to user profiles for saving consent decisions.

    The attribute must be of type array.

    For instructions on adding the attribute, refer to Update the identity repository for a custom attribute.

  2. In the AM admin UI, go to Realms > Realm Name > Services > OAuth2 Provider and select the Consent tab.

  3. In the Saved Consent Attribute field, add the name of the attribute you created, such as custom_consent.

  4. Save your changes.

To force AM to prompt for consent for a specific client request, add the prompt=consent parameter.

You can revoke a client application’s access at any time through the user dashboard page:

  1. Sign on as an end user.

    Your dashboard page displays.

  2. Expand Authorized Apps.

  3. Click the delete icon to revoke access:

    Revoke client application access through the user dashboard.
    Figure 7. Authorized Apps pane

AM supports OAuth 2.0 remote consent services, which allow the consent-gathering part of an OAuth 2.0 flow to be handed off to a separate service.

A remote consent service renders a consent page, gathers the result, signs and encrypts the result, and returns it to the authorization server.

During an OAuth 2.0 flow that requires user consent, AM can create a consent request JWT that contains the necessary information to render a consent gathering page. It does not send the actual values of the requested scopes.

Consent request JWT example and properties
{
  "clientId": "myClient",
  "iss": "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha",
  "csrf": "gjeH2C43nFJwW+Ir1zL3hl8kux9oatSZRso7aCzI0vk=",
  "client_description": "",
  "aud": "rcs",
  "save_consent_enabled": true,
  "claims": {},
  "scopes": {
      "write": null
  },
  "exp": 1536229486,
  "iat": 1536229306,
  "client_name": "My Client",
  "consentApprovalRedirectUri": "https://openam.example.com:8443/openam/oauth2/authorize?client_id=MyClient&response_type=code&redirect_uri=https://application.example.com:8443/callback&scope=write&state=1234zy",
  "username": "demo"
}
iat

Specifies the creation time of the JWT.

iss

Specifies the name of the issuer - configured in the OAuth 2.0 provider service in AM.

aud

Specifies the name of the expected recipient of the JWT, in this case, the remote consent service.

exp

Specifies the expiration time of the JWT.

Use short expiration times, for example, 180 seconds, as the JWT is intended for use in machine-to-machine interactions.

csrf

Specifies a unique string that must be returned in the response to help prevent cross-site request forgery (CSRF) attacks.

AM generates this string from a hash of the user’s session ID.

client_id

Specifies the ID of the OAuth 2.0 client making the request.

client_name

Specifies the display name of the OAuth 2.0 client making the request.

client_description

Specifies a description of the OAuth 2.0 client making the request.

username

Specifies the username of the logged-in user.

Ensure you encrypt the JWT if the username could be considered personally identifiable information.
scopes

Specifies the requested scopes.

claims

Specifies the claims the request is making.

Use the claims field for additional information to display on the remote consent page that helps the user to determine if consent should be granted. For example, Open Banking OAuth 2.0 flows may include identifiers for a money transaction.

save_consent_enabled

Specifies whether to provide the user the option to save their consent decision.

If set to false, the value of the save_consent property in the consent response from the RCS must also be false.

consentApprovalRedirectUri

Specifies the URI to return the resource owner to after they have provided consent. The response JWT must be sent as a consent_response form parameter in a POST operation to this URI.

Acting as the authorization server, AM signs and encrypts the JWT.

The remote consent service decrypts the JWT, verifies the signature and other details, such as the validity of the aud, iss and exp properties, and renders the consent page to the resource owner.

After the remote consent service gathers the user’s consent, it creates a consent response JWT, encrypts and signs the response, and returns it to AM for processing.

Consent response JWT example and properties
{
  "consent_response" : {
    "clientId": "myClient",
    "iss": "rcs",
    "csrf": "gjeH2C43nFJwW+Ir1zL3hl8kux9oatSZRso7aCzI0vk=",
    "client_description": "",
    "aud": "https://openam.example.com:8443/openam/oauth2",
    "save_consent": true,
    "claims": {},
    "scopes": "[write]",
    "exp": 1536229430,
    "iat": 1536229250,
    "client_name": "My Client",
    "consentApprovalRedirectUri": "https://openam.example.com:8443/openam/oauth2/authorize?client_id=MyClient&response_type=code&redirect_uri=https://application.example.com:8443/callback&scope=write&state=1234zy",
    "username": "demo",
    "decision": true
  },

}
iat

Specifies the creation time of the JWT.

iss

Specifies the name of the remote consent service.

Must match the value of the aud property received from AM.

aud

Specifies the name of the expected recipient of the JWT, in this case, AM acting as the AS.

Must match the value of the iss property received from AM.

exp

Specifies the expiration time of the JWT.

Use short expiration times, for example, 180 seconds, as the JWT is intended for use in machine-to-machine interactions.

decision

Specifies true if consent was provided, or `false ` if consent was withheld.

client_id

Specifies the ID of the OAuth 2.0 client making the request, matching the value provided in the request.

client_name

Specifies the display name of the OAuth 2.0 client making the request.

client_description

Specifies a description of the OAuth 2.0 client making the request.

scopes

Specifies an array of allowed scopes.

Must be equal to, or a subset of the array of scopes in the request.

save_consent

Specifies true if the user chose to save their consent decision, or false if they did not.

If save_consent_enabled was set to false in the request, save_consent must also be false.

consentApprovalRedirectUri

Specifies the URI to return the resource owner to after they have provided consent.

AM decrypts and verifies the signature of the consent response and other details, such as the validity of the aud, iss and exp properties, and processes the response. For example, it may save the consent decision if configured to do so.

If the remote consent service compresses the consent response JWT, AM rejects JWTs that expand to a size larger than 32 KiB (32768 bytes). For more information, see Control the size of compressed JWTs.

AM and the remote consent service make their required public keys available from two `jwk_uri`s, to enable signing and encryption between the two servers.

Configuring a remote consent service requires completion of these high-level tasks:

Task Resources

Add the details of the remote consent service as an agent profile in AM

You can configure a single remote consent service in a realm, by adding the details to a remote consent agent profile.

The profile defines properties for signing and encrypting the consent request and consent response, redirect URI, and the jwk_uri URI details of the remote consent service.

Enable remote consent and specify the agent profile in AM’s OAuth 2.0 provider service.

Configure the remote consent service with AM’s jwk_uri URI details.

The remote consent service must be able to obtain the required signature and decryption keys from AM.

N/A

AM includes an example remote consent service. Do not use the example in production environments.

Configure AM to use a remote consent service

To add the details of the remote consent service as an agent profile:

  1. In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Remote Consent, and click Add Remote Consent Agent.

  2. Enter an agent ID, for example, myRCSAgent, and click Create.

  3. If you will be using an HMAC algorithm for signing the JWTs, enter the shared symmetric key in the Remote Consent Service secret field.

    This step is not required when using other algorithms.

  4. Select the Remote Consent Agent, and configure the properties as required.

    Remote consent agent properties
    Group

    Configure several remote consent agent profiles by assigning them to a group.

    Default value: none

    amster attribute: agentgroup

    Remote Consent Service secret

    If the remote consent agent needs to authenticate to AM, enter the password it will use.

    amster attribute: userpassword

    Redirect URL

    Specify the URL to which the user should be redirected during the OAuth 2.0 flow to obtain their consent.

    The AM example remote consent service provides an /oauth2/consent path to obtain consent from the user.

    Example: https://rcs.example.com:8443/openam/oauth2/consent

    amster attribute: remoteConsentRedirectUrl

    Enable consent request Encryption

    Specify whether to encrypt the consent request JWT sent to the remote consent service.

    Default: true

    amster attribute: remoteConsentRequestEncryptionEnabled

    Consent request Encryption Algorithm

    Specify the encryption algorithm used to encrypt the consent request JWT sent to the remote consent service.

    AM supports the following encryption algorithms:

    • A128KW - AES Key Wrapping with 128-bit key derived from the client secret.

    • A192KW - AES Key Wrapping with 192-bit key derived from the client secret.

    • A256KW - AES Key Wrapping with 256-bit key derived from the client secret.

    • RSA-OAEP - RSA with Optimal Asymmetric Encryption Padding (OAEP) with SHA-1 and MGF-1.

    • RSA-OAEP-256 - RSA with OAEP with SHA-256 and MGF-1.

    • RSA1_5 - RSA with PKCS#1 v1.5 padding.

    • dir - Direct encryption with AES using the hashed client secret.

    Default value: RSA-OAEP-256

    amster attribute: remoteConsentRequestEncryptionAlgorithm

    Consent request Encryption Method

    Specify the encryption method used to encrypt the consent request JWT sent to the remote consent service

    AM supports the following encryption methods:

    • A128GCM, A192GCM, and A256GCM - AES in Galois Counter Mode (GCM) authenticated encryption mode.

    • A128CBC-HS256, A192CBC-HS384, and A256CBC-HS512 - AES encryption in CBC mode, with HMAC-SHA-2 for integrity.

    Default value: A128GCM

    amster attribute: remoteConsentRequestEncryptionMethod

    Consent response signing algorithm

    Specify the algorithm used to verify a signed consent response JWT received from the remote consent service.

    AM supports signing algorithms listed in JSON Web Algorithms (JWA): "alg" (Algorithm) Header Parameter Values for JWS:

    • ES256 - ECDSA with SHA-256 and NIST standard P-256 elliptic curve.

    • ES384 - ECDSA with SHA-384 and NIST standard P-384 elliptic curve.

    • ES512 - ECDSA with SHA-512 and NIST standard P-521 elliptic curve.

    • HS256 - HMAC with SHA-256.

    • HS384 - HMAC with SHA-384.

    • HS512 - HMAC with SHA-512.

    • RS256 - RSASSA-PKCS-v1_5 using SHA-256.

    Default value: RS256

    amster attribute: remoteConsentResponseSigningAlg

    Consent response encryption algorithm

    Specify the encryption algorithm used to decrypt the consent response JWT received from the remote consent service.

    AM supports the following encryption algorithms:

    • A128KW - AES Key Wrapping with 128-bit key derived from the client secret.

    • A192KW - AES Key Wrapping with 192-bit key derived from the client secret.

    • A256KW - AES Key Wrapping with 256-bit key derived from the client secret.

    • RSA-OAEP-256 - RSA with OAEP with SHA-256 and MGF-1.

    • dir - Direct encryption with AES using the hashed client secret.

    The decryption key used depends on the algorithm chosen. The relevant secret IDs and the default decryption key aliases are shown in the table below: The following table shows the secret ID mapping used to decrypt remote consent responses:

    Secret ID Default Alias Algorithms(1)

    am.services.oauth2.remote.consent.response.decryption

    test

    RSA-OAEP-256

    (1) If you select an algorithm other than RSA-OAEP-256 for decrypting consent responses, the value of the remote consent service secret property is used, instead of an entry from the secret stores.

    By default, secret IDs are mapped to demo keys contained in the default keystore provided with AM and mapped to the default-keystore keystore secret store. Use these keys for demo and test purposes only. For production environments, replace the secrets as required and create mappings for them in a secret store configured in AM.

    For more information about managing secret stores and mapping secret IDs to aliases, see Secrets, certificates, and keys.

    Default value: RSA-OAEP-256

    amster attribute: remoteConsentResponseEncryptionAlgorithm

    Consent request Signing Algorithm

    Specify the algorithm used to sign the consent request JWT sent to the remote consent service.

    The signing key used depends on the algorithm chosen. The relevant secret IDs and the default signing key aliases are shown in the table below:

    The following table shows the secret ID mappings used to sign remote consent requests:

    Secret ID Default Alias Algorithms(1)

    am.applications.agents.remote.consent.request.signing.ES256

    es256test

    ES256

    am.applications.agents.remote.consent.request.signing.ES384

    es384test

    ES384

    am.applications.agents.remote.consent.request.signing.ES512

    es512test

    ES512

    am.applications.agents.remote.consent.request.signing.RSA

    rsajwtsigningkey

    RS256
    RS384
    RS512
    PS256
    PS384
    PS512

    (1) If you select an HMAC algorithm for signing consent requests (HS256, HS384, or HS512), the value of the Remote Consent Service secret property is used, instead of an entry from the secret stores.

    Since the HMAC secret is shared between AM and the remote consent client, a malicious user compromising the client could potentially create tokens that AM would trust. Therefore, to protect against misuse, AM also signs the token using a non-shared signing key configured in the am.services.oauth2.jwt.authenticity.signing secret ID.

    By default, secret IDs are mapped to demo keys contained in the default keystore provided with AM and mapped to the default-keystore keystore secret store. Use these keys for demo and test purposes only. For production environments, replace the secrets as required and create mappings for them in a secret store configured in AM.

    For more information about managing secret stores and mapping secret IDs to aliases, see Secrets, certificates, and keys.

    Default value: RS256

    amster attribute: remoteConsentRequestSigningAlgorithm

    Consent response encryption method

    Specify the encryption method used to decrypt the consent response JWT received from the remote consent service.

    AM supports the following encryption methods:

    • A128GCM, A192GCM, and A256GCM - AES in Galois Counter Mode (GCM) authenticated encryption mode.

    • A128CBC-HS256, A192CBC-HS384, and A256CBC-HS512 - AES encryption in CBC mode, with HMAC-SHA-2 for integrity.

    Default value: A128GCM

    amster attribute: remoteConsentResponseEncryptionMethod

    Public key selector

    Specify whether the remote consent service provides its public keys using a JWKs_URI, or manually in JWKs format.

    If you select JWKs, enter the keys in the Json Web Key property. Otherwise complete the JWKs URI-related properties.

    Default: JWKs_URI

    amster attribute: remoteConsentRedirectUrl

    Json Web Key URI

    Specify the URI from which AM can obtain the remote consent service’s public keys.

    The example remote consent service uses the URI /oauth2/consent/jwk_uri to provide its public keys.

    amster attribute: jwksUri

    JWKs URI content cache timeout in ms

    Specify the amount of time, in milliseconds, that the content of the JWKs' URI is cached for before being refreshed. Caching the content avoids fetching it for every token encryption or validation.

    Default: 3600000

    amster attribute: com.forgerock.openam.oauth2provider.jwksCacheTimeout

    JWKs URI content cache miss cache time

    Specify the amount of time, in milliseconds, that AM waits before fetching the URI’s content again when a key ID (kid) is not in the JWKs that are already cached.

    For example, if a request comes in with a kid that is not in the cached JWKs, AM checks the value of JWKs' URI content cache miss cache time. If the amount of time specified in this property has already passed since the last time AM fetched the JWKs, AM fetches them again. Otherwise, the request is rejected.

    Use this property as a rate limit to prevent denial-of-service attacks against the URI.

    Default: 60000

    amster attribute: com.forgerock.openam.oauth2provider.jwkStoreCacheMissCacheTime

    Json Web Key

    If the Public key selector: property is set to JWKs, specify the remote consent service’s public keys, in JSON Web Key format.

    Example:

    {
      "keys": [
        {
          "kty": "RSA",
          "kid": "RemA6Gw0...LzsJ5zG3E=",
          "use": "enc",
          "alg": "RSA-OAEP-256",
          "n": "AL4kjz74rDo3VQ3Wx...nhch4qJRGt2QnCF7M0",
          "e": "AQAB"
        },
        {
          "kty": "RSA",
          "kid": "wUy3ifIIaL...eM1rP1QM=",
          "use": "sig",
          "alg": "RS256",
          "n": "ANdIhkOZeSHagT9Ze...ciOACVuGUoNTzztlCUk",
          "e": "AQAB"
        }
      ]
    }

    amster attribute: jwkSet

    Consent Request Time Limit

    Specify the amount of time, in seconds, for which the consent request JWT sent to the remote consent service should be considered valid.

    Default: 180

    amster attribute: requestTimeLimit

  5. Save your changes.

    The remote consent agent profile is now available for selection in the OAuth 2.0 provider. See Configure the OAuth 2.0 provider to use a remote consent agent profile.

Configure the OAuth 2.0 provider to use a remote consent agent profile

To add the details of the remote consent agent profile to an OAuth 2.0 provider service:

  1. In the AM admin UI, go to Realms > Realm Name > Services > OAuth2 Provider.

  2. On the Consent tab:

    • Click Enable Remote Consent.

    • In the Remote Consent Service ID drop-down list, select the agent ID of the remote consent agent. For example, myRCSAgent.

  3. If required, modify the supported signing and encryption methods and algorithms used for the consent request and consent response JSON web tokens.

    For more information on the available properties, see Consent.

    Example
    Configure the service ID, and encryption and signing properties.
    Figure 8. Configure RCS in an OAuth 2.0 provider
  4. Save your changes.

    OAuth 2.0 flows by any client in the realm will now use the remote consent service. OAuth 2.0 clients in other realms are unaffected.

Configure the AM example remote consent service

AM includes an example remote consent service that lets you demonstrate and test remote consent.

The example remote consent service is not intended for use in production environments, because the encryption and signing algorithms are not configurable. It is just an example that shows how you can configure AM to use a custom remote consent service.

The following example uses two instances of AM:

  • One instance that acts as the authorization server. For example, https://openam.example.com:8443/openam.

  • One instance that acts as the example remote consent service. For example, https://rcs.exampe.com:8443/openam.

Perform the following steps to configure your environment:

  1. As an administrative user, for example, amAdmin log in to the instance that acts as the example remote consent service.

  2. Go to Realms > Realm Name > Services, and click Add a Service.

  3. From the Choose a service type drop-down list, select Remote Consent Service.

  4. Perform the following steps to configure the remote consent service:

    • In Client Name, enter the agent ID given to the remote consent agent profile in AM.

      In this example, enter myRCSAgent.

    • In Authorization Server jwk_uri, enter the URI where the remote consent service will obtain the keys that the authorization service uses to sign and encrypt the consent request. These keys include:

      • The public signing key, used to sign the consent request that is sent to the remote consent server, so that it can be validated on the remote consent server.

      • The public encryption key for the consent response, so that the response can be encrypted (if encryption is enabled).

        The default JWKs URI for remote consent clients is /oauth2/consent_agents/jwk_uri.

For example, https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/consent_agents/jwk_uri.

  • Click Create.

  • Verify the configuration. For more information about the available properties, see Remote consent service.

    1. Configure the secret IDs for encrypting the consent request and signing the consent response.

      You can use an existing secret store at the global or realm level, or create a new secret store. This step assumes you have a keystore secret store in the realm where the remote consent service is configured:

  • Go to Realms > Realm Name > Secret Stores, and click the name of the keystore secret store that contains the secrets you will use to sign and encrypt the consent response.

  • On the Mappings tab, add the following mappings if not already present:

    • am.services.oauth2.remote.consent.response.signing.RSA: rsajwtsigningkey

    • am.services.oauth2.remote.consent.request.encryption: test

    These keys must match the configuration of the remote consent service agent.

    For more information about mapping secrets, see Map and rotate secrets.

    1. In the AM admin UI of the instance acting as the OAuth 2.0 provider, configure a remote consent service agent by performing the steps in Configure AM to use a remote consent service.

      The example remote consent service provides an /oauth2/consent/jwk_uri path to provide its public keys to the authorization server. In this example, configure https://rcs.example.com:8443/openam/oauth2/consent/jwk_uri in the Json Web Key URI field.

    2. Configure the authorization server to use the remote consent service agent by performing the steps in Configure the OAuth 2.0 provider to use a remote consent agent profile.

    3. Test your configuration.

      Performing an OAuth 2.0 flow on the AM instance that is acting as the authorization server will redirect the user to the second instance when user consent is required:

      Example remote consent service

      The remote consent service renders the consent page, using the decrypted information received from AM acting as the authorization server.

      Note that the fr-dark-theme has been applied to the AM instance acting as the remote consent service for the purpose of this demonstration.

      For more information on customizing the user interface, see UI customization.

Client application registration

OAuth 2.0 or OpenID Connect client applications must register with AM before they can connect.

Registration involves setting up a client application profile in one of the following ways:

Create a client profile

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

  2. Click Add Client and provide values for Client ID, Client secret, Redirection URIs, Scope(s), and Default Scope(s).

    Finally, click Create to create the profile.

  3. Adjust the configuration as needed, using the inline help and the following documentation:

    Core
    Group

    Set this field if you have configured an OAuth 2.0 client group.

    Status

    Specify whether the client profile is active for use or inactive.

    Client secret

    Specify the client secret as described by RFC 6749 in the section, Client Password.

    For OAuth 2.0/OpenID Connect 1.0 clients, AM uses the client password as the client shared secret key when signing the contents of the request parameter with HMAC-based algorithms, such as HS256.

    Client type

    Specify the client type.

    Confidential clients can maintain the confidentiality of their credentials, such as a web application running on a server where its credentials are protected. Public clients run the risk of exposing their passwords to a host or user agent, such as a JavaScript client running in a browser.

    Allow wildcard ports in redirection URIs

    Specify whether AM allows the use of wildcards (* characters) in the redirection URI port to match one or more ports.

    The URL configured in the redirection URI must be either localhost, 127.0.01, or ::1. For example, http://localhost:*/, https://127.0.0.1:80*/, or https://[::1]:*443/.

    Enable this setting, for example, for desktop apps that start a web server on a random free port during the OAuth 2.0 flow.

    Redirection URIs

    Specify client redirection endpoint URIs as described by RFC 6749 in the section, Redirection Endpoint. AM’s OAuth 2.0 authorization service redirects the resource owner’s user-agent back to this endpoint during the authorization code grant process. If your client has more than one redirection URI, then it must specify the redirection URI to use in the authorization request.

    Redirection URI values must NOT contain a fragment () and must be an exact match. Wildcards are only considered special characters for ports when you enable [.label]#Allow wildcard ports in redirection URIs.

    OpenID Connect clients require redirection URIs.

    Scope(s)

    Specify scopes that are to be presented to the resource owner when the resource owner is asked to authorize client access to protected resources.

    The openid scope is required for OpenID Connect clients. It indicates that the client is making an OpenID Connect request to the authorization server.

    Scopes can be entered as simple strings, such as openid, read, email, profile, or as a pipe-separated string in the format: scope|locale|localized description. For example, read|en|Permission to view email messages.

    Locale strings have the format: language_country_variant. For example, en, en_GB, or en_US_WIN. If you omit the locale and pipe, AM displays the localized description to users with undefined locales. If the localized description is omitted, nothing is displayed to all users. For example, a scope of read| would allow the client to use the read scope but would not display it to the user when requested.

    AM reserves special scopes to let resource servers introspect tokens issued to other clients. For more information, refer to Special Scopes.

    For more information about scopes and default scopes, and how AM uses them, refer to OAuth 2.0 scopes.

    Default Scope(s)

    Scopes that AM uses when the client does not request any during a grant flow.

    Specify scopes in scope or scope|locale|localized description format.

    Scopes defined in this property take the same format as those defined in Scope(s).

    For more information about scopes and default scopes, and how AM uses them, refer to OAuth 2.0 scopes.

    Client Name

    Specify a human-readable name for the client.

    Authorization Code Lifetime (seconds)

    Specify the time in seconds for an authorization code to be valid. If this field is set to zero, the authorization code lifetime of the OAuth2 provider is used.

    Default: 0

    Refresh Token Lifetime (seconds)

    Specify the time in seconds for a refresh token to be valid. If this field is set to zero, the refresh token lifetime of the OAuth2 provider is used. If the field is set to -1, the token will never expire.

    Default: 0

    Access Token Lifetime (seconds)

    Specify the time in seconds for an access token to be valid. If this field is set to zero, the access token lifetime of the OAuth2 provider is used.

    Default: 0

    Advanced
    Token Exchange Auth Level

    Specify the authentication level that will be set for tokens created as a result of Token exchange. when the subject token does not have an authentication level to begin with. For example, when exchanging an ID token for an access token.

    Default: 0

    Display name

    Specify a client name to display to the resource owner when the resource owner is asked to authorize client access to protected resources. Valid formats include name or locale|localized name .

    The Display name can be entered as a single string or as a pipe-separated string for locale and localized name, for example, en|My Example Company.

    Locale strings have the format: language_country_variant. For example, en, en_GB, or en_US_WIN. If the locale is omitted, the name is displayed to all users having undefined locales.

    Display description

    Specify a client description to display to the resource owner when the resource owner is asked to authorize client access to protected resources. Valid formats include description or locale|localized description.

    The Display description can be entered as a single string or as a pipe-separated string for locale and localized name, for example, en|The company intranet is requesting the following access permission.

    Locale strings have the format: language_country_variant. For example, en, en_GB, or en_US_WIN. If the locale is omitted, the name is displayed to all users having undefined locales.

    JavaScript Origins

    The origin URLs allowed by the client to make cross-origin resource sharing (CORS) requests to AM.

    For example, you might add the URL of a resource server being protected by an app that uses the ForgeRock SDKs, so that it can access the OAuth 2.0 endpoints from a different domain than AM.

    This property does not support using a non-standard header. To use a custom header, you must create a new CORS configuration.

    Wildcards are not supported; each value should be an exact match for the origin of the CORS request.

    The global CORS service collects the value of this property from each OAuth 2.0 client, and combines it with its own configuration.

    Ensure that customers allowlist all headers for CORS and OAuth 2.0 client integration with AM.

    For more information, refer to Configure CORS support.

    Request uris

    Specify request_uri values that a dynamic client would pre-register.

    URIs must be pre-registered in this field before the client can request them in the request_uri parameter.

    Grant Types

    Specify the set of OAuth 2.0 grant flows allowed for this client. The following flows are available:

    • Authorization Code

    • Back Channel Request

    • Implicit

    • Resource Owner Password Credentials

    • Client Credentials

    • Refresh Token

    • UMA

    • Device Code

    • SAML2

    • Token Exchange

    Default: Authorization Code. When registering clients dynamically, if no grant types are specified in the registration request, then the default Authorization Code grant type is assumed, and configured in the client. Any grant types selected in a client must also be enabled in the OAuth 2.0 provider service. Refer to OAuth2 Provider.

    Response Types

    Specify the response types that the client uses. The response type value specifies the flow that determine how the ID token and access token are returned to the client. For more information, refer to OAuth 2.0 Multiple Response Type Encoding Practices.

    Configure this field only if the client uses OAuth 2.0 / OpenID Connect grant flows that interact with the /oauth2/authorize endpoint.

    The following response types are available:

    • code. Specifies that the client requests an authorization code during the Authorization code grant flow for OAuth 2.0 and OpenID Connect.

      This response type also applies to the Authorization Code grant with PKCE flows.

    • token. Specifies that the client requests an access token during the Implicit grant flow.

    • id_token. Specifies that the client requests an ID token during the OpenID Connect Implicit grant flow.

    • code token. Specifies that the client requests an access token and an authorization code during the OpenID Connect Hybrid grant flow.

    • code id_token. Specifies that the client requests an authorization code and an ID token during the OpenID Connect Hybrid grant flow.

    • code token id_token. Specifies that the client application requests an authorization code, an access token, and an ID token, during the OpenID Connect Hybrid grant flow.

    • token id_token. Specifies that the client requests an access token and an ID token during the OpenID Connect Implicit grant flow.

    Contacts

    Specify the email addresses of users who administer the client.

    Token Endpoint Authentication Method

    Specify the authentication method with which a client authenticates to AM (as an authorization server) at the token endpoint. The authentication method applies to OIDC requests with scope openid.

    • client_secret_basic. Clients authenticate with AM (as an authorization server) using the HTTP Basic authentication scheme after receiving a client_secret value.

    • client_secret_post. Clients authenticate with AM (as an authorization server) by including the client credentials in the request body after receiving a client_secret value.

    • private_key_jwt. Clients sign a JSON web token (JWT) with a registered public key.

    • tls_client_auth. Clients use a CA-signed certificate for mutual TLS authentication.

    • self_signed_tls_client_auth. Clients use a self-signed certificate for mutual TLS authentication.

    For more information, refer to OAuth 2.0 client authentication, and Client Authentication in the OpenID Connect Core 1.0 incorporating errata set 1 specification.

    Sector Identifier URI

    The value of this field must be a URL (including the https scheme) that references a JSON file containing an array of redirect_uri values. AM uses the host component of this URL to compute pairwise subject identifiers.

    If you configure a single Post Logout Redirect URI, the Sector Identifier URI takes this value by default. If you configure several Post Logout Redirect URIs and specify a pairwise Subject Type, you must set a value for the Sector Identifier URI.

    Subject Type

    Specify the subject identifier type, a locally unique identifier that the client consumes. The subject type can be one of the following:

    • public. Provides the same sub (subject) value to all clients.

    • pairwise. Provides a different sub (subject) value to each client to prevent correlation between clients.

    If you specify a pairwise subject type, refer to Sector Identifier URI.
    Access Token

    Specify the registration_access_token value that you provide when registering the client, and then subsequently when reading or updating the client profile.

    Client URI

    Specify the URI containing further information about this client. The URI is displayed as a link in user-facing pages, such as consent pages.

    The URI can be made locale-specific by specifying a pipe-separated string in the format: URI|locale. For example, https://www.example.es:8443/aplicacion/informacion.html|es.

    Logo URI

    Specify the URI of a logo for the client. The logo is displayed in user-facing pages, such as consent pages.

    The logo can be made locale-specific by specifying a pipe-separated string in the format: URI|locale. For example, https://www.example.es:8443/aplicacion/imagen.png|es.

    Privacy Policy URI

    Specify the URI containing the client’s privacy policy documentation. The URI is displayed as a link in user-facing pages, such as consent pages.

    The URI can be made locale-specific by specifying a pipe-separated string in the format: URI|locale. For example, https://www.example.es:8443/aplicacion/legal.html|es.

    Terms of Service URI

    The URI that contains the client’s terms of service. The URI is displayed as a link in user-facing pages, such as consent pages.

    The URI can be made locale-specific by specifying a pipe-separated string in the format: URI|locale. For example, https://www.example.es:8443/aplicacion/terminos.html|es.

    Refresh Token Grace Period (seconds)

    The time, in seconds, that a refresh token can be reused, for this client. This grace period lets the client recover seamlessly, if the response from an original refresh token request is not received, because of a network problem or other transient issue. During the grace period, the refresh token can be reused multiple times, if the network problem persists. When the grace period ends, the refresh token is revoked.

    The refresh token grace period applies only to server-side tokens, in a one-to-one storage scheme.

    This property can take the following values:

    • 0 The client inherits the refresh token grace period set in the OAuth 2.0 provider configuration. This is the default setting.

    • -1 There is no refresh token grace period for this client.

    • Any positive integer up to the maximum—​this value overrides the grace period set in the OAuth 2.0 provider configuration.

    Having a long grace period poses a security risk. You should therefore keep the grace period as small as possible. By default, the grace period cannot exceed 120 seconds. You can override this default maximum by setting the org.forgerock.openam.oauth2.client.graceperiod.disabled advanced server property. Note, however, that exceeding the default maximum of 120 seconds is not recommended.
    Implied Consent

    Enable the implied consent feature. When enabled, the resource owner will not be asked for consent during authorization flows. The OAuth2 Provider must also be configured to allow clients to skip consent.

    OAuth 2.0 Mix-Up Mitigation enabled

    Enable OAuth 2.0 mix-up mitigation on the authorization server side.

    Enable this setting only if this OAuth 2.0 client supports the OAuth 2.0 Mix-Up Mitigation draft, otherwise AM will fail to validate access token requests received from this client.

    Require Pushed Authorization Requests

    If enabled, the client must use the PAR endpoint to initiate authorization requests.

    Note that, even if this value is set to false, the authorization server may be configured to enforce PAR for all clients.

    OpenID Connect
    Claim(s)

    Specify one or more claim name translations that will override those specified for the authentication session. Claims are values that are presented to the user to inform them what data is being made available to the client.

    Claims can be in entered as simple strings, such as name, email, profile, or sub, or as a pipe-separated string in the format: scope|locale|localized description. For example, name|en|Full name of user.

    Locale strings have the format: language_country_variant. For example, en, en_GB, or en_US_WIN. If you omit the locale and pipe, AM displays the localized description to users with undefined locales. If you omit the localized description, AM displays nothing to all users. For example, a claim of name| lets the client use the name claim but doesn’t display it to the user when requested.

    If you don’t specify a value here, the value is computed from the OAuth 2.0 provider.

    Post Logout Redirect URIs

    Specify one or more allowable URIs to which AM can redirect the user-agent after the client logout process.

    Client Session URI

    Specify the relying party (client) URI to which the OpenID Connect Provider sends session changed notification messages using the HTML 5 postMessage API.

    Default Max Age

    Specify the maximum time in seconds that a user can be authenticated. If the user last authenticated earlier than this value, the user must reauthenticate. The request parameter max_age overrides this setting, if specified.

    Minimum value: 0. A value of 0 forces the user to reauthenticate rather than use an existing session that might have been set in their browser by another client.

    Default: 600

    Default Max Age Enabled

    Enable the default max age feature.

    Default ACR values

    Default Authentication Context Class Reference values.

    Specify strings that will be requested as Voluntary Claims by default in all incoming requests.

    Values specified in the acr_values request parameter or an individual acr claim request override these default values.

    OpenID Connect JWT Token Lifetime (seconds)

    Specify the time in seconds for a JWT to be valid. If this field is set to zero, the JWT token lifetime of the OAuth2 provider is used.

    Default: 0

    Backchannel Logout URL

    Specify the URL to where AM will send the logout token during backchannel logout.

    This URL can use the http or the https scheme, and may contain a port, a path, or query parameters, depending on the implementation of the relying party. For example, https://my-rp.example.com:443/logout.

    For more information, refer to Backchannel logout.

    Backchannel Logout Session Required

    Specify whether to add the session ID (sid) to the logout token. The session ID identifies the relying party’s session with the provider.

    For more information, refer to Backchannel logout.

    Signing and Encryption

    AM returns an error if the administrator tries to save a client profile configuration containing an unsupported signing or encryption algorithm on a client.

    For example, upon saving the configuration, AM will return an error if there is a typo on an algorithm, or a symmetric signing or encryption algorithm is configured on a public client: these algorithms are derived from the client’s secret, which public clients do not have.

    Clients registering dynamically must also send supported algorithms as part of their configuration, or AM will reject the registration request.

    Different features support different algorithms. Refer to the documentation or the UI for more information.

    Json Web Key URI

    Specify the URI that contains the client’s public keys in JSON web key format.

    When the client authenticates to AM using the private_key_jwt method, AM checks this field to find the public key to validate the JWT.

    JWKs URI content cache timeout in ms

    Specify the amount of time, in milliseconds, that the content of the JWKs' URI is cached for before being refreshed. Caching the content avoids fetching it for every token encryption or validation.

    Default: 3600000

    JWKs URI content cache miss cache time

    Specify the amount of time, in milliseconds, that AM waits before fetching the URI’s content again when a key ID (kid) is not in the JWK set already cached.

    For example, if a request comes in with a kid that is not in the cached JWKs, AM checks the value of JWKs' URI content cache miss cache time. If the amount of time specified in this property has already passed since the last time AM fetched the JWKs, AM fetches them again. Otherwise, the request is rejected.

    Use this property as a rate limit to prevent denial-of-service attacks against the URI.

    Default: 60000

    Token Endpoint Authentication Signing Algorithm

    Specify the JWS algorithm that must be used for signing JWTs used to authenticate the client at the Token Endpoint.

    JWTs that are not signed with the selected algorithm in token requests from the client using the private_key_jwt or client_secret_jwt authentication methods will be rejected.

    Default: RS256

    Json Web Key

    Raw JSON web key value containing the client’s public keys.

    ID Token Signing Algorithm

    Specify the signing algorithm that the ID token must be signed with.

    Enable ID Token Encryption

    Enable ID token encryption using the specified ID token encryption algorithm.

    ID Token Encryption Algorithm

    Specify the algorithm that the ID token must be encrypted with.

    Default value: RSA1_5 (RSAES-PKCS1-V1_5).

    ID Token Encryption Method

    Specify the method that the ID token must be encrypted with.

    Default value: A128CBC-HS256.

    Authorization Response JWT Signing Algorithm

    Specify the algorithm to be used to sign an authorization response JWT.

    If configured, it must match one of the values set in the Authorization Response Signing Algorithms Supported property of the OAuth2 provider service.

    Default value: RS256.

    Authorization Response JWT Encryption Algorithm

    Specify the algorithm to be used to encrypt an authorization response JWT.

    To disable encryption of the authorization response JWT, ensure this property is not set.

    To enable encryption, set the property to a valid value. This must match one of the values set in the Authorization Response Encryption Algorithms Supported property of the OAuth2 provider service.

    Authorization Response JWT Encryption Method

    Specify the encryption method to be used to secure an authorization response JWT.

    If configured, it must match one of the values set in the Authorization Response Encryption Methods Supported property of the OAuth2 provider service.

    Default value: A128CBC-HS256, when Authorization Response JWT Encryption Algorithm is set.

    Client ID Token Public Encryption Key

    Specify the Base64-encoded public key for encrypting ID tokens.

    Client JWT Bearer Public Key Certificate

    Specify the base64-encoded X509 certificate in PEM format. The certificate is never used during the signing process, but is used to obtain the client’s JWT bearer public key. The client uses the private key to sign client authentication and access token request JWTs, while AM uses the public key for verification.

    The following is an example of the certificate:

    -----BEGIN CERTIFICATE-----
    MIIDETCCAfmgAwIBAgIEU8SXLj.....
    -----END CERTIFICATE-----

    You can generate a new key pair alias by using the Java keytool command. Follow the steps in To Create Key Aliases in an Existing Keystore.

    For example:

    $ keytool \
    -list \
    -alias myAlias \
    -rfc \
    -storetype JCEKS \
    -keystore myKeystore.jceks \
    -keypass myKeypass \
    -storepass myStorepass
    Alias name: myAlias
    Creation date: Oct 27, 2020
    Entry type: PrivateKeyEntry
    Certificate chain length: 1
    Certificate[1]:
    -----BEGIN CERTIFICATE-----
    MIIDETCCAfmgAwIBAgIEU8SXLj…​
    -----END CERTIFICATE-----

    For more information, refer to JWT profile.

    mTLS Self-Signed Certificate

    Specify the base64-encoded X.509 certificate in PEM format that clients can use to authenticate to the access_token endpoint during mutual TLS authentication.

    Only applies when clients use self-signed certificates to authenticate.

    For more information, refer to Mutual TLS.

    mTLS Subject DN

    Specify the distinguished name that must exactly match the subject field in the client certificate used for mutual TLS authentication. For example, CN=myOauth2Client.

    Only applies when clients use CA-signed certificates to authenticate.

    For more information, refer to Mutual TLS.

    Use Certificate-Bound Access Tokens

    Specify that access tokens issued to this client should be bound to the X.509 certificate that it uses to authenticate to the access_token endpoint.

    If enabled, AM adds a confirmation key labelled x5t#S256 to all access tokens. The confirmation key contains the SHA-256 hash of the client’s certificate.

    For more information, refer to Certificate-bound proof-of-possession.

    Public key selector

    Select the format of the public keys for JWT profile client authentication, ID token encryption, and mTLS self-signed certificate authentication. Valid formats are:

    • JWKs_URI

      Configure a URI that exposes the client public keys in the Json Web Key URI field, and ensure the following related properties have sensible values for your environment:

      • JWKs URI content cache timeout in ms

      • JWKs URI content cache miss cache time

    • JWKs

      Enter a JWK Set containing one or more keys in the Json Web Key field. For example:

      {
          "keys": [
              {
                  "kty": "RSA",
                  "n": "..."
              }
          ]
      }
    • X509

      Enter a key object or a single certificate in one of the following fields, depending on the feature you are configuring:

      • (ID token encryption) Client ID Token Public Encryption Key. Requires an RSA public key object in X.509 PEM format. For example:

        -----BEGIN PUBLIC KEY-----
        ......
        -----END PUBLIC KEY-----
      • (JWT client authentication) Client JWT Bearer Public Key. Requires an X.509 certificate in PEM format. For example:

        -----BEGIN CERTIFICATE-----
        .....
        -----END CERTIFICATE-----
      • (mTLS client authentication) mTLS Self-Signed Certificate. Requires an X.509 certificate in PEM format. For example:

        -----BEGIN CERTIFICATE-----
        .....
        -----END CERTIFICATE-----

    Default: JWKs_URI

    User info response format.

    Specify the output format from the UserInfo endpoint.

    Default: User info JSON response format.

    The supported output formats are as follows:

    • User info JSON response format.

    • User info encrypted JWT response format.

    • User info signed JWT response format.

    • User info signed then encrypted response format.

    For more information on the output format of the UserInfo Response, refer to Successful UserInfo Response in the [ref]_OpenID Connect Core 1.0 incorporating errata set 1 _ specification.

    User info signed response algorithm

    Specify the JSON Web Signature (JWS) algorithm for signing UserInfo Responses. If specified, the response will be JSON Web Token (JWT) serialized, and signed using JWS.

    The default, if omitted, is for the UserInfo Response to return the claims as a UTF-8-encoded JSON object using the application/json content type.

    User info encrypted response algorithm

    Specify the JSON Web Encryption (JWE) algorithm for encrypting UserInfo Responses.

    If both signing and encryption are requested, the response will be signed then encrypted, with the result being a nested JWT.

    The default, if omitted, is that no encryption is performed.

    User info encrypted response encryption algorithm

    Specify the JWE encryption method for encrypting UserInfo Responses. If specified, you must also specify an encryption algorithm in the User info encrypted response algorithm property.

    AM supports the following encryption methods:

    • A128GCM, A192GCM, and A256GCM - AES in Galois Counter Mode (GCM) authenticated encryption mode.

    • A128CBC-HS256, A192CBC-HS384, and A256CBC-HS512 - AES encryption in CBC mode, with HMAC-SHA-2 for integrity.

    Default: A128CBC-HS256

    Request parameter signing algorithm

    Specify the JWS algorithm for signing the request parameter.

    Must match one of the values configured in the Request parameter Signing Algorithms supported property of the OAuth2 Provider service.

    Request parameter encryption algorithm

    Specify the algorithm for encrypting the request parameter.

    Must match one of the values configured in the Request parameter Encryption Algorithms supported property of the OAuth2 Provider service.

    Request parameter encryption method

    Specify the method for encrypting the request parameter.

    Must match one of the values configured in the Request parameter Encryption Methods supported property of the OAuth2 Provider service.

    Default: A128CBC-HS256

    Token introspection response format

    Specifies the format of the token introspection response. The possible values for this property are:

    • JSON response format

    • Signed JWT response format

    • Signed then encrypted JWT response format

      Even if the client has configured the response to be JSON-formatted, it can request a signed JWT by adding the "Accept: application/jwt" header to the request. However, when a client that is configured to use either of the JWT-formatted responses requests a JSON response, AM returns an error. For an example, refer to /oauth2/introspect.

      For related signing and encryption algorithms, refer to the following properties:

    • Token introspection response signing algorithm

    • Token introspection response encryption algorithm

    • Token introspection response encryption method

    Default: JSON response format

    Token introspection response signing algorithm

    Specifies the algorithm used to sign the token introspection response when it is formatted as a signed JWT.

    Must match a value configured in the Token Introspection Response Signing Algorithms Supported property of the OAuth2 Provider service.

    AM supports the following signing algorithms:

    • HS256 - HMAC with SHA-256.

    • HS384 - HMAC with SHA-384.

    • HS512 - HMAC with SHA-512.

    • ES256 - ECDSA with SHA-256 and NIST standard P-256 elliptic curve.

    • ES384 - ECDSA with SHA-384 and NIST standard P-384 elliptic curve.

    • ES512 - ECDSA with SHA-512 and NIST standard P-521 elliptic curve.

    • RS256 - RSASSA-PKCS-v1_5 using SHA-256.

    • RS384 - RSASSA-PKCS-v1_5 using SHA-384.

    • RS512 - RSASSA-PKCS-v1_5 using SHA-512.

    • EdDSA - EdDSA with SHA-512.

      The signing key used depends on the algorithm chosen. The relevant secret IDs and the default signing key aliases are shown in the table below:

      The following table shows the secret ID mapping used to sign OpenID Connect ID tokens and backchannel logout tokens:

      Secret ID Default Alias Algorithms(1)

      am.services.oauth2.oidc.signing.ES256

      es256test

      ES256

      am.services.oauth2.oidc.signing.ES384

      es384test

      ES384

      am.services.oauth2.oidc.signing.ES512

      es512test

      ES512

      am.services.oauth2.oidc.signing.RSA

      rsajwtsigningkey

      PS256
      PS384
      PS512
      RS256
      RS384
      RS512

      am.services.oauth2.oidc.signing.EDDSA

      EdDSA with SHA-512

      (1) The following applies to confidential clients only:

      If you select an HMAC algorithm for signing ID tokens (HS256, HS384, or HS512), the Client Secret property value in the OAuth 2.0 Client is used as the HMAC secret instead of an entry from the secret stores.

      Since the HMAC secret is shared between AM and the client, a malicious user compromising the client could potentially create tokens that AM would trust. Therefore, to protect against misuse, AM also signs the token using a non-shared signing key configured in the am.services.oauth2.jwt.authenticity.signing secret ID.

    Default: RS256

    Token introspection response encryption algorithm

    Specifies the algorithm used to encrypt the token introspection response when it is formatted as a signed then encrypted JWT.

    Must match a value configured in the Token Introspection Response Encryption Algorithms Supported property of the OAuth2 Provider service.

    AM supports the following encryption algorithms:

    • A128KW - AES Key Wrapping with 128-bit key derived from the client secret.

    • A192KW - AES Key Wrapping with 192-bit key derived from the client secret.

    • A256KW - AES Key Wrapping with 256-bit key derived from the client secret.

    • RSA-OAEP - RSA with Optimal Asymmetric Encryption Padding (OAEP) with SHA-1 and MGF-1.

    • RSA-OAEP-256 - RSA with OAEP with SHA-256 and MGF-1.

    • RSA1_5 - RSA with PKCS#1 v1.5 padding.

    • dir - Direct encryption with AES using the hashed client secret.

    • ECDH-ES - Elliptic Curve Diffie-Hellman

    • ECDH-ES+A128KW - Elliptic Curve Diffie-Hellman + AES Key Wrapping with 128-bit key.

    • ECDH-ES+A192KW - Elliptic Curve Diffie-Hellman + AES Key Wrapping with 192-bit key.

    • ECDH-ES+A256KW - Elliptic Curve Diffie-Hellman + AES Key Wrapping with 256-bit key.

    The algorithms that are not specified as being derived from the client secret use the client’s public keys. For more information, refer to the Public key selector property.

    + Default: RSA-OAEP-256

    Token introspection response encryption method

    Specifies the encryption method used to encrypt the token introspection response when it is formatted as a signed then encrypted JWT.

    Must match a value configured in the Token Introspection Response Encryption Methods Supported property of the OAuth2 Provider service.

    AM supports the following encryption methods:

    • A128GCM, A192GCM, and A256GCM - AES in Galois Counter Mode (GCM) authenticated encryption mode.

    • A128CBC-HS256, A192CBC-HS384, and A256CBC-HS512 - AES encryption in CBC mode, with HMAC-SHA-2 for integrity.

    Default: A128CBC-HS256

    UMA
    Client Redirection URIs
    This property is for future use, and not currently active.

    Specify one or more allowable URIs to which the client can be redirected after the UMA claims collection process. The URIs must not contain a fragment (#).

    If multiple URIs are registered, the client MUST specify the redirection URI to be redirected to following approval.

    OAuth2 Provider Overrides
    Enable OAuth2 Provider Overrides

    Enable the OAuth 2.0 provider configuration to be overridden by the settings in this section.

    When enabled, these client-level attributes override the corresponding attributes set by the OAuth 2.0 provider service or group.

    The overriding attributes will only apply if this setting is enabled.

    Issue Refresh Tokens

    Whether to issue a refresh token when returning an access token.

    Issue Refresh Tokens on Refreshing Access Tokens

    Whether to issue a refresh token when refreshing an access token.

    Use Policy Engine for Scope decisions

    With this setting enabled, the policy engine is consulted for each scope value that is requested.

    Scope decisions based on the policy engine are determined in the following way:

    • If a policy returns an action of GRANT=true, the scope is consented automatically, and the user is not consulted in a user-interaction flow.

    • If a policy returns an action of GRANT=false, the scope is not added to any resulting token, and AM does not display it to the user in a user-interaction flow.

    • If no policy returns a value for the GRANT action:

      • For user-facing grant types, such as the authorization or device code flows, the user is asked for consent or saved consent is used.

      • For grant types that are not user-facing, such as those using password or client credentials, the scope is not added to any resulting token.

    Scopes Policy Set

    The policy set that defines the context in which policy evaluations occur when Use Policy Engine for Scope decisions is enabled. Leave blank to use the default oauth2Scopes policy set.

    Access Token Modification Plugin Type

    This setting determines the type of plugin that is invoked:

    • SCRIPTED to run the script defined in Access Token Modification Script.

    • JAVA to run the class defined in Access Token Modifier Plugin Implementation Class.

    • PROVIDER to use the access token modification plugin settings configured on the OAuth2 provider.

    Default value: PROVIDER

    Access Token Modification Script

    This script is run when issuing an access token. The script lets you modify the token, for example, by altering the data fields, before it is persisted or returned to the client.

    The script is run if Access Token Modification Plugin Type is set to SCRIPTED.

    Default value: --- Select a script ---

    Access Token Modification Plugin Implementation Class

    The Java class that provides the custom implementation for the access token modifier plugin interface, org.forgerock.oauth2.core.plugins.AccessTokenModifier. This class is invoked when Access Token Modification Plugin Type is set to JAVA.

    Default value: [Empty]

    OAuth2 Access Token May Act Script

    The script that is executed when issuing an access token explicitly to modify the may_act claim placed on the token.

    Refer to Token exchange.

    Default value: --- Select a script ---

    OIDC ID Token May Act Script

    The script that is executed when issuing an OpenID Connect ID token explicitly to modify the may_act claim placed on the token.

    Default value: --- Select a script ---

    OIDC Claims Plugin Type

    This setting can have the following possible values:

    • SCRIPTED to run the script defined in OIDC Claims Script.

    • JAVA to run the class defined in OIDC Claims Plugin Implementation Class.

    • PROVIDER to use the OIDC claims plugin settings configured on the OAuth2 provider.

    Default value: PROVIDER

    OIDC Claims Script

    This script is run when issuing an ID token or during a request to the /userinfo OpenID Connect endpoint. Use this script to retrieve claim values based on an issued access token.

    The script is run if OIDC Claims Plugin Type is set to SCRIPTED.

    Default value: --- Select a script ---

    OIDC Claims Plugin Implementation Class

    The Java class that provides the custom implementation for the OIDC claims plugin interface, org.forgerock.oauth2.core.plugins.UserInfoClaimsPlugin. This class is invoked when OIDC Claims Plugin Type is set to JAVA.

    Default value: [Empty]

    Custom Login URL Template

    Supports Freemarker syntax, with the following variables:

    Variable

    Description

    gotoUrl

    The URL to redirect to after login.

    acrValues

    The Authentication Context Class Reference (acr) values for the authorization request.

    realm

    The AM realm the authorization request was made on.

    module

    The name of the AM authentication module requested to perform resource owner authentication.

    service

    The name of the AM authentication chain requested to perform resource owner authentication.

    locale

    A space-separated list of locales, ordered by preference.

    The following example template redirects users to a non-AM front end to handle login, which will then redirect back to the /oauth2/authorize endpoint with any required parameters:

    http://mylogin.com/login?goto=${goto}<#if acrValues??>&acr_values=${acrValues}</#if><#if realm??>&realm=${realm}</#if><#if module??>&module=${module}</#if><#if service??>&service=${service}</#if><#if locale??>&locale=${locale}</#if>

    The default AM login page is constructed using the base URL source service.
    Use Client-Side Access & Refresh Tokens

    When enabled, AM issues client-side access and refresh tokens that can be inspected by resource servers.

    Encrypt Client-Side Tokens

    Whether client-side access and refresh tokens should be encrypted.

    Enabling token encryption will disable token signing as encryption is performed using direct symmetric encryption.

    Allow Clients to Skip Consent

    If enabled, clients can be configured so that the resource owner will not be asked for consent during authorization flows.

    Enable Remote Consent

    Enables consent to be gathered by a separate service.

    Remote Consent Service ID

    The ID of an existing remote consent service agent.

    Scope Evaluation Plugin Type

    This setting can have the following possible values:

    • SCRIPTED to run the script defined in Scope Evaluation Script.

    • JAVA to run the class defined in Scope Evaluation Plugin Implementation Class.

    • PROVIDER to use the scope evaluation plugin settings configured on the OAuth2 provider.

    Default value: PROVIDER

    Scope Evaluation Script

    This script retrieves and evaluates the scope information for an OAuth2 access token.

    The script lets you populate the scopes with profile attribute values. For example, if one of the scopes is mail, AM sets mail to the resource owner’s email address in the token information returned.

    Default value: --- Select a script ---

    Scope Evaluation Plugin Implementation Class

    The Java class that provides the custom implementation for the evaluate scope plugin interface: org.forgerock.oauth2.core.plugins.ScopeEvaluator.

    Default value: org.forgerock.oauth2.core.plugins.registry.DefaultScopeEvaluator

    Scope Validation Plugin Type

    This setting can have the following possible values:

    • SCRIPTED to run the script defined in Scope Validation Script.

    • JAVA to run the class defined in Scope Validation Plugin Implementation Class.

    • PROVIDER to use the scope validation plugin settings configured on the OAuth2 provider.

    Default value: PROVIDER

    Scope Validation Script

    This script validates and customizes the set of requested scopes for authorize, access token, refresh token, and back channel authorize requests.

    Default value: --- Select a script ---

    Scope Validation Plugin Implementation Class

    The Java class that provides the custom implementation for the evaluate scope plugin interface: org.forgerock.oauth2.core.plugins.ScopeValidator.

    Default value: org.forgerock.oauth2.core.plugins.registry.DefaultScopeValidator

    Authorize Endpoint Data Provider Plugin Type

    This setting can have the following possible values:

    • SCRIPTED to run the script defined in Authorize Endpoint Data Provider Script.

    • JAVA to run the class defined in Authorize Endpoint Data Provider Plugin Implementation Class.

    • PROVIDER to use the Authorize Endpoint Data Provider plugin settings configured on the OAuth2 provider.

    Default value: PROVIDER

    Authorize Endpoint Data Provider Script

    Use this script to retrieve additional data from an authorization request, such as data from the user’s session or from an external service.

    Default value: --- Select a script ---

    Authorize Endpoint Data Provider Plugin Implementation Class

    The Java class that provides the custom implementation for the evaluate scope plugin interface: org.forgerock.oauth2.core.plugins.AuthorizeEndpointDataProvider.

    Default value: org.forgerock.oauth2.core.plugins.registry.DefaultEndpointDataProvider

    Overrideable Id_Token Claims

    List of claims in the ID token that can be overridden in the OIDC claims script. These should be the subset of the core OpenID Connect claims; for example aud or azp.

    Some client configuration will depend on the configuration of the authorization server, and the type of client you are registering.

    Configuration tips

    Some basic points you must decide on are:

    • Is the client public or confidential?

    • What is its redirection URI?

    • Which scopes does it need?

    • What’s the name this client will show as in the UI pages?

    • Which grant types the client can use to request tokens?

    • Which tokens can this client request?

    • In the case of an OpenID Connect client:

      • If the client is confidential, which authentication method will it use?

      • Which claims does the client need?

  4. When finished, save your work.

Shared application settings

To define shared settings for multiple client application profiles, you have these alternatives:

  • Configure default settings for all clients in the realm.

    Client applications inherit their default settings from the OAuth 2.0 provider service. Find the settings in the AM admin UI under Realms > Realm Name > Services > OAuth2 Provider.

  • Create an OAuth 2.0 client profile group.

    Client applications that belong to the group can inherit its settings.

Create group settings

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

  2. On the Groups tab, click + Add Group, and click Create.

  3. Adjust the configuration as needed, saving changes on each tab.

  4. Assign clients to the group.

Inherit group settings

  1. In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID.

  2. On the Core tab, select the Group in the drop-down.

  3. Save your work.

    Selecting a group refreshes the client configuration, discarding any other unsaved settings.

    Inheritance icons appear next to inherited group settings. Not all properties can inherit their value; for example, the Client secret property is specific to each client application.

    Set a client application’s group to inherit settings.
    Figure 9. Inheriting group settings
  4. Inherit settings by clicking their inheritance icons .

    The icon changes to , indicating the setting is inherited.

  5. Save your work.

Configuration changes have the following effects:

  • When you change inherited settings in the group, the client applications get them automatically.

  • When you change a client application’s Group, locked settings inherit from the new group.

  • When you remove or delete a group, AM writes inherited settings to the client profile, which you can edit independently.

OAuth 2.0 client authentication

OAuth 2.0 client applications send their authentication credentials using one of the following mechanisms:

Authentication depends on the Client type defined in the AM admin UI under Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Core:

Confidential clients

These applications include websites and services that make secure connections to AM.

They can protect their client secret or JSON Web Token (JWT).

You configure the authentication method for a confidential client in the AM admin UI under Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Advanced as the Token Endpoint Authentication Method.

When a client authenticates with form parameters, the server can store POST data on the user-agent in an OAUTH_REQUEST_ATTRIBUTES cookie. AM uses the cookie to continue the authentication process across redirects. It marks the cookie for deletion on the next successful OAuth 2.0 authorization.

Public clients

These are single-page applications and applications running on devices.

They cannot protect secrets.

Public clients identify themselves by client ID, but do not fully authenticate.

Public OIDC clients must specify none as their authentication method.

Authorization header (HTTP Basic)

This is the default authentication method for AM confidential clients.

The OAuth 2.0 client authenticates by sending the credentials in an HTTP Basic authentication (Authorization) header.

The value is client_id:client_secret, first URL encoded, then base64 encoded. For example, myClient:forgerock encodes to bXlDbGllbnQ6Zm9yZ2Vyb2Nr:

$ curl \
--request POST \
--header "Authorization: Basic bXlDbGllbnQ6Zm9yZ2Vyb2Nr" \
…​

To confirm this authentication method for a confidential OAuth 2.0 client, check the client profile in the AM admin UI:

  1. Go to Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Advanced.

  2. Verify the Token Endpoint Authentication Method is client_secret_basic and save your work.

Make sure all connections to AM use HTTPS to protect the secret.

URL encode the client_id and client_secret before base64 encoding the client_id:client_secret value.

For example, a client with ID example.com and secret s=cr%t has characters you must URL encode in the secret:

  • The URL-encoded ID remains example.com.

  • The URL-encoded secret is s%3Dcr%25t.

  • The credentials are example.com:s%3Dcr%25t before base64 encoding.

  • The base64-encoded form is ZXhhbXBsZS5jb206cyUzRGNyJTI1dA==.

  • The final HTTP Basic header is Authorization: Basic ZXhhbXBsZS5jb206cyUzRGNyJTI1dA==

Form parameters (HTTP POST)

The OAuth 2.0 client authenticates by sending client_id and client_secret form parameters in an HTTP POST request:

$ curl \
--request POST \
--data "client_id=myClient" \
--data "client_secret=forgerock" \
…​

To use this authentication method for a confidential OAuth 2.0 client, edit the client profile in the AM admin UI:

  1. Go to Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Advanced.

  2. Set the Token Endpoint Authentication Method to client_secret_post and save your work.

Make sure all connections to AM use HTTPS to protect the secret.

JWT profile

The OAuth 2.0 client authenticates by sending a signed JSON Web Token (JWT) Bearer Token as described in RFC 7523, JWT Profile for OAuth 2.0 Client Authentication and Authorization Grants:

$ curl \
--request POST \
--data "client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer" \
--data "client_assertion=the-signed-JWT" \
…​

Client configuration

The JWT issuer must digitally sign the JWT or apply a Message Authentication Code (MAC). When the client is the JWT issuer, it can sign the JWT with a private key.

To use this authentication method for a confidential OAuth 2.0 client, edit the client profile in the AM admin UI:

  1. Go to Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Advanced.

  2. Add Grant Types: JWT Bearer.

  3. Set Token Endpoint Authentication Method to private_key_jwt.

  4. Save your work before switching tabs.

  5. Update additional settings depending on the mechanism for signing the JWT.

    AM must validate the JWT to authenticate the client.

    Mechanism Settings

    Certificate-based

    The client protects the JWT with public-private key cryptography with the public key in a digital certificate.

    On the Signing and Encryption tab:

    1. Set Client JWT Bearer Public Key to the PEM-format value of the JWT issuer’s public key, as in the following example:

      -----BEGIN CERTIFICATE-----
      MIIDETCCAfmgAwIBAgIEU8SXLjANBgkqhkiG9w0BAQsFADA5MRswGQYDVQQKExJvcGVuYW0uZXhh
      bXBsZS5jb20xGjAYBgNVBAMTEWp3dC1iZWFyZXItY2xpZW50MB4XDTE0MTAyNzExNTY1NloXDTI0
      ...
      TeGSgcqEAd6XlGXY1+M/yIeouUTi0F1bk1rNlqJvd57Xb4CEq17tVbGBm0hkECM8
      -----END CERTIFICATE-----
    2. Set Public key selector to X509.

    A client can have only one public key.

    HMAC secret

    The client protects the JWT with a Hash-based Message Authentication Code (HMAC).

    On the Core tab, reset the client secret to the HMAC secret.

    The HMAC secret must contain at least 32 octets and sufficient entropy for a cryptographically strong key, as described in the Symmetric Key Entropy section of the OpenID Connect 1.0 specification.

    A client can have only one HMAC secret.

    JWK set in the client profile

    The client protects the JWT with public-private key cryptography with the public key in a JSON Web Key (JWK).

    On the Signing and Encryption tab:

    1. Set Public key selector to JWKs.

    2. Paste the JWK set into the Json Web Key field.

      The JWK set is similar to the following:

      {
        "keys": [
          {
            "alg": "RSA-OAEP-256",
            "kty": "RSA",
            "use": "sig",
            "kid": "RemA6Gw0...LzsJ5zG3E=",
            "n": "AL4kjz74rDo3VQ3Wx...nhch4qJRGt2QnCF7M0",
            "e": "AQAB"
          }
        ]
      }

      Enter a JWK set with multiple JWKs for certificate rotation.

    JWK set in a URI

    The client protects the JWT with public-private key cryptography with the public key in a JWK.

    On the Signing and Encryption tab:

    1. Set Public key selector to JWKs_URI.

    2. Paste the URI to the JWK set into the Json Web Key URI field.

  6. Save your work.

Make sure all connections to AM use HTTPS to protect any secrets, including the JWT.

The JWT profile flow

The following sequence diagram shows a JWT profile authentication flow:

JWT profile client authentication
Figure 10. JWT profile client authentication
  1. The client requests a JWT from the issuer.

    Clients can generate their own JWTs. They can also delegate the task to a separate service in the deployment.

    AM cannot generate JWTs for this purpose.

  2. The issuer returns a signed JWT to the client.

  3. The client POSTs the JWT and a client assertion type as parameters of an OAuth 2.0 request:

    • client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer

    • client_assertion=the-signed-JWT

  4. AM validates the JWT using the public key from the client profile.

  5. AM issues the response, such as an access token.

The JWT profile claims

The JWT Bearer Token must contain at least the following claims:

Claim Description

aud

The authorization server that is the intended audience of the JWT; must be the AM token endpoint, such as https://openam.example.com/openam/oauth2/realms/root/realms/alpha/access_token.

To specify additional audiences that will be permitted when verifying the JWT, set the Additional Audience Values property of the OAuth 2.0 provider.

exp

The expiration time.

This must be at most 30 minutes in the future. If not, AM returns a JWT expiration time is unreasonable error message.

iss

The unique identifier of the issuer that digitally signs the JWT:

  • The client_id if it generates its own JWT.

  • A third party if a separate service generates the JWT.

jti

A random, unique identifier for the JWT.

Required if the client requests the openid scope; otherwise optional.

sub

The principal who is the subject of the JWT; must be the client_id.

AM ignores keys specified in JWT headers, such as jku and jwe.

For additional details, refer to the section of RFC 7523 on JWT Format and Processing Requirements.

Sample JWT profile client

The AM code samples include a Java-based client to test the JWT token bearer flow.

Mutual TLS

Clients can authenticate to AM by using mutual TLS (mTLS) and X.509 certificates. The certificates are either self-signed or use public key infrastructure (PKI), as per version 12 of the draft OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens specification.

AM also supports the Certificate Bound Access Tokens part of the specification. For more information, see Certificate-bound proof-of-possession.

Mutual TLS using public key infrastructure

This method of authenticating OAuth 2.0 clients requires that the certificate presented by the client contains a subject-distinguished name that matches exactly a value specified in the client profile in AM.

The Certificate Authority specified in the chain must also be trusted by AM. You can configure secret mappings with secret ID am.services.oauth2.tls.client.cert.authentication to specify which certificate authorities AM trusts.

Configure AM for mutual TLS using public key infrastructure

Follow the steps in this procedure to configure AM to support mutual TLS using PKI.

  1. If you have not already done so, create an OAuth 2.0 client profile in AM.

    For more information, see Client application registration.

  2. Set up a secret store in the same realm as the OAuth 2.0 client.

    AM maintains the details of trusted certificate authorities in this secret store.

    You can use an existing secret store or create a new store as follows:

    • In the AM admin UI, go to Realms > Realm Name > Secret Stores, and click Add Secret Store.

    • Enter an ID for the secret store (for example, TrustStore), select the store type, complete the required fields, and click Create.

      You may need to configure the credentials for accessing the new store in one of the other configured secret stores. For more information on configuring secret stores, see Secrets, certificates, and keys.

  3. Import the certificates belonging to the certificate authorities you want the instance of AM to trust.

  4. Map the aliases of the imported certificates to the am.services.oauth2.tls.client.cert.authentication secret ID:

    • In the AM admin UI, go to Realms > Realm Name > Secret Stores > Store Name > Mappings, and click Add Mapping.

    • In the Secret ID field, select am.services.oauth2.tls.client.cert.authentication.

    • In the Aliases field, enter the aliases of the imported CA certificate to trust, and click the Add Alias (➕) button.

    • Repeat the previous step to add the aliases of all the CA certificates to trust, and click Create.

  5. Add the subject-distinguished name that must appear in the client certificate to be able to authenticate:

    • In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Agent Name > Signing and Encryption.

    • In the mTLS Subject DN field, enter the distinguished name that must exactly match the subject field in the client certificate. For example, CN=myOauth2Client.

      If this field is left empty, the default value that must be found in a CA-signed client certificate is CN=Client ID. For example, CN=myMTLSClient.

    • Save your changes.

  6. Configure the OAuth 2.0 provider to check whether the certificates presented by the authenticating clients have been revoked:

    • In the AM admin UI, go to Realms > Realm Name > Services > OAuth2 Provider > Advanced.

    • Enable Check TLS Certificate Revocation Status.

    • In the OCSP Responder URI field, enter the URI of the online certificate status protocol responder service. AM will use this service to check the certificates.

      If not specified, AM determines the appropriate URI from the certificate.

    • In the OCSP Responder Certificate field, enter the PEM-encoded certificate that AM will use to verify all OCSP responses.

      If not specified, AM determines the appropriate certificate from the trusted CA certificates configured in the am.services.oauth2.tls.client.cert.authentication secret ID.

AM is now configured to accept CA-signed client certificate for authentication. For information on how to present the certificates when authenticating, see Providing client certificates to AM.

Mutual TLS using self-signed X.509 certificates

This method of authenticating OAuth 2.0 clients requires that the self-signed X.509 certificate presented by the client matches exactly a certificate specified in the client profile in AM.

You can specify the expected self-signed X.509 certificate in the client profile using one of the following methods:

  1. JSON Web Key Set (JWKS)

    Specify the X.509 certificates in the X.509 Certificate Chain (x5c) attribute of the one or more JSON Web Keys specified in the set.

  2. JSON Web Key Set URI (JWKS_uri)

    AM periodically retrieves the JWKS from the specified URI, and uses the certificates provided in the X.509 Certificate Chain (x5c) attribute to verify the client certificate.

  3. X.509

    Add the content of the X.509 certificate as-is into the client profile.

    Unlike the other methods, only a single certificate can be specified using this method.

Configure AM for Mutual TLS using self-signed X.509 certificates

Follow the steps in this procedure to configure AM to support mutual TLS using self-signed certificates.

  1. If you have not already done so, create an OAuth 2.0 client profile in AM.

    For more information, see Client application registration.

  2. To provide the X.509 certificates the client will use to authenticate, go to Applications > OAuth 2.0 > Agent Name > Signing and Encryption, and then perform one of the following steps:

    1. To use a JSON Web Key Set (JWKS) to specify the certificates:

      • Set the Public key selector property to JWKs.

      • Enter the contents of the JWKS in the Json Web Key property.

    2. To use a JSON Web Key Set URI (JWKS_uri) to specify the certificates:

      • Set the Public key selector property to JWKs_uri.

      • Enter the JWKS URI in the Json Web Key URI property.

    3. To use the contents of an X.509 certificate:

      • Set the Public key selector property to X509.

      • In the mTLS Self-Signed Certificate field, enter the content of the X.509 certificate, which must be in PEM format.

        You can include or exclude the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- labels.

        OpenID Connect clients must also specify the authentication method they are using in their client profiles. See OIDC client authentication.

  3. Save your changes.

AM is now configured to accept self-signed client certificate for authentication. For information on how to present the certificates when authenticating, see Providing client certificates to AM.

Providing client certificates to AM

The client can provide its certificate to AM using either standard TLS client certificate authentication or trusted headers.

You must configure the web container in which AM runs to use TLS connections, and to request and accept client certificates.

Consult the documentation for your web container to determine the appropriate actions to take.

  1. Standard TLS client certificate authentication

    The client provides its certificates in the standard servlet client certificate attribute.

    This is the preferred method, as the web container will verify that the client authenticated the TLS session with the private key associated with the certificate.

    After configuring AM to accept client certificates, the client can authenticate to the OAuth 2.0 access_token endpoint using one of the X.509 certificates registered in the client.

    Any of the OAuth 2.0 grant flows that makes a call to the access_token endpoint can authenticate clients using X.509 certificates. The following example uses grant_type=client_credentials and attaches the client certificates to the request:

    $ curl \
    --request POST \
    --data "client_id=myClient" \
    --data "grant_type=client_credentials" \
    --data "scope=write" \
    --data "response_type=token" \
    --cert "myClientCertificate.pem" \
    --key "myClientCertificate.key.pem" \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"
    {
      "access_token": "sbQZuveFumUDV5R1vVBl6QAGNB8",
      "scope": "write",
      "token_type": "Bearer",
      "expires_in": 3599
    }
  2. Trusted headers

    AM receives the certificates in a configured, trusted HTTP header.

    This method is intended for cases where TLS is being terminated at a reverse proxy or load balancer, and therefore, the container in which AM runs is not directly able to authenticate the client.

    You must configure the proxy or load balancer to:

    1. Forward the certificate to AM in the trusted header.

      AM supports receiving certificates in the following formats:

      • Raw PEM-encoded.

      • PEM-encoded first, then URL-encoded, for compatibility with the NGINX $ssl_client_escaped_cert variable.

      • PEM-encoded first, URL-encoded next, and then included as a field in a multi-field trusted header, for compatibility with the Envoy x-forwarded-client-cert headers.

    To specify the format of the trusted header, go to Realms > Realm Name > Services > OAuth2 Provider > Advanced, and choose the appropriate value in the TLS Client Certificate Header Format drop-down list:

    • Use URLENCODED_PEM for raw PEM and NGINX-like URL-encoded formats.

    • Use X_FORWARDED_CLIENT_CERT for the Envoy-like format.

      1. Strip the trusted header from any incoming requests.

        This is because AM has no way of authenticating the contents of this header, and so would trust whatever is present.

        To specify the name of the trusted header, in the AM admin UI, go to Realms > Realm Name > Services > OAuth2 Provider > Advanced, and enter the header name in the Trusted TLS Client Certificate Header property.

        Specify a strong, random name for the trusted header. A misconfigured proxy or load balancer could let an attacker send malicious header values. A trusted header name that is difficult to guess makes this type of attack more difficult.

Proof-of-possession

Proof-of-possession is a means of ensuring that the client sending a request to the resource server is in possession of a particular cryptographic key. In other words, it is a way of proving the identity of the client.

Configure proof-of-possession to control which clients access your resources, or to mitigate against token theft; a malicious user with an access token must also present the cryptographic key to access the resources.

AM supports the following proof-of-possession methods:

JWK-based proof-of-possession

With proof-of-possession, the OAuth 2.0 client uses a known cryptographic key to prove its identity to the resource server.

How it works

Proof-of-possession has the OAuth 2.0 client include a JSON Web Key (JWK) with the client’s public key in a request for an access token:

  • The client presents the access token to a resource server.

  • The resource server gets the client’s public key from the access token.

  • The resource server uses the public key from the JWK to issue and validate a challenge-response with the client.

  • The client uses the private key to respond to the challenge.

Successfully solving the challenge cryptographically confirms proof-of-possession of the access token.

For details, refer to RFC 7800, Proof-of-Possession Key Semantics for JSON Web Tokens (JWTs). AM does not support jwe and jku format keys; the public key must be represented in jwk format.

This sequence diagram displays the flow:

OAuth 2.0 JWK-based proof-of-possession flow
Figure 11. OAuth 2.0 JWK-based proof-of-possession flow
  1. The client requests an access token using an OAuth 2.0 grant flow with the JWK in the request.

    Before using the flow, the client gets a public-private key pair and prepares the JWK to hold the public key.

  2. The authorization server returns the access token to the client:

    • When AM uses server-side OAuth 2.0 token storage, it keeps the JWK with the access token in the CTS token store and provides the client with the access token ID.

    • When AM uses client-side OAuth 2.0 token storage, the access token is a JWT with the JWK embedded.

  3. The client requests access to the protected resources from the resource server.

  4. The resource server recovers the JWK associated with the access token:

    • When AM uses server-side OAuth 2.0 token storage, the resource server introspects the access token to get the JWK.

    • When AM uses client-side OAuth 2.0 token storage, the access token is a JWT with the JWK embedded.

  5. The resource server creates a challenge using the public key from the JWK.

    For example, the challenge could be a message or a nonce encrypted with the public key.

  6. The resource server sends the challenge to the client.

  7. The client solves the challenge using its private key.

  8. The client sends the response to the challenge to the resource server.

The resource server validates the response, confirming the client’s proof-of-possession, and grants access.

Demonstrate proof-of-possession

Demonstrate the process with an OAuth 2.0 client that uses the client credentials grant:

Create an OAuth 2.0 client

  1. Create a confidential OAuth 2.0 client account.

    In the AM admin UI, click 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

    Scopes

    access

  2. Under the Advanced tab, add Grant Type: Client Credentials and save your work.

Get an access token

  1. Generate a public-private key pair for the OAuth 2.0 client.

    AM supports both RSA and elliptic curve (EC) key types.

    To demonstrate the process, use an online JWK generator, such as https://mkjwk.org/.

    For production deployments, store the key pair with the private key in a secure location. The OAuth 2.0 client must never reveal the private key. It uses the private key to solve the challenge from the resource server.

  2. Represent the public key as a JWK.

    Adapt the output to use the JWK format fields.

    AM proof-of-possession requires a JWK where the key fields depend on the key type and the body is a single public key object, not an array, as in the following example:

    {
      "jwk": {
        "kty": "EC",
        "use": "enc",
        "crv": "P-256",
        "kid": "myPublicJsonWebKey",
        "x": "D5kNqoGZbLZa77xdh4HSlSZIJcHxNw4UP0pgd5wbXvU",
        "y": "tX3SnRZgUOy48FV0XTCtaQNLG_DxXGbcVk94KvpyXrk"
      }
    }
  3. Base64-encode your JWK, as in the following example:

    ewogICJqd2siOiB7CiAgICAia3R5IjogIkVDIiwKICAgICJ1c2UiOiAiZW5jIiwKICAgICJjc
    nYiOiAiUC0yNTYiLAogICAgImtpZCI6ICJteVB1YmxpY0pzb25XZWJLZXkiLAogICAgIngiOi
    AiRDVrTnFvR1piTFphNzd4ZGg0SFNsU1pJSmNIeE53NFVQMHBnZDV3Ylh2VSIsCiAgICAieSI
    6ICJ0WDNTblJaZ1VPeTQ4RlYwWFRDdGFRTkxHX0R4WEdiY1ZrOTRLdnB5WHJrIgogIH0KfQ==
  4. Include the base64-encoded JWK as the value of the cnf_key parameter to request an access token:

    $ curl \
    --request POST \
    --user 'myClient:forgerock' \
    --data 'grant_type=client_credentials' \
    --data 'scope=access' \
    --data 'cnf_key=eyJqd2siOnsia3R5IjoiRUMiLCJ1c2UiOiJlbmMiLCJjcnYiOiJQLTI1NiIsImtpZCI6Im15UHVibGljSnNvbldlYktleSIsIngiOiJENWtOcW9HWmJMWmE3N3hkaDRIU2xTWklKY0h4Tnc0VVAwcGdkNXdiWHZVIiwieSI6InRYM1NuUlpnVU95NDhGVjBYVEN0YVFOTEdfRHhYR2JjVms5NEt2cHlYcmsifX0=' \
    'https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token'
    {"access_token":"nhFC8RBEA6Zm672ir9GlWOMdJYc","scope":"access","token_type":"Bearer","expires_in":3599}

    In this example, AM uses server-side OAuth 2.0 tokens. The response includes the access token ID.

    If AM used client-side OAuth 2.0 tokens, the access_token field would contain the embedded JWK.

Use the access token

  1. The client uses the access token to request a protected resource on the resource server.

    This step is not shown in the demonstration.

  2. The resource server uses the access token to get the public key.

    In this demonstration where AM uses server-side OAuth 2.0 tokens, use the OAuth 2.0 client credentials to introspect the token on behalf of the resource server.

    The cnf field contains the JWK:

    $ curl \
    --request POST \
    --user 'myClient:forgerock' \
    --data 'token=nhFC8RBEA6Zm672ir9GlWOMdJYc' \
    'https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/introspect'
    {
      "active": true,
      "scope": "access",
      "realm": "/alpha",
      "client_id": "myClient",
      "user_id": "myClient",
      "username": "myClient",
      "token_type": "Bearer",
      "exp": 1671126270,
      "sub": "myClient",
      "subname": "myClient",
      "iss": "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha",
      "cnf": {
        "jwk": {
          "kty": "EC",
          "use": "enc",
          "crv": "P-256",
          "kid": "myPublicJsonWebKey",
          "x": "D5kNqoGZbLZa77xdh4HSlSZIJcHxNw4UP0pgd5wbXvU",
          "y": "tX3SnRZgUOy48FV0XTCtaQNLG_DxXGbcVk94KvpyXrk"
        }
      },
      "authGrantId": "CBmKDJ1Ei8V7HhyXcKAyHaNR42I",
      "auditTrackingId": "3c47dc23-a35f-4a34-9f73-daf709d42400-385803"
    }
  3. The resource server uses the public key to confirm proof-of-possession with a challenge-response interaction.

    This step is not shown in the demonstration.

    By successfully responding to the challenge, the client proves it has the private key for the public key it presented to get the access token.

  4. The resource server grants access to the resource.

Certificate-bound proof-of-possession

AM supports associating an X.509 certificate with an access token to support proof-of-possession interactions, as per version 12 of the OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens internet-draft.

This ensures that only the client in possession of the private key corresponding to the certificate can use the bearer token to access protected resources.

Since the resource server validates the hash contained in the access token as proof-of-possession against the client’s certificate, clients must use the certificate used to request the bearer token when accessing the protected resources. Moreover, this implies that access tokens are invalidated when clients update their certificates.

OAuth 2.0 Certificate-Bound Proof-of-Possession Flow
Figure 12. OAuth 2.0 Certificate-Bound Proof-of-Possession Flow
Certificate-Bound Proof-of-Possession Flow Explained
  1. The client, communicating over TLS, requests an access token using an OAuth 2.0 grant flow.

    The implicit grant flow does not support certificate-bound proof-of-possession. For more information, see the OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens internet-draft.

  2. The authorization server returns the access token to the client with the client’s certificate hash embedded:

    • If the authorization server is configured for server-side OAuth 2.0, the authorization server stores the certificate hash with the access token in the CTS token store and provides the client with the access token ID.

    • If the authorization server is configured for client-side OAuth 2.0, the access token is a JWT that contains the certificate hash embedded in it.

    The hash of the client’s certificate is stored in the cnf confirmation key of the type x5t#S256, which contains the base64URL-encoded SHA-256 hash of the DER-encoding of the full X.509 certificate.

  3. The client, communicating over mTLS, requests access to the protected resources from the resource server.

  4. The resource server validates the client’s certificate with the certificate hash contained in the access token:

    • If the authorization server is configured for server-side OAuth 2.0, the resource server calls the OAuth 2.0 introspect endpoint with the access token to recover the cnf claim that contains the certificate’s hash.

    • If the authorization server is configured for client-side OAuth 2.0, the resource server recovers the cnf claim that contains the certificate’s hash from the access token JWT.

  5. The resource server allows access to the protected resources.

To configure your environment for certificate-bound tokens, see the following sections:

Obtain certificate-bound tokens when mutual TLS authentication is configured

Clients can authenticate to the OAuth 2.0 endpoints by presenting X.509 self-signed or CA-signed certificates as per version 12 of the OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens internet-draft.

Depending on the type of client, AM performs the following actions:

  • Confidential clients. When clients present a certificate as the authentication method while making a call to the token endpoint, AM authenticates the client and AM binds the certificate to the access token.

  • Public clients. When clients present a certificate while making a call to the token endpoint, AM ignores the certificate for authentication purposes and binds the certificate to the access token.

Perform the steps in the following procedure to obtain a certificate-bound access token when a client authenticates using mutual TLS:

  1. Ensure your environment enforces TLS between the authorization server and the clients, and between the resource server and the clients.

    Self-signed and CA-signed certificates are supported.

    You must configure the container where AM runs to request and accept client certificates.

  2. Configure AM as an OAuth 2.0 authorization server using the following information:

    • You must enable the Support TLS Certificate-Bound Access Tokens switch (Realms > Realm Name > Services > OAuth2 Provider > Advanced).

      This property specifies whether AM should bind certificates to access tokens when clients authenticate using TLS client certificates.

    • If TLS is being terminated at a reverse proxy or load balancer, you must configure the Trusted TLS Client Certificate Header property (Realms > Realm Name > Services > OAuth2 Provider > Advanced) to hold the name of the HTTP header that will provide AM with the client certificate.

      For more information, see Providing Client Certificates to AM.

  3. Register an OAuth 2.0 client in AM.

    The following configuration will be used in the examples of this procedure:

    • Client ID: myClient

    • Scopes: write

    • Grant Types: Client Credentials

    • You must enable the Use Certificate-Bound Access Tokens switch (Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Signing and Encryption).

      This switch specifies whether AM should bind certificates to access tokens for this client when the client authenticates to the token endpoint using a TLS client certificate. When disabled, AM does not bind certificates to access tokens issued to the client even if the client presents a TLS client certificate.

  4. Configure the client for mutual TLS authentication.

    For more information, see Mutual TLS.

  5. The client makes a call to the token endpoint to request an access token, and includes its client certificate in the call:

    $ curl \
    --request POST \
    --cacert AMServer.cer \
    --data "client_id=myClient" \
    --data "grant_type=client_credentials" \
    --data "scope=write" \
    --data "response_type=token" \
    --cert myClientCertificate.pem \
    --key myClientCertificate.key.pem \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"

    The authorization server returns the access token:

    • If server-side OAuth 2.0 tokens are enabled, the response will include an access token ID in the access_token property, which identifies the access token data stored on the server. For example:

      {
          "access_token":"f08f1fcf-3ecb-4120-820d-fb71e3f51c04",
          "scope":"profile",
          "token_type":"Bearer",
          "expires_in":3599
      }
    • If client-side OAuth 2.0 tokens are enabled, the response will be a JWT in the access_token, which has the JWK embedded within. The following example has shortened the access token for display purposes:

      {
          "access_token": "eyJ0eXAiOiJKV1QiLCHi51zbE3t…​zc2NjI3NDgsInNjb3zUOCVKCX0Se0",
          "scope": "profile",
          "token_type": "Bearer",
          "expires_in": 3599
      }
  6. The client requests access to the protected resources.

    The resource server validates the hash contained in the access token against the certificate the client presents as part of the TLS handshake.

    The hash contained in the access token is stored in the cnf confirmation key of the type x5t#S256, which contains the base64URL-encoded SHA-256 hash of the DER-encoding of the full X.509 certificate.

    If server-side OAuth 2.0 tokens are enabled, the resource server can make a POST request to the introspect endpoint to acquire the certificate’s hash:

    $ curl \
    --request POST \
    --header "Authorization: Basic bXlDbGllbnQ6Zm9yZ2Vyb2Nr" \
    --data "token=f08f1fcf-3ecb-4120-820d-fb71e3f51c04" \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/introspect"
    {
       "active":true,
       "scope":"write",
       "client_id":"myClient",
       "user_id":"myClient",
       "username":"myClient",
       "token_type":"Bearer",
       "exp":1547079953,
       "sub":"(age!myClient)",
       "subname":"myClient"
       "iss":"https://openam.example.com:8443/openam/oauth2",
       "cnf":{
          "x5t#S256":"m8UcWBSPNtaKN19TdR8zUHvWWOSCSX9nsa5vU6fscd0"
       }
    }

    If client-side OAuth 2.0 tokens are enabled, the resource server can decode the JWT to access the cnf key in the JWT’s payload. For example:

    {
      "sub": "myClient",
      "cts": "OAUTH2_STATELESS_GRANT",
      ....
      "cnf": {
         "x5t#S256": "m8UcWBSPNtaKN19TdR8zUHvWWOSCSX9nsa5vU6fscd0"
      },
      "exp": 1547083590,
      "iat": 1547079990,
      "expires_in": 3600,
      "jti": "sLzkRiayAQKsrXN0Gu_vwFog3Rs"
    }

Obtain certificate-bound tokens without configuring mutual TLS authentication

Clients can obtain a certificate-bound access token when making a call to the OAuth 2.0 endpoints as long as they provide an X.509 client certificate in one of the following ways:

  • Presenting a self-signed or CA-signed certificate as part of the TLS handshake with AM.

    AM authenticates the clients using the specified credentials (for example, client ID and secret) and binds the certificate to the access token.

    Your environment must enforce TLS between the authorization server and the clients, and between the resource server and the clients.

    You must also configure the container where AM runs to request and accept client certificates.

  • Providing a hash of the self-signed or CA-signed certificate in the cnf_key parameter as part of the call to the OAuth 2.0 endpoint.

    This method uses capabilities already implemented in AM that are not part of the OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens internet-draft.

    Use this option only if the client cannot authenticate its TLS connection to AM.

Perform the steps in the following procedure to obtain a certificate-bound access token when clients are not authenticating with mutual TLS:

  1. Configure AM as an OAuth 2.0 authorization server using the following information:

    • You must enable the Support TLS Certificate-Bound Access Tokens switch (Realms > Realm Name > Services > OAuth2 Provider > Advanced).

      This property specifies whether AM should bind certificates to access tokens when clients authenticate using TLS client certificates.

    • If not using the cnf_key, and if TLS is being terminated at a reverse proxy or load balancer, you must configure the Trusted TLS Client Certificate Header property (Realms > Realm Name > Services > OAuth2 Provider > Advanced) to hold the name of the HTTP header that will provide AM with the client certificate.

      For more information, see Provide client certificates to AM.

  2. Register a client in AM.

    The following configuration will be used in the examples of this procedure:

    • Client ID: myClient

    • Scopes: write

    • Grant Types: Client Credentials

    • or confidential clients, configure a secret. For example:

      • Client Secret: forgerock

    • You must enable the Use Certificate-Bound Access Tokens switch (Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Signing and Encryption).

      This switch specifies whether AM should bind certificates to access tokens for this client when the client authenticates to the token endpoint using a TLS client certificate. When disabled, AM does not bind certificates to access tokens issued to the client even if the client presents a TLS client certificate.

  3. The client makes a call to the token endpoint to request an access token, and includes its client certificate in the call:

    $ curl \
    --request POST \
    --cacert AMServer.cer \
    --data "client_id=myClient" \
    --data "client_secret=forgerock" \
    --data "grant_type=client_credentials" \
    --data "scope=write" \
    --data "response_type=token" \
    --cert myClientCertificate.pem \
    --key myClientCertificate.key.pem \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"

    To use the cnf_key parameter, the client must perform the following additional steps:

    • Calculate the SHA-256 hash of the DER-encoding of the full X.509 client certificate and base64URL-encode it. For example:

      m8UcWBSPNtaKN19TdR8zUHvWWOSCSX9nsa5vU6fscd0
    • Store the certificate’s hash in JSON format, as follows:

      {"x5t#S256":"m8UcWBSPNtaKN19TdR8zUHvWWOSCSX9nsa5vU6fscd0"}
    • Base64-encode the JSON. For example:

      eyJ4NXQjUzI1NiI6Im04VWNXQlNQTnRhS04xOVRkUjh6VUh2V1dPU0NTWDluc2E1dlU2ZnNjZDAifQ==
    • Make a call to the token endpoint to request an access token, including the cnf_key parameter with the certificate hash. Note that the client certificate is not included in any other way:

      $ curl \
      --request POST \
      --data "grant_type=client_credentials"\
      --data "client_id=myClient" \
      --data "client_secret=forgerock" \
      --data "cnf_key=eyJ4NXQjUzI1NiI6Im04
                      VWNXQlNQTnRhS04xOVRk
                      Ujh6VUh2V1dPU0NTWDlu
                      c2E1dlU2ZnNjZDAifQ==" \
      "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"

    The authorization server returns the access token:

    • If server-side OAuth 2.0 tokens are enabled, the response will include an access token ID in the access_token property, which identifies the access token data stored on the server. For example:

    {
        "access_token":"f08f1fcf-3ecb-4120-820d-fb71e3f51c04",
        "scope":"profile",
        "token_type":"Bearer",
        "expires_in":3599
    }
    • If client-side OAuth 2.0 tokens are enabled, the response will be a JSON web token in the access_token, which has the certificate hash embedded within. The following example has shortened the access token for display purposes:

    {
        "access_token": "eyJ0eXAiOiJKV1QiLCHi51zbE3t…​zc2NjI3NDgsInNjb3zUOCVKCX0Se0",
        "scope": "profile",
        "token_type": "Bearer",
        "expires_in": 3599
    }
  4. The client requests access to the protected resources from the resource server and the resource server validates the hash contained in the access token against the certificate the client presents as part of the TLS handshake.

    The hash contained in the access token is stored in the cnf confirmation key of the type x5t#S256, which contains the base64URL-encoded SHA-256 hash of the DER-encoding of the full X.509 certificate.

    If server-side OAuth 2.0 tokens are enabled, the resource server can make a POST request to the introspect endpoint to acquire the certificate’s hash:

    $ curl \
    --request POST \
    --header "Authorization: Basic bXlDbGllbnQ6Zm9yZ2Vyb2Nr" \
    --data "token=f08f1fcf-3ecb-4120-820d-fb71e3f51c04" \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/introspect"
    {
       "active":true,
       "scope":"write",
       "client_id":"myClient",
       "user_id":"myClient",
       "username":"myClient",
       "token_type":"Bearer",
       "exp":1547079953,
       "sub":"(age!myClient)",
       "subname":"myClient"
       "iss":"https://openam.example.com:8443/openam/oauth2",
       "cnf":{
          "x5t#S256":"m8UcWBSPNtaKN19TdR8zUHvWWOSCSX9nsa5vU6fscd0"
       }
    }

    If client-side OAuth 2.0 tokens are enabled, the resource server can decode the JWT to access the cnf key in the JWT’s payload. For example:

    {
      "sub": "myClient",
      "cts": "OAUTH2_STATELESS_GRANT",
      ....
      "cnf": {
        "x5t#S256": "m8UcWBSPNtaKN19TdR8zUHvWWOSCSX9nsa5vU6fscd0"
      },
      "exp": 1547083590,
      "iat": 1547079990,
      "expires_in": 3600,
      "jti": "sLzkRiayAQKsrXN0Gu_vwFog3Rs"
    }

Refresh tokens

Refresh tokens (RFC 6749) let an OAuth 2.0 client get a new access token with identical or narrower scopes than the original and without involving the resource owner. AM can issue refresh tokens for all OAuth 2.0/OpenID Connect grant flows except the implicit and client credentials flows.

About refresh tokens

Access tokens have short lifetimes because they grant any bearer access to a protected resource.

Refresh tokens give an OAuth 2.0 client something to exchange for a new access token. The exchange does not involve resource owner interaction. Refresh tokens are useful when an OAuth 2.0 client needs:

  • Long term access to a protected resource.

  • Access when the resource owner is unavailable.

  • Multiple operations to access the same protected resources, and the resource owner should only have to grant consent once.

Refresh tokens are safer than long-lived access tokens. To exchange a refresh token for an access token, the OAuth 2.0 client must authenticate. A malicious user with a compromised access token has access to the protected resource. A user with a refresh token must also have the client ID and client secret to obtain an access token.

Settings for refresh tokens

Refresh tokens configuration settings include:

Token issuance

By default, AM issues a refresh token whenever it issues an access token. When AM issues a new refresh token, it expires the old refresh token.

You can disable refresh token issuance in the AM admin UI OAuth 2.0 provider configuration under Realms > Realm Name > Services > OAuth2 Provider > Core with:

Issue Refresh Tokens

Whether to issue refresh tokens with access tokens.

Issue Refresh Tokens on Refreshing Access Tokens

Whether to issue new refresh tokens when exchanging a refresh token for an access token.

Token lifetime

Refresh tokens are long-lived by default.

You set the lifetime of refresh tokens in the OAuth 2.0 provider settings or for individual OAuth 2.0 clients. By default, AM relies on the OAuth 2.0 provider configuration.

In the AM admin UI, you can change the setting per client under Realm > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Refresh Token Lifetime.

For details, refer to the OAuth2 provider and the advanced client settings.

Grace period

The grace period specifies how long an OAuth 2.0 client can replay requests to exchange a refresh token for an access token if there’s a network problem or other transient issue.

For details, refer to the OAuth2.0 provider or OAuth 2.0 client settings.

Clients can revoke refresh tokens using the /oauth2/token/revoke endpoint. The next time the client requires access to protected resources, it must involve the resource owner.

Demonstrate refresh tokens

Demonstrate using refresh tokens with the following steps:

OAuth 2.0 client

  1. Create a confidential OAuth 2.0 client account.

  2. In the AM admin UI, select Realm > Realm Name > Applications > OAuth 2.0 > Clients and click + Add Client.

  3. Create a new confidential client with the following credentials:

    Client ID

    myClient

    Client Secret

    forgerock

    Redirection URIs

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

Resource owner

An OAuth 2.0 client requests the access token on behalf of a resource owner. Create the OAuth 2.0 resource owner account:

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

  2. Record the username and password.

Get an access token

  1. Authenticate as the resource owner:

    curl \
    --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://openam.example.com:8443/openam/json/realms/root/realms/alpha/authenticate'
    {"tokenId":"<resource-owner-tokenId>","successUrl":"/enduser/?realm=/alpha","realm":"/alpha"}
  2. Request the authorization code as the client:

    curl \
    --dump-header - \
    --request POST \
    --Cookie 'iPlanetDirectoryPro=<resource-owner-tokenId>' \
    --data 'scope=openid' \
    --data 'response_type=code' \
    --data 'client_id=myClient' \
    --data 'csrf=<resource-owner-tokenId>' \
    --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'
    …​
    location: https://www.example.com:443/callback?code=<authorization-code>&iss=https%3A%2F%2F…​
    …​
  3. Exchange the authorization code for an access token as the client:

    curl \
    --request POST \
    --user 'myClient:forgerock' \
    --data 'grant_type=authorization_code' \
    --data 'code=<authorization-code>' \
    --data 'redirect_uri=https://www.example.com:443/callback' \
    '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
    }

Refresh an access token

Exchange the refresh token for a new access token:

$ curl \
--request POST \
--data "grant_type=refresh_token" \
--data "refresh_token=<refresh-token>" \
--data "client_id=myClient" \
--data "client_secret=forgerock" \
--data "scope=openid" \
"https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"
{
  "access_token": "<new-access-token>",
  "refresh_token": "<new-refresh-token>",
  "scope": "openid",
  "id_token": "<id-token>",
  "token_type": "Bearer",
  "expires_in": 3599
}
  • The scope parameter is optional. By default, AM issues an access token with the same scopes as the original token.

  • AM has issued a new refresh token; the original refresh token is now inactive.

Macaroons: sharable tokens

Macaroons are bearer tokens that you use in place of regular OAuth 2.0 access and refresh tokens. They let multiple clients and resource servers share a single token without compromising security.

Coordinating multiple access tokens with different scopes across a set of clients can be complicated.

The idea behind macaroons is to issue a single access token with a broad scope. The client creates as many sharable tokens as needed from the initial token by restricting its scope.

This is useful in a microservice architecture; for example, where a single client delegates tasks to other services that have a limited set of capabilities or are bound by certain restrictions.

Caveats

To restrict macaroon token scopes, use caveats.

Caveats are restrictions included in the token that must be satisfied when using the token. For example, an expiry time could be set as a caveat. When the expiry time is past, the token is invalid.

Caveats that can be satisfied locally are referred to as first-party caveats. Caveats satisfied by a service external from AM are referred to as third-party caveats.

Supported first-party caveats

There is no standard format for caveats in macaroons. AM uses a JSON-based syntax that mirrors the existing JSON Web Token (JWT)-based token restrictions:

scope

Restricts the scope of the token.

The resulting scope is the intersection of the original scopes and any scope caveats.

exp

Restricts the expiry time of the token.

The effective expiry time is the minimum of the original expiry time and any expiry caveats. If you append more than one exp caveat, the most restrictive one applies.

cnf

Binds the access token to a client certificate.

You can only bind one client certificate to a macaroon. AM ignores attempts to bind a new certificate with subsequent caveats.

aud

Restricts the audience of the token.

The effective audience is the intersection of any audience restriction and aud caveats.

AM returns other caveats in a caveats object in the JSON introspection response.

OpenID Connect clients must ensure the following information is present in the JSON:

  • The openid scope; for example, "scopes": ["profile", "openid"].

  • The id_token response type; for example, "response_types": ["code", "id_token code"].

Third-party caveats

Third-party caveats require the client to use a service other than AM to prove they satisfy the condition specified by the caveat. They are useful where services external to AM run authorization checks relevant to the access token.

Consider the case where you have an identity provider service external to AM to query whether the user related to the access token belongs to a particular user group.

Another use case for third-party caveats is transactional authorization, requiring a user to authorize every access to a resource. Consider the case where a payment is tied to a unique transaction. You create a macaroon access token with a third-party caveat requiring the client to obtain a one-time discharge macaroon from an external transactional service.

A third-party caveat has the following parts:

  • A hint describing where the client can find the third-party service, which is usually a URL.

  • A unique secret key to sign discharge macaroons, known as the discharge key.

  • An identifier indicating to the third-party service which condition to check and how to recover the discharge key.

    There is no standard format for the identifier.

Discharge macaroons

A third-party service returns proof a condition is satisfied in a discharge macaroon. The client must present both the access token macaroon and the discharge macaroon to access a protected resource.

A discharge macaroon can hold first-party caveats, such as expiry time. This allows for flows where the access token macaroon is long-lived, and the discharge macaroon is not, forcing the client to acquire a new discharge macaroon for each access to a protected resource.

AM treats first-party caveats attached to discharge macaroons like caveats on the access token.

For example, if the discharge macaroon limits the expiry time to five minutes, the introspection response lists the expiry time of the access token as five minutes, even if the access token is valid for longer.

Append caveats

A client appends caveats to a macaroon using a macaroon library. This depends on your client, not AM.

To manage first-party caveats and to inspect the caveats on a macaroon, you can use the /json/token/macaroon endpoint.

AM endpoints and macaroons

AM OAuth 2.0 endpoints that support access tokens also support macaroons without further configuration. AM endpoints reject macaroons whose caveats are not satisfied.

For macaroons with third-party caveats, use the X-Discharge-Macaroon header to pass discharge macaroons.

Macaroons and token storage

AM layers macaroons on top of the existing server-side OAuth 2.0 tokens and client-side OAuth 2.0 tokens. When you enable macaroons, AM issues one of the following:

Server-side macaroon tokens

AM stores the access token in the CTS and issues macaroons to clients. The macaroon identifier points to the access token in the CTS.

Client-side macaroon tokens

AM issues signed or encrypted JWTs as access tokens wrapped in a macaroon.

Make sure the resulting token fits in the storage available to the client. If the storage available is limited to the size of a browser cookie, for example, the token may be too large to store. Token size can also impact network performance.

Enable macaroons

Follow these steps to enable macaroons in the OAuth 2.0 provider service:

  1. In the AM admin UI, go to Realms > Realm Name > Services > OAuth2 Provider.

  2. On the Core tab, enable Use Macaroon Access and Refresh Tokens and save your changes.

  3. On the Advanced tab, select the Macaroon Token Format.

    If possible, use the default V2 format.

    Macaroons using the older V1 token format are much less efficient. Only use V1 when you require compatibility with older macaroon libraries.

  4. Set the OAuth2 Token Signing Algorithm to HS256 or stronger.

  5. Save your changes.

OAuth 2.0 grant flows

This section describes the OAuth 2.0 flows that AM supports, and also provides the information required to implement them. All the examples assume the realm is configured for server-side tokens; however, the examples also apply to client-side tokens.

You should decide which flow is best for your environment based on the application that will be the OAuth 2.0 client. The following table provides an overview of the flows AM supports and when they should be used:

Deciding Which Flow to Use Depending on the OAuth 2.0 Client
Client Type Which Grant to use? Description

The client is a web application running on a server. For example, a .war application.

(RFC 6749) The authorization server uses the user-agent, for example, the resource owner’s browser, to transport a code that is later exchanged for an access token.

The client is a native application or a single-page application (SPA). For example, a desktop, a mobile application, or a JavaScript application.

(RFC 6749, RFC 7636) The authorization server uses the user-agent, for example, the resource owner’s browser, to transport a code that is later exchanged for an access token.

Since the client does not communicate securely with the authorization server, the code may be intercepted by malicious users. The implementation of the Proof Key for Code Exchange (PKCE) standard mitigates against those attacks.

The client is a web application, a native application, or a SPA, that needs to make complex and highly secure authorization requests.

(RFC 9126) Clients can push the payload of an authorization request directly to the authorization server without exposing sensitive request data to the browser. The server provides them with a request URI that is used to secure a subsequent authorization request.

The client is a SPA. For example, a JavaScript application.

(RFC 6749) The authorization server gives the access token to the user-agent so it can forward the token to the client. Therefore, the access token might be exposed to the user and other applications.

For security purposes, you should use the authorization code grant with PKCE when possible.

The client is trusted with the resource owner credentials. For example, the resource owner’s operating system.

(RFC 6749) The resource owner provides their credentials to the client, which uses them to obtain an access token from the authorization server.

This flow should only be used if other flows are not available.

The client is the resource owner, or the client does not act on behalf of the resource owner.

(RFC 6749) Similar to the Resource Owner Password Credentials grant type, but the resource owner is not part of the flow and the client accesses information relevant to itself.

The client is an input-constrained device. For example, a TV set.

(RFC 8628) The resource owner authorizes the client to access protected resources on their behalf by using a different user-agent and entering a code displayed on the client device.

The client is an input-constrained device that can generate a PKCE challenge.

(AM-only, based on RFC 8628 and RFC 7636) The resource owner authorizes the client to access protected resources on their behalf by using a different user-agent and entering a code displayed on the client device.

Since the client does not communicate securely with the authorization server, the code may be intercepted by malicious users. The implementation of the Proof Key for Code Exchange (PKCE) standard mitigates against those attacks.

The client has a SAML v2.0 trust relationship with the resource owner. For example, an application in an environment where a SAML v2.0 ecosystem coexists with an OAuth 2.0 one.

(RFC 7522) The client uses the resource owner’s SAML v2.0 assertion to obtain an access token from the authorization server without interacting with the resource owner again.

The client has a trust relationship with the resource owner that is specified as a JWT. For example, an application in an environment where a non-SAML v2.0 identity ecosystem coexists with an OAuth 2.0 one.

(RFC 7523) The client uses a signed JWT to obtain an access token from the authorization server without interacting with the resource owner.

ForgeRock provides a Postman collection to try out the flows. See ForgeRock grant flows collection.

AM supports associating a confirmation key or a certificate with an access token to support proof-of-possession interactions.

ForgeRock grant flows collection

ForgeRock provides an OAuth 2.0 and OpenID Connect Postman collection to try out the flows that AM support. The source for the REST calls, including the prerequisites needed to run the collection, is provided as a downloadable JSON file collection.

  1. Download and install Postman.

  2. Download the ForgeRock OAuth 2.0 and OpenID Connect Collection.

  3. Import the collection in Postman:

    • Go to File > Import …​ > Upload Files.

    • Select the collection you downloaded, and click Open. Then, click Import.

  4. Configure the collection’s variables to suit your environment:

    • In Postman, on the Collections tab, select the ForgeRock OAuth 2.0 and OpenID Connect Collection. Click the …​ button, and then on Edit.

    • Click on the Variables tab, and change at least the value of the following variables:

      • URL_base

      • admin_password

    • Click Update to save your changes.

      You are ready to start running the collection.

The collection is divided into the following folders:

  • Prerequisites, containing REST calls to configure AM as an authorization server, and to create the clients and users required to run the collection.

  • OAuth 2.0 Flows, containing the flows explained in OAuth 2.0 grant flows.

  • OpenID Connect Flows, containing the flows explained in OpenID Connect grant flows.

    The Backchannel (CIBA) grant is not included, since it requires push notifications and an additional device to work.

  • Refresh Token Flow, containing calls explained in Refresh tokens and /oauth2/token/revoke.

  • Token Exchange Flows, containing the token exchange flows explained in Token exchange.

Authorization code grant

Endpoints

The authorization code grant flow for OAuth 2.0 and OIDC lets a confidential client, such as a web application running on a server, exchange an authorization code for an access token to get authorized access to protected resources.

The authorization code grant is secure because:

  • It is a two-step process:

    1. The resource owner authenticates to the authorization server and authorizes the client to access the protected resource. The client receives a temporary authorization code from the server as confirmation.

    2. The authorization server validates the authorization code and exchanges it for an access token.

  • The authorization server delivers the access token directly to the client, usually over HTTPS. Neither the access token nor the client secret is exposed publicly, which protects confidential clients.

The authorization code grant flow

OAuth 2.0

oauth2-authz
  1. The client, usually a web-based service, receives a request to access a protected resource. To access the resource, the client requires authorization from the resource owner.

  2. The client redirects the resource owner’s user-agent to the authorization server.

  3. The authorization server authenticates the resource owner, confirms resource access, and gathers consent if not previously saved.

  4. The authorization server redirects the resource owner’s user agent to the client.

  5. During the redirection process, the authorization server appends an authorization code.

  6. The client receives the authorization code and authenticates to the authorization server to exchange the code for an access token.

    Note that this example assumes a confidential client. Public clients are not required to authenticate.

  7. If the authorization code is valid, the authorization server returns an access token (and a refresh token, if configured) to the client.

  8. The client requests access to the protected resource from the resource server.

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

OIDC

oidc-authz
  1. The end user wants to use the services provided by the relying party (RP). The RP, usually a web-based service, requires an account to provide those services.

    The end user issues a request to share their information with the RP.

  2. To access the end user’s information in the OpenID provider (OP), the RP requires end user consent.

    The RP redirects the end user’s user-agent…​

  3. …​to the OP.

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

  5. The OP redirects the end user’s user-agent to the RP.

  6. During the redirection process, the OP appends an authorization code.

  7. The RP authenticates to the OP and exchanges the authorization code for an access token and an ID token.

    Note that this example assumes a confidential client. Public clients are not required to authenticate.

  8. If the authorization code is valid, the OP returns an access token and an ID token to the RP.

  9. The RP validates the ID token and its claims.

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

  10. If the RP requires additional claims, it sends a request to the /oauth2/userinfo endpoint with the access token for authorization.

  11. 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 authorization code grant flow

Follow these steps to get an authorization code and exchange it for an access token:

Prepare the demonstration

This demonstration 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.

    For more information, refer to Authorization server configuration.

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

    • Client secret: forgerock

    • Scopes: write (for OAuth 2.0)
      openid and profile (for OIDC)

    • Response Types: code

    • Grant Types: Authorization Code

    For more information, refer to Client application registration.

Get an authorization code using a browser

  1. The client redirects the resource owner’s user-agent to the authorization server’s /oauth2/authorize endpoint specifying, at least, the following form parameters:

    • client_id=your-client-id

    • response_type=code

    • redirect_uri=your-redirect-id

    If the OAuth 2.0 provider is configured for a subrealm rather than the Top Level Realm, you must specify it in the endpoint. For example, if the OAuth 2.0 provider is configured for the /alpha realm, then use /oauth2/realms/root/realms/alpha/authorize.

    For example:

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

    For OIDC, set scope=openid profile instead.

    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 parameter is included to protect against CSRF attacks but is also optional.

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

  3. On a successful login, the authorization server presents the AM consent screen unless AM is configured to use implied consent.

    The OAuth 2.0 AM user interface consent screen requesting access to the write scope.
    Figure 13. OAuth 2.0 consent screen
  4. 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/callback?code=g5B3qZ8rWzKIU2xodV_kkSIk0F4&scope=write&iss…​

  6. The client performs the steps in Exchange an authorization code for an access token to exchange the authorization code for an access token.

Get an authorization code using REST

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

    For example:

    $ 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 call to the authorization server’s /oauth2/authorize endpoint, specifying the resource owner’s SSO token in a cookie, and the following parameters:

    • client_id=your-client-id

    • response_type=code

    • redirect_uri=your-redirect-uri

    • decision=allow

    • csrf=demo-user-SSO-token

    If the OAuth 2.0 provider is configured for a subrealm rather than the Top Level Realm, you must specify it in the endpoint. For example, if the OAuth 2.0 provider is configured for the /alpha realm, then use /oauth2/realms/root/realms/alpha/authorize.

    For example:

    $ curl --dump-header - \
    --request POST \
    --Cookie "iPlanetDirectoryPro=AQIC5wM…​TU3OQ*" \
    --data "scope=write" \
    --data "response_type=code" \
    --data "client_id=myClient" \
    --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"

    For OIDC, set scope=openid profile instead.

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

    The state parameter is included to protect against CSRF attacks but is also optional.

    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:

    HTTP/2 302
    …​
    location: https://www.example.com:443/callback?code=<authorization-code>&iss…​
    …​
  3. Follow the steps in Exchange an authorization code for 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:

  • grant_type=authorization_code

  • code=your-authorization-code

  • redirect_uri=your-redirect-uri

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, refer to OAuth 2.0 client authentication.

If the OAuth 2.0 provider is configured for a subrealm rather than the Top Level Realm, you must specify it in the endpoint. For example, if the OAuth 2.0 provider is configured for the /alpha realm, then use /oauth2/realms/root/realms/alpha/access_token.

For example:

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

For OAuth 2.0, the authorization server returns an access token; for example:

{
  "access_token": "sbQZuveFumUDV5R1vVBl6QAGNB8",
  "scope": "write",
  "token_type": "Bearer",
  "expires_in": 3599
}

For OIDC, the OP returns an access token and an ID token; for example:

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

If the RP does not require the access token, revoke it.

The authorization server can also issue refresh tokens at the same time the access tokens are issued. For more information, refer to Refresh tokens.

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://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/userinfo"
{
  "name": "<resource-owner-display-name>",
  "family_name": "<resource-owner-family-name>",
  "given_name": "<resource-owner-given-name>",
  "sub": "<resource-owner-sub>",
  "subname": "<resource-owner-id>"
}

Authorization code grant with PKCE

Endpoints

The authorization code grant, when combined with the Proof Key for Code Exchange (PKCE) standard (RFC 7636), is used when a public client, such as a native or SPA application, requires access to protected resources.

The flow is similar to the regular authorization code grant but the client must generate a code that is used in the communication between the client and the authorization server. This code mitigates against interception attacks performed by malicious users.

Browser-based clients making OAuth 2.0 requests to different domains must implement Cross-Origin Resource Sharing (CORS) calls to access OAuth 2.0 resources in different domains.

The PKCE flow adds three parameters to those used for the authorization code grant:

code_verifier

A random string that correlates the authorization request to the token request.

code_challenge

A string derived from the code verifier sent in the authorization request, which is validated against the code verifier during the token request.

code_challenge_method

The method used to derive the code challenge.

The authorization code grant with PKCE flow

OAuth 2.0

oauth2-authz-pkce
  1. The client receives a request to access a protected resource. To access the resource, the client requires authorization from the resource owner. When using the PKCE standard, the client must generate a unique code and a way to verify it, and append the code to the request for the authorization code.

  2. The client redirects the resource owner’s user-agent to the authorization server.

  3. The authorization server authenticates the resource owner, confirms resource access, and gathers consent if not previously saved.

  4. If the resource owner’s credentials are valid, the authorization server stores the code challenge and redirects the resource owner’s user agent to the redirection URI.

  5. During the redirection process, the authorization server appends an authorization code to the request to the client.

  6. The client receives the authorization code and calls the authorization server’s token endpoint to exchange the authorization code for an access token appending the verification code to the request.

  7. The authorization server verifies the code stored in memory using the validation code. It also verifies the authorization code. If both codes are valid, the authorization server returns an access token (and a refresh token, if configured) to the client.

  8. The client requests access to the protected resource from the resource server.

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

OIDC

oidc-authz-pkce
  1. The end user wants to use the services provided by the relying party (RP). The RP, usually a web-based service, requires an account to provide those services.

    The end user issues a request to share their information with the RP.

  2. To access the end user’s information in the OpenID provider (OP), the RP requires end user consent. When using the PKCE standard, the RP must generate a unique code and a way to verify it, and append the code to the request for the authorization code.

  3. The RP redirects the end user’s user-agent with code_challenge and code_challenge_method…​

  4. …​to the OP.

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

  6. On success, the OP stores the code challenge and its method.

  7. The OP redirects the end user’s user-agent to the redirection URI, usually at the RP.

  8. During the redirection process, the OP appends an authorization code.

  9. The RP authenticates to the OP and exchanges the authorization code for an access token and an ID token, appending the verification code to the request.

  10. The OP verifies the code challenge it stored using the validation code, and verifies the authorization code.

  11. If the codes are valid, the OP issues an access token and an ID token to the RP.

  12. The RP validates the ID token and its claims.

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

  13. If the RP requires additional claims, it sends a request to the /oauth2/userinfo endpoint with the access token for authorization.

  14. 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 authorization code grant with PKCE flow

Follow these steps to get an authorization code and exchange it for an access token:

Prepare the demonstration

This demonstration 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.

    For more information, refer to Authorization server configuration.

  • A public client called myClient is registered in AM with the following configuration:

    • Scopes: write (for OAuth 2.0)
      openid and profile (for OIDC)

    • Response Types: code

    • Grant Types: Authorization Code

    For more information, refer to Client application registration.

Generate a code verifier and a code challenge

The client application must generate a code verifier, a high-entropy URL-safe random string between 43 and 128 characters long, and a code challenge, a base64url-encoded hash of the code verifier.

It is mandatory to create the challenge using a SHA-256 algorithm if the client supports it, as specified in the PKCE standard (RFC 7636).

This example JavaScript code generates values such as 082b7ab3042995bcb3163ec83cf5f348ff4393d5713630eb5f09dcf7d0c2cca39749313556c260558eb49355ff86d0e61449 for the code verifier and K7Dz7AcV1urbgo4FYNgy2QAAz6v2LyIdmmGPzsFZbAc for the code challenge:

const crypto = require('crypto');

const verifier = crypto.randomBytes(50).toString('hex').slice(0, 128);
const challenge = crypto.createHash('sha256')
    .update(Buffer.from(verifier))
    .digest('base64')
    .replace(/=/g, '')
    .replace(/\+/g, '-')
    .replace(/\//g, '_');

console.log("verifier: " + verifier);
console.log("challenge: " + challenge);

The client is now ready to request an authorization code.

Get an authorization code using a browser

  1. The client redirects the resource owner’s user-agent to the authorization server’s /oauth2/authorize endpoint specifying, at least, the following query parameters:

    • client_id=your-client-id

    • response_type=code

    • redirect_uri=your-redirect-uri

    • code_challenge=your-code-challenge

    • code_challenge_method=S256

    If the OAuth 2.0 provider is configured for a subrealm rather than the Top Level Realm, you must specify it in the endpoint. For example, if the OAuth 2.0 provider is configured for the /customers realm, then use /oauth2/realms/root/realms/customers/authorize.

    For example:

    https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/authorize \
    ?client_id=myClient \
    &response_type=code \
    &scope=write \
    &redirect_uri=https://www.example.com:443/callback \
    &code_challenge=K7Dz7AcV1urbgo4FYNgy2QAAz6v2LyIdmmGPzsFZbAc \
    &code_challenge_method=S256 \
    &state=abc123

    For OIDC, set scope=openid profile instead.

    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 parameter is included to protect against CSRF attacks but is also optional.

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

  3. On a successful login, the authorization server presents the AM consent screen unless AM is configured to use implied consent.

    The OAuth 2.0 AM user interface consent screen requesting access to the write scope.
    Figure 14. OAuth 2.0 consent screen
  4. 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/callback?code=ZNSDo8LrsI2w-6NOCYKQgvDPqtg&scope=write&iss…​

  6. The client performs the steps in Exchange an authorization code for an access token to exchange the authorization code for an access token.

Get an authorization code using REST

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

    For example:

    $ 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 call to the authorization server’s /oauth2/authorize endpoint specifying the resource owner’s SSO token in a cookie, and the following parameters:

    • client_id=your-client-id

    • response_type=code

    • redirect_uri=your-redirect-uri

    • decision=allow

    • csrf=demo-user-SSO-token

    • code_challenge=your-code-challenge

    • code_challenge_method=S256

    The Code Verifier Parameter Required setting (Realms > Realm Name > Services > OAuth2 Provider > Advanced) specifies whether AM requires clients to include a code verifier in their calls. However, if a client makes a call to AM with the code_challenge parameter, AM will honor the code exchange regardless of the Code Verifier Parameter Required value. For more information, refer to Authorization server configuration.

    If the OAuth 2.0 provider is configured for a subrealm rather than the Top Level Realm, you must specify it in the endpoint. For example, if the OAuth 2.0 provider is configured for the /customers realm, then use /oauth2/realms/root/realms/customers/authorize.

    For example:

    $ curl --dump-header - \
    --request POST \
    --Cookie "iPlanetDirectoryPro=AQIC5wM…​TU3OQ*" \
    --data "redirect_uri=https://www.example.com:443/callback" \
    --data "scope=write" \
    --data "response_type=code" \
    --data "client_id=myClient" \
    --data "csrf=AQIC5wM…​TU3OQ*" \
    --data "state=abc123" \
    --data "decision=allow" \
    --data "code_challenge=K7Dz7AcV1urbgo4FYNgy2QAAz6v2LyIdmmGPzsFZbAc" \
    --data "code_challenge_method=S256" \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/authorize"

    For OIDC, set scope=openid profile instead.

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

    The state parameter is included to protect against CSRF attacks but is also optional.

    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:

    HTTP/2 302
    …​
    location: https://www.example.com:443/callback?code=<authorization-code>&iss…​
    …​
  3. Follow the steps in Exchange an authorization code for 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:

  • grant_type=authorization_code

  • code=your-authorization-code

  • client_id=your-client-id

  • redirect_uri=your-redirect-uri

  • code_verifier=your-code-verifier

For example:

$ curl \
--request POST \
--data "grant_type=authorization_code" \
--data "code=g5B3qZ8rWzKIU2xodV_kkSIk0F4" \
--data "client_id=myClient" \
--data "redirect_uri=https://www.example.com:443/callback" \
--data "code_verifier=082b7ab3042995bcb3163ec8…​" \
"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.

For OAuth 2.0, the authorization server returns an access token; for example:

{
  "access_token": "sbQZuveFumUDV5R1vVBl6QAGNB8",
  "scope": "write",
  "token_type": "Bearer",
  "expires_in": 3599
}

For OIDC, the OP returns an access token and an ID token; for example:

{
  "access_token": "<access-token>",
  "scope": "openid profile",
  "id_token": "<id-token>",
  "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, refer to Refresh tokens.

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://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/userinfo"
{
  "name": "<resource-owner-display-name>",
  "family_name": "<resource-owner-family-name>",
  "given_name": "<resource-owner-given-name>",
  "sub": "<resource-owner-sub>",
  "subname": "<resource-owner-id>"
}

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 is used to reference the payload data in subsequent interactions with the server.

PAR is optional by default, but you can enable the Require Pushed Authorization Requests setting in the AM admin UI to enforce the use of the PAR endpoint to initiate authorization requests.

To force all clients to use PAR, configure the OAuth 2.0 provider advanced settings. To force an individual client, configure the client settings.

The authorization code grant with PAR flow

OAuth 2.0 authorization code grant flow
Figure 15. OAuth 2.0 authorization code grant flow
  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 resource.

Demonstrate the authorization code grant with PAR flow

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

Prepare the demonstration

This demonstration 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, refer to Authorization server configuration.

  • 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, refer to Client application registration. Complete these steps to prepare the authorization code grant with PAR flow demonstration:

Get a PAR request URI

As the client, call the authorization server’s /oauth2/par endpoint. Specify parameters directly in the request body. Alternatively, 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=signed-encrypted-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

Example PAR request with a JWT:

$ 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:

$ 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:

{
  "request_uri": "C2c3yhu2IApAELttmZtfPNPQaIJxvTCHk", (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 the authorization server’s /oauth2/authorize endpoint, including the following parameters:

    • client_id=your-client-id

    • response_type=code

    • redirect_uri=your-redirect-id

    • request_uri=the-PAR-request-uri

    For example:

    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

    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 parameter is included to protect against CSRF attacks but is also optional.

  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 unless AM is configured to use implied consent.

    The OAuth 2.0 AM user interface consent screen requesting access to the write scope.
    Figure 16. OAuth 2.0 consent screen
  5. Click Allow to consent.

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

  6. 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/callback?code=g5B3qZ8rWzKIU2xodV_kkSIk0F4&scope=write&iss…​

  7. The client performs the steps in Exchange an authorization code for an access token to exchange the authorization code for an access token.

Get an authorization code using REST

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

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

    For example:

    $ 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 /oauth2/authorize 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 example:

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

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

    The state parameter is included to protect against CSRF attacks but is also optional.

    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:

    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 exchange the authorization code for 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:

  • grant_type=authorization_code

  • code=your-authorization-code

  • redirect_uri=your-redirect-uri

  • code_verifier=your-code-verifier

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, refer to OAuth 2.0 client authentication.

For example:

$ 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" \
--data "code_verifier=082b7ab3042995bcb3163ec8…​" \
"https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"

The client_id and 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:

{
  "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, refer to Refresh tokens.

Implicit grant

Endpoints

The implicit grant is designed for public clients that run inside the resource owner’s user-agent, for example, JavaScript applications. For OIDC, this flow lets the relying party (RP) interact directly with the OpenID provider (OP), and receive tokens directly from the authorization endpoint.

Because applications running in the user-agent are considered less trusted than applications running in servers, the authorization server or OP never issues refresh tokens in this flow. Also, you must consider the security impact of cross-site scripting (XSS) attacks that could leak the access token to other systems, and implement Cross-Origin Resource Sharing (CORS) to make OAuth 2.0 requests to different domains.

Due to the security implications of this flow, ForgeRock recommends that you use the Authorization code grant with PKCE flow whenever possible.

The implicit grant flow

OAuth 2.0

oauth2-implicit
  1. The client, usually a single-page application (SPA), receives a request to access a protected resource. To access the resource, the client requires authorization from the resource owner.

  2. The client redirects the resource owner’s user-agent or opens a new frame to the AM authorization service.

  3. The authorization server authenticates the resource owner, confirms resource access, and gathers consent if not previously saved.

  4. If the resource owner’s credentials are valid, the authorization server returns the access token to the user-agent as part of the redirection URI.

  5. Now, the client must extract the access token from the URI. In this example, the user-agent follows the redirection to the web-hosted server that contains the protected resources without the access token.

  6. The web-hosted server returns a web page with an embedded script to extract the access token from the URI.

    In another possible scenario, the redirection URI is a dummy URI in the client, and the client already has the logic in itself to extract the access token.

  7. The user-agent executes the script and retrieves the access token.

  8. The user-agent returns the access token to the client.

  9. The client requests access to the protected resource presenting the access token to the resource server.

  10. The resource server contacts the authorization server to validate the access token.

  11. The authorization server validates the token and responds to the resource server.

  12. If the token is valid, the resource server allows the client to access the protected resource.

OIDC

oidc-implicit
  1. The RP, usually an SPA, receives a request to access user information at the OP. To access this information, the RP requires authorization from the end user.

  2. The RP redirects the end user’s user-agent or opens a new frame to the OP.

    As part of the implicit flow, the request includes the openid scope and the nonce parameter.

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

  4. On success, the OP returns access and ID tokens to the user-agent in the redirection URI.

  5. The user-agent extracts the tokens from the URI.

    In this example, the user-agent follows the redirection to the RP without the tokens.

  6. The RP returns a web page with an embedded script to extract the tokens from the URI.

    In another possible scenario, the redirection URI is a dummy URI in the RP application and the RP application already has the logic to extract the tokens.

  7. The user-agent executes the script and retrieves the tokens.

  8. The user-agent returns the tokens to the RP.

  9. The RP validates the ID token and its claims.

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

  10. If the RP requires additional claims, it sends a request to the /oauth2/userinfo endpoint with the access token for authorization.

  11. 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 implicit grant flow

Perform these steps to get an access token:

Prepare the demonstration

This demonstration assumes the following configuration:

  • AM is configured as an OAuth 2.0 authorization server. Ensure that:

    • The token plugin is configured in the Response Type Plugins field.

    • The Implicit Grant grant type is configured in the Grant Types field.

    For more information, see Authorization server configuration.

  • A public client called myClient is registered in AM with the following configuration:

    • Scopes: write (for OAuth 2.0)
      openid and profile (for OIDC)

    • Response Types: token and token id_token

    • Grant Types: Implicit

For more information, see Client application registration.

Get an access token using a browser

Perform the steps in this procedure to obtain an access token using the implicit grant:

  1. The client redirects the resource owner’s user-agent to the authorization server’s /oauth2/authorize endpoint, including the following query parameters:

    • client_id: your-client-id

    • response_type: token (OAuth 2.0); token id_token (OIDC)

    • scope: write (OAuth 2.0); openid and profile (OIDC)

    • redirect_uri=your-redirect-uri

    If the OAuth 2.0 provider is configured for a subrealm rather than the Top Level Realm, you must specify it in the endpoint. For example, if the OAuth 2.0 provider is configured for the /alpha realm, then use /oauth2/realms/root/realms/alpha/authorize.

    For example:

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

    For OIDC, use scope=openid profile and response_type=token id_token instead.

    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 parameter is included to protect against CSRF attacks but is also optional.

  2. The resource owner logs in 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.

    After logging in, the authorization server presents the AM user interface consent screen:

    The OAuth 2.0 AM user interface consent screen requesting access to a scope.
    Figure 17. OAuth 2.0 consent screen
  3. The resource owner selects the Allow button to grant consent for the write scope.

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

  4. Inspect the URL in the browser.

    For OAuth 2.0, it contains the access token the authorization server has issued, for example:

    https://www.example.com:443/callback#access_token=[.var]##<access_token>##&iss...

    For OIDC, it contains the access and ID tokens; for example:

    https://www.example.com/callback#access_token=<access_token>&id_token=<id_token>…​

Get an access token using REST

  1. Authenticate as the resource owner.

    For example:

    $ 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. 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: your-client-id

    • response_type: token (OAuth 2.0); token id_token (OIDC)

    • decision: allow

    • csrf: demo-user-SSO-token

    • redirect_uri: your-redirect-uri

    • scope: write (OAuth 2.0); openid and profile (OIDC)

    For information about the parameters supported by the /oauth2/authorize endpoint, see /oauth2/authorize.

    If the OAuth 2.0 provider is configured for a subrealm rather than the Top Level Realm, you must specify it in the endpoint. For example, if the OAuth 2.0 provider is configured for the /alpha realm, then use /oauth2/realms/root/realms/alpha/authorize.

    For example:

    curl --dump-header - \
    --request POST \
    --Cookie "iPlanetDirectoryPro=AQIC5wM…​TU3OQ*" \
    --data "client_id=myClient" \
    --data "response_type=token" \
    --data "scope=write" \
    --data "state=123abc" \
    --data "decision=allow" \
    --data "csrf=AQIC5wM…​TU3OQ*" \
    --data "redirect_uri=https://www.example.com:443/callback" \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/authorize"

    For OIDC, use scope=openid profile and response_type=token id_token instead.

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

    The state parameter is included to protect against CSRF attacks but is also optional.

    For OAuth 2.0, if the authorization server is able to authenticate the user, it returns an HTTP 302 response with the access token appended to the redirection URI:

    HTTP/2 302
    …​
    location: https://www.example.com:443/callback#access_token=<access-token>&iss…​

    For OIDC, it returns the access and ID tokens in the redirection URI:

    HTTP/2 302
    …​
    location: https://www.example.com:443/callback#access_token=<access-token>&id_token=<id_token>…​
    …​

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://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/userinfo"
{
  "name": "<resource-owner-display-name>",
  "family_name": "<resource-owner-family-name>",
  "given_name": "<resource-owner-given-name>",
  "sub": "<resource-owner-sub>",
  "subname": "<resource-owner-id>"
}

Resource owner password credentials grant

The resource owner password credentials (ROPC) grant flow lets the client use the resource owner’s user name and password to get an access token.

Since the resource owner shares their credentials with the client, this flow is deemed the most insecure of the OAuth 2.0 flows. The resource owner’s credentials can potentially be leaked or abused by the client application, and the resource owner has no control over the authorization process.

You should implement the ROPC grant flow only if the resource owner has a trust relationship with the client (such as the device operating system, or a highly privileged application).

OAuth 2.0 Resource Owner Password Credentials Grant Flow
Figure 18. OAuth 2.0 Resource Owner Password Credentials Grant Flow
ROPC grant flow explained
  1. The resource owner provides the client with their username and password.

  2. The client sends the resource owner’s and its own credentials to the authorization server, which authenticates the credentials and authorizes the resource owner’s request.

  3. If the credentials are valid, the authorization server returns an access token to the client.

  4. The client requests access to the protected resources presenting the access token to the resource server.

  5. The resource server contacts the authorization server to validate the access token.

  6. The authorization server validates the token and responds to the resource server.

  7. If the token is valid, the resource server allows the client to access the protected resources.

Perform the following procedure to obtain an access token:

Obtain an access token using the ROPC grant flow

This procedure assumes the following configuration:

  • An authentication service that is able to authenticate a username and password combination, without requiring any UI-based interaction from the resource owner, is available.

    For example, the ldapService chain (the default), or the Example tree.

    Specify the tree or chain by using one or more of the methods below. AM checks for the configured value in the following order, using the first value found:

    1. For a specific access token REST request.

      Set the auth_chain parameter.

    2. Individually for a realm, overriding the realm-level setting below.

      Go to Realms > Realm Name > Services > OAuth2 Provider > Advanced, and set the Password Grant Authentication Service property.

    3. Individually for a realm.

      Go to Realms > Realm Name > Authentication > Settings > Core, and set the Organization Authentication Configuration property.

    4. Globally, for all realms.

      Go to Configure > Authentication > Core Attributes > Core, and set the Organization Authentication Configuration property.

  • AM is configured as an OAuth 2.0 authorization server. Ensure that:

    • The Resource Owner Password Credentials grant type is configured in the Grant Types field.

    For more information, see Authorization server configuration.

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

    • Client secret: forgerock

    • Scopes: write

    • Grant Types: Resource Owner Password Credentials

For more information, see Client application registration.

Perform the following steps to obtain an access token using the ROPC grant flow:

  1. The resource owner provides their credentials to the client. This is done outside the scope of this procedure.

  2. The client creates a POST request to the authorization server’s token endpoint specifying, at least, the following parameters:

    • username=your-resource-owner-username

    • password=your-resource-owner-password

    • grant_type=password

      For information about the parameters supported by the /oauth2/access_token endpoint, see /oauth2/access_token.

      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.

    If the OAuth 2.0 provider is configured for a subrealm rather than the Top Level Realm, you must specify it in the endpoint. For example, if the OAuth 2.0 provider is configured for the /alpha realm, then use /oauth2/realms/root/realms/alpha/access_token.

    For example:

    $ curl \
    --request POST \
    --data "grant_type=password" \
    --data "username=demo" \
    --data "password=Ch4ng31t" \
    --data "scope=write" \
    --data "client_id=myClient" \
    --data "client_secret=forgerock" \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"

    Note that the scope parameter has 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 authorization server returns an access token in the access_token property. For example:

    {
      "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.

Client credentials grant

The client credentials grant is used when the client is also the resource owner and is accessing its own data rather than acting on behalf of a user. For example, an application that needs access to a protected resource to retrieve its own data to perform a task, or update its configuration, would use the client credentials grant to acquire an access token.

The client credentials grant flow supports confidential clients only.

OAuth 2.0 client credentials grant flow
Figure 19. OAuth 2.0 client credentials grant flow
Client credentials grant flow explained
  1. The client sends its credentials to the authorization server to get authenticated, and requests an access token.

  2. If the client credentials are valid, the authorization server returns an access token to the client.

  3. The client requests access to the protected resources from the resource server.

  4. The resource server contacts the authorization server to validate the access token.

  5. The authorization server validates the token and responds to the resource server.

  6. If the token is valid, the resource server allows the client to access the protected resources.

Obtain an access token using the client credentials grant

Perform the steps in the following procedure to obtain an access token. This procedure assumes the following configuration:

  • AM is configured as an OAuth 2.0 authorization server. Ensure that:

    • The Client Credentials grant type is configured in the Grant Types field.

    For more information, see Authorization server configuration.

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

    • Client secret: forgerock

    • Scopes: write

    • Grant Types: Client Credentials

For more information, see Client application registration.

  1. The client makes a POST call to the authorization server’s token endpoint specifying, at least, the following parameters:

    • grant_type=client_credentials

    For information about the parameters supported by the /oauth2/access_token endpoint, see /oauth2/access_token.

    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.

    If the OAuth 2.0 provider is configured for a subrealm rather than the Top Level Realm, you must specify it in the endpoint. For example, if the OAuth 2.0 provider is configured for the /alpha realm, use /oauth2/realms/root/realms/alpha/access_token.

    For example:

    $ curl \
    --request POST \
    --data "grant_type=client_credentials" \
    --data "client_id=myClient" \
    --data "client_secret=forgerock" \
    --data "scope=write" \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"

    Note that the scope parameter has 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 authorization server returns an access token in the access_token property. For example:

    {
      "access_token": "sbQZuveFumUDV5R1vVBl6QAGNB8",
      "scope": "write",
      "token_type": "Bearer",
      "expires_in": 3599
    }

Device flow

The device flow is designed for client devices that have limited user interfaces, such as a set-top box, streaming radio, or a server process running on a headless operating system.

Rather than logging in by using the client device itself, you can authorize the client to access protected resources on your behalf by logging in with a different user agent, such as an Internet browser or smartphone, and entering a code displayed on the client device.

OAuth 2.0 Device Flow
Figure 20. OAuth 2.0 Device Flow
Device flow explained
  1. The client device requests a device code from AM.

  2. AM returns a device code, a user code, a URL for entering the user code, and an interval, in seconds.

  3. The client device provides instructions to the user to enter the user code. The client may choose an appropriate method to convey the instructions, for example, text instructions on screen, or a QR code.

  4. The client device begins to continuously poll AM to see if authorization has been completed.

  5. If the user has not yet completed the authorization, AM returns an HTTP 403 status code, with an authorization_pending message.

  6. The user follows the instructions from the client device to enter the user code by using a separate device.

  7. If the user code is valid, AM redirects the resource owner for authentication.

  8. Upon authentication, the user is prompted to confirm the user code. The page is pre-populated with the one entered before.

  9. The user can authorize the client device. The AM consent page also displays the requested scopes, and their values.

    AM does not display the confirmation nor the consent pages if the user has a valid session when they entered the code, and the client is allowed to skip consent.

    This is also true if you perform the call using REST and pass the decision=allow parameter.

  10. Upon authorization, AM responds to the client device’s polling with an HTTP 200 status, and an access token, giving the client device access to the requested resources.

The following procedures show how to use the OAuth 2.0 device flow endpoints:

Obtain a user code for the device

Devices can display a user code and instructions for a user, which can be used on a separate client to provide consent, allowing the device to access resources.

User codes consist of a random selection of a configurable set of characters.

By default, the user code is generated using eight of the following characters:

234567ABCDEFGHIJKLMNOPQRSTVWXYZabcdefghijkmnopqrstvwxyz

You can configure the list of possible characters to improve usability. For example, remove similar characters such as 'l' and 'I' to reduce ambiguity on low resolution device screens, or limit input to either alphabetical or numerical characters to suit mobile keyboards.

The length of the user code is also configurable.

For more information, see the device flow configuration.

This procedure assumes the following configuration:

  • AM is configured as an OAuth 2.0 authorization server.

    Ensure that the Device Code grant type is configured in the Grant Types field.

    For more information, see Authorization server configuration.

  • A public client called myClient is registered in AM with the following configuration:

    • Scopes: write

    • Grant Types: Device Code

For more information, see Client application registration.

Perform the following steps to request a user code in the OAuth 2.0 device flow:

  1. The client creates a POST request to the /oauth2/device/code endpoint specifying the client ID, myClient, as a minimum.

    For information about the parameters supported by the /oauth2/device/code endpoint, see /oauth2/device/code. For information about private client authentication methods, see OAuth 2.0 client authentication.

    For example:

    $ curl \
    --request POST \
    --data "client_id=myClient" \
    --data "scope=write" \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/device/code"
    {
        "interval": 5,
        "device_code": "7a95a0a4-6f13-42e3-ac3e-d3d159c94c55…​",
        "verification_uri": "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/device/user",
        "verification_url": "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/device/user",
        "verification_uri_complete": "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/device/user?user_code=VAL12e0v",
        "user_code": "VAL12e0v",
        "expires_in": 300
    }

    On success, AM returns a user code, a verification URI, and a verification_uri_complete value comprising the user code appended to the URI, which can be used to create QR codes.

    The verification_url output is included to support earlier versions of the specification.

    AM also returns an interval, in seconds, that the client device must wait for in between requests for an access token.

    You can configure the returned values by navigating to Realms > Realm Name > Services > OAuth2 Provider > Device Flow.

  2. The client device should now provide instructions to the user to enter the user code and grant access to the OAuth 2.0 device.

    The client may choose an appropriate method to convey the instructions, for example, text instructions on screen, or a QR code. Perform the steps in one of the following procedures:

  3. The client device should also begin polling the authorization server for the access token using the interval and device code information obtained in the previous step.

Grant consent with a user code without using a browser in the device flow

OAuth 2.0 device flow requires that the user grants consent to allow the client device to access the resources. The authorization server would then provide the client with an access token.

To grant consent with a user code without using a browser, perform the following steps:

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

    For example:

    $ 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 call to the authorization server’s authorization device user endpoint specifying in a cookie SSO token of the demo and, at least, the following parameters:

    • user_code*=resource-owner-user-code

    • decision*=allow

    • csrf*=demo-user-SSO-token

    For information about the parameters supported by the /oauth2/device/user endpoint, see /oauth2/device/user.

    The iPlanetDirectoryPro cookie is required and should contain the SSO token of the user granting access to the client. For example:

    $ curl \
    --request POST \
    --header "Cookie: iPlanetDirectoryPro=AQIC5wM…​TU3OQ*" \
    --data "user_code=VAL12e0v" \
    --data "decision=allow" \
    --data "csrf=AQIC5wM…​TU3OQ*" \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/device/user"

    The scope and the client_id parameters have not been included because the user code already contains that information.

    AM returns HTML containing a JavaScript fragment named pageData, with details of the result.

    Successfully allowing or denying access returns:

    pageData = {
        locale: "en_US",
        baseUrl : "https://openam.example.com:8443/openam/XUI/",
        realm : "/alpha",
        done: true
    }

    done: true means that the flow can now continue.

    If the supplied user code has already been used, or is incorrect, AM returns the following:

    pageData = {
        locale: "en_US",
        errorCode: "not_found",
        realm : "/alpha",
        baseUrl : "https://openam.example.com:8443/openam/XUI/"
        oauth2Data: {
              csrf: "ErFIk8pMraJ1rvKbloTgpp6b7GZ57kyk9HaIiKMVK3g=",
              userCode: "VAL12e0v",
        }
    }

    As per Section 4.1.1 of the OAuth 2.0 authorization framework, it is required that the authorization server legitimately obtains an authorization decision from the resource owner.

    Any client using the endpoints to register consent is responsible for ensuring this requirement, AM cannot assert that consent was given in these cases.

Grant consent with a user code using a browser in the device flow

OAuth 2.0 device flow requires that the user grants consent to allow the client device to access the resources. The authorization server would then provide the client with an access token.

To grant consent with a user code using a browser, perform the following steps:

  1. The resource owner navigates to the verification URL acquired with the user code, for example, https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/device/user.

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

  3. The resource owner enters their user code:

    Visit the verification URL to enter the user code.
    Figure 21. OAuth 2.0 User Code
  4. The resource owner authorizes the device flow client by allowing the requested scopes:

    AM lists the scopes requested by the client device, and their values.
    Figure 22. OAuth 2.0 Consent Page

    If the client uses implied consent, AM does not display this screen.

  5. AM adds the OAuth 2.0 client to the user’s profile page in the Authorized Apps section and displays that the user is done with the flow:

    The user code part of the device flow is done.
    Figure 23. OAuth 2.0 Done Page

    The device now can request an access token from AM.

Poll for authorization in the OAuth 2.0 device flow

The client device must poll the authorization server for an access token, since it cannot know whether the resource owner has already given consent or not.

Perform the following steps to poll for an access token:

  1. On the client device, create a POST request to poll the /oauth2/access_token endpoint to request an access token specifying, at least, the following parameters:

    • client_id=your-client-id

    • grant_type=urn:ietf:params:oauth:grant-type:device_code

    • device_code=your-device-code

    For information about the parameters supported by the /oauth2/access_token endpoint, see /oauth2/access_token.

    The client device must wait for the number of seconds previously provided as the value of interval between polling AM for an access token. For example:

    $ curl \
    --request POST \
    --data "client_id=myClient" \
    --data "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
    --data "device_code=7a95a0a4-6f13-42e3-ac3e-d3d159c94c55…​" \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"

    If the user has authorized the client device, an HTTP 200 status code is returned, with an access token that can be used to request resources:

    {
        "expires_in": 3599,
        "token_type": "Bearer",
        "access_token": "c1e9c8a4-6a6c-45b2-919c-335f2cec5a40"
    }

    If the user has not yet authorized the client device, an HTTP 403 status code is returned, with the following error message:

    {
        "error": "authorization_pending",
        "error_description": "The user has not yet completed authorization"
    }

    If the client device is polling faster than the specified interval, an HTTP 400 status code is returned, with the following error message:

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

    The authorization server can also issue refresh tokens at the same time the access tokens are issued. For more information, see Refresh tokens.

Device flow with PKCE

The device flow is designed for client devices that have limited user interfaces, such as a set-top box. Since the devices are usually public clients and the device code can be intercepted by malicious users, you can combine the device flow with the PKCE standard (RFC 7636) to mitigate against interception attacks if the devices allow it.

AM implements this flow by adding the following parameters on top of those used for the device flow grant:

  • code_verifier (form parameter). Contains a random string that correlates the authorization request to the token request.

  • code_challenge (query parameter). Contains a string derived from the code verifier that is sent in the authorization request and that needs to be verified later with the code verifier.

  • code_challenge_method (query parameter). Contains the method used to derive the code challenge.

OAuth 2.0 Device Flow with PKCE
Figure 24. OAuth 2.0 Device Flow with PKCE
Device flow with PKCE explained
  1. When using the PKCE standard, the device must be able to generate a code verifier and a code challenge. For details, see the PKCE standard (RFC 7636).

    For a JavaScript example that generates a code verifier and a code challenge, see here.

  2. The client device requests a device code from AM, appending the code challenge previously generated to the request.

  3. AM returns a device code, a user code, a URL for entering the user code, and an interval, in seconds.

  4. The client device provides instructions to the user to enter the user code. The client may choose an appropriate method to convey the instructions, for example, text instructions on screen, or a QR code.

  5. The client device begins to continuously poll AM to see if authorization has been completed, appending the code verifier previously generated.

  6. If the user has not yet completed the authorization, AM returns an HTTP 403 status code, with an authorization_pending message.

  7. The user follows the instructions from the client device to enter the user code by using a separate device.

  8. The authorization server verifies the code challenge stored in memory using the validation code. It also verifies the user code. If both codes are valid, AM redirects the resource owner for authentication.

  9. Upon authentication, the user is prompted to confirm the user code. The page is pre-populated with the one entered before.

  10. The user can authorize the client device. The AM consent page also displays the requested scopes, and their values.

    AM does not display the confirmation nor the consent pages if the user has a valid session when they entered the code, and the client is allowed to skip consent.

    This is also true if you perform the call using REST and pass the decision=allow parameter.

  11. Upon authorization, AM responds to the client device’s polling with an HTTP 200 status, and an access token, giving the client device access to the requested resources.

The following procedures show how to use the OAuth 2.0 device flow endpoints:

Obtain a user code for the device in the device flow with PKCE

Devices can display a user code and instructions for a user, which can be used on a separate client to provide consent, allowing the device to access resources.

User codes consist of a random selection of a configurable set of characters.

By default, the user code is generated using eight of the following characters:

234567ABCDEFGHIJKLMNOPQRSTVWXYZabcdefghijkmnopqrstvwxyz

You can configure the list of possible characters to improve usability. For example, remove similar characters such as 'l' and 'I' to reduce ambiguity on low resolution device screens, or limit input to either alphabetical or numerical characters to suit mobile keyboards.

The length of the user code is also configurable.

For more information, see the device flow configuration.

This procedure assumes the following configuration:

  • AM is configured as an OAuth 2.0 authorization server. Ensure that:

    • The Device Code grant type is configured in the Grant Types field.

    The Code Verifier Parameter Required setting (Realms > Realm Name > Services > OAuth2 Provider > Advanced) specifies whether AM requires clients to include a code verifier in their calls. However, if a client makes a call to AM with the code_challenge parameter, AM will honor the code exchange regardless of the Code Verifier Parameter Required value. For more information, refer to Authorization server configuration.

  • A public client called myClient is registered in AM with the following configuration:

    • Scopes: write

    • Grant Types: Device Code

For more information, see Client application registration.

Perform the following steps to request a user code in the OAuth 2.0 device flow:

  1. The client creates a POST request to the /oauth2/device/code endpoint specifying, at least, the following parameters:

    • client_id=your-client-id

    • code_challenge=your-code-challenge

    • code_challenge_method=S256

      Creating the challenge using a SHA-256 algorithm is mandatory if the device supports it, as per the RFC 7636 standard.

    For information about the parameters supported by the /oauth2/device/code endpoint, see /oauth2/device/code. For information about private client authentication methods, see OAuth 2.0 client authentication.

    For example:

    $ curl \
    --request POST \
    --data "client_id=myClient" \
    --data "code_challenge=j3wKnK2Fa_mc2tgdqa6GtUfCYjdWSA5S23JKTTtPF8Y" \
    --data "code_challenge_method=S256" \
    --data "scope=write" \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/device/code"
    {
        "interval": 5,
        "device_code": "7a95a0a4-6f13-42e3-ac3e-d3d159c94c55…​",
        "verification_uri": "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/device/user",
        "verification_url": "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/device/user",
        "verification_uri_complete": "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/device/user?user_code=VAL12e0v",
        "user_code": "VAL12e0v",
        "expires_in": 300
    }

    On success, AM returns a user code, a verification URI, and a verification_uri_complete value comprising the user code appended to the URI, which can be used to create QR codes.

    The verification_url output is included to support earlier versions of the specification.

    AM also returns an interval, in seconds, that the client device must wait for in between requests for an access token.

    You can configure the returned values by navigating to Realms > Realm Name > Services > OAuth2 Provider > Device Flow.

  2. The client device should now provide instructions to the user to enter the user code and grant access to the OAuth 2.0 device.

    The client may choose an appropriate method to convey the instructions, for example, text instructions on screen, or a QR code. Perform the steps in one of the following procedures:

  3. The client device should also begin polling the authorization server for the access token using the interval and device code information obtained in the previous step and the PKCE code verifier. For more information, see Poll for authorization in the OAuth 2.0 device flow with PKCE.

Grant consent with a user code without using a browser in the device flow with PKCE

OAuth 2.0 device flow requires that the user grants consent to allow the client device to access the resources. The authorization server would then provide the client with an access token.

To grant consent with a user code without using a browser, perform the following steps:

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

    For example:

    $ 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 call to the authorization server’s authorization device user endpoint specifying in a cookie SSO token of the demo and, at least, the following parameters:

    • user_code*=resource-owner-user-code

    • decision*=allow

    • csrf*=demo-user-SSO-token

    For information about the parameters supported by the /oauth2/device/user endpoint, see /oauth2/device/user.

    The iPlanetDirectoryPro cookie is required and should contain the SSO token of the user granting access to the client. For example:

    $ curl \
    --request POST \
    --header "Cookie: iPlanetDirectoryPro=AQIC5wM…​TU3OQ*" \
    --data "user_code=VAL12e0v" \
    --data "decision=allow" \
    --data "csrf=AQIC5wM…​TU3OQ*" \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/device/user"

    The scope and the client_id parameters have not been included because the user code already contains that information.

    AM returns HTML containing a JavaScript fragment named pageData, with details of the result.

    Successfully allowing or denying access returns:

    pageData = {
        locale: "en_US",
        baseUrl : "https://openam.example.com:8443/openam/XUI/",
        realm : "/alpha",
        done: true
    }

    done: true means that the flow can now continue.

    If the supplied user code has already been used, or is incorrect, AM returns the following:

    pageData = {
        locale: "en_US",
        errorCode: "not_found",
        realm : "/alpha",
        baseUrl : "https://openam.example.com:8443/openam/XUI/"
        oauth2Data: {
              csrf: "ErFIk8pMraJ1rvKbloTgpp6b7GZ57kyk9HaIiKMVK3g=",
              userCode: "VAL12e0v",
        }
    }

    As per Section 4.1.1 of the OAuth 2.0 authorization framework, it is required that the authorization server legitimately obtains an authorization decision from the resource owner.

    Any client using the endpoints to register consent is responsible for ensuring this requirement, AM cannot assert that consent was given in these cases.

Grant consent with a user code using a browser in the device flow with PKCE

OAuth 2.0 device flow requires that the user grants consent to allow the client device to access the resources. The authorization server would then provide the client with an access token.

To grant consent with a user code using a browser, perform the following steps:

  1. The resource owner navigates to the verification URL acquired with the user code, for example, https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/device/user.

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

  3. The resource owner enters their user code:

    Visit the verification URL to enter the user code.
    Figure 25. OAuth 2.0 User Code
  4. The resource owner authorizes the device flow client by allowing the requested scopes:

    AM lists the scopes requested by the client device, and their values.
    Figure 26. OAuth 2.0 Consent Page

    If the client uses implied consent, AM does not display this screen.

  5. AM adds the OAuth 2.0 client to the user’s profile page in the Authorized Apps section and displays that the user is done with the flow:

    The user code part of the device flow is done.
    Figure 27. OAuth 2.0 Done Page

    The device now can request an access token from AM.

Poll for authorization in the OAuth 2.0 device flow with PKCE

The client device must poll the authorization server for an access token, since it cannot know whether the resource owner has already given consent or not.

Perform the following steps to poll for an access token:

  1. On the client device, create a POST request to poll the /oauth2/access_token endpoint to request an access token specifying, at least, the following parameters:

    • client_id*=your-client-id

    • grant_type=urn:ietf:params:oauth:grant-type:device_code

    • device_code=your-device-code

    • code_verifier=your-code-verifier

    For information about the parameters supported by the /oauth2/access_token endpoint, see /oauth2/access_token.

    The client device must wait for the number of seconds previously provided as the value of interval between polling AM for an access token. For example:

    $ curl \
    --request POST \
    --data "client_id=myClient" \
    --data "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
    --data "device_code=7a95a0a4-6f13-42e3-ac3e-d3d159c94c55…​" \
    --data "code_verifier=ZpJiIM_G0SE9WlxzS69Cq0mQh8uyFaeEbILlW8tHs62SmEE6n7Nke0XJGx_F4OduTI4"
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"

    If the user has authorized the client device, an HTTP 200 status code is returned, with an access token that can be used to request resources:

    {
        "expires_in": 3599,
        "token_type": "Bearer",
        "access_token": "c1e9c8a4-6a6c-45b2-919c-335f2cec5a40"
    }

    If the user has not yet authorized the client device, an HTTP 403 status code is returned, with the following error message:

    {
        "error": "authorization_pending",
        "error_description": "The user has not yet completed authorization"
    }

    If the client device is polling faster than the specified interval, an HTTP 400 status code is returned, with the following error message:

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

    The authorization server can also issue refresh tokens at the same time the access tokens are issued. For more information, see Refresh tokens.

SAML v2.0 profile for authorization grant

The SAML v2.0 profile for authorization grant is designed for environments that want to leverage the REST-based services provided by AM’s OAuth 2.0 support, while keeping their existing SAML v2.0 federation implementation.

The RFC 7522 describes the means to use SAML v2.0 bearer assertions to request access tokens and to authenticate OAuth 2.0 clients.

At present, AM implements the profile to request access tokens.

Consider the following requirements before implementing this flow:

  • The client (the application the resource owner uses to start the flow) must inform the resource owner that, by authenticating to the SAML v2.0 identity provider, the resource owner grants the client access to the protected resources. AM does not present the resource owner with consent pages.

    This client must be able to consume the access token and handle errors as required.

  • The OAuth 2.0 authorization service and SAML v2.0 service provider must be configured in the same AM instance.

  • The service provider must require that assertions are signed.

  • The SAML v2.0 identity provider must issue signed assertions.

    The assertion must contain the SAML v2.0 entity names, as follows:

    • The issuer must be set to the identity provider’s name. For example, https://idp.example.com:8443/idp.

    • The audience must be set to the service provider’s name. For example, https://openam.example.com:8443/openam.

  • The identity provider and the service provider must belong to the same circle of trust.

  • AM must be able to determine the resource owner from the name ID contained in the assertion. Failure to determine the resource owner results in an error similar to:

    {"error_description":"AM identity should not be null","error":"server_error"}

    AM may fail to determine the resource owner if the assertion contains an opaque name ID during transient federation. Because the opaque reference is never stored during a transient flow, the OAuth 2.0 provider cannot determine the resource owner it relates to.

    To work around this, configure an identity in the Transient User field of the SAML v2.0 service provider. This will map all transient ID references to that identity.

  • The OAuth 2.0 client is registered, at least, with the following configuration:

    • Grant Types: SAML2

  • The OAuth 2.0 provider is configured. Ensure that:

    • The SAML2 grant type is configured in the Grant Types field.

The following diagram demonstrates the SAML v2.0 Profile for authorization grants:

SAML v2.0 Profile for Authorization Grant Flow
Figure 28. SAML v2.0 Profile for Authorization Grant Flow
  1. The client requests the SAML v2.0 identity provider the SAML v2.0 assertion related to the resource owner. Usually, this means the client redirects the resource owner to the identity provider for authentication.

  2. The SAML v2.0 identity provider returns the signed assertion to the client.

  3. The client includes the assertion and a special grant type in the call to the OAuth 2.0 token endpoint in the following parameters:

    • grant_type=urn:ietf:params:oauth:grant-type:saml2-bearer

    • assertion=my-assertion

      Note that the assertion must be first base64-encoded, and then URL encoded.

    For example:

    $ curl \
    --request POST \
    --data "client_id=myClient" \
    --data "client_secret=forgerock" \
    --data-urlencode "assertion=PHNhbWxwOl…​ZT4" \
    --data "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Asaml2-bearer" \
    --data "redirect_uri=https://www.example.com:443/callback" \
    --data "scope=write" \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"
  4. The AM authorization server validates the assertion. If the assertion is valid, the authorization server returns an access token to the client.

  5. The client request access to the protected resources from the resource server.

  6. The resource server contacts the authorization server to validate the access token.

  7. The authorization server validates the token and responds to the resource server.

  8. If the token is valid, the resource server allows the client to access the protected resources.

JWT profile for OAuth 2.0 authorization grant

The JWT profile for OAuth 2.0 authorization grant is designed for environments that want to use the REST-based services provided by AM’s OAuth 2.0 framework, but keep their existing authentication services. The trust relationship must be able to be expressed with a JWT bearer token.

Because the trust relationship is already established, this flow does not require the end user’s interaction.

RFC 7523 defines the use of JWT bearer tokens for requesting access tokens and for client authentication.

Read this section for information about requesting access tokens.

To use JWTs for client authentication, refer to JWT profile.

As the authorization server, AM must validate the bearer JWT to issue the access token to the client. To ensure that malicious clients cannot self-sign their own JWTs to acquire tokens, AM requires the token issuer to be pre-registered as a special type of agent.

JWT Bearer Profile for Authorization Grant
Figure 29. JWT Bearer Profile for Authorization Grant
  1. The client requests a JWT from the issuer. The client itself can be the issuer, in which case it will create a JWT for itself before starting the OAuth 2.0 flow.

    Regardless of who signs the JWT, the issuer must be pre-registered in AM as a trusted JWT issuer by completing the steps to configure a trusted JWT issuer. Alternatively, you can configure a scripted trusted JWT issuer that dynamically acquires the details of the issuer from an external system.

  2. The issuer returns a signed JWT to the client; JWTs with message authentication codes (MACs) applied to them are not supported.

    The JWT must contain, at least, the following claims in the payload:

    • aud. Specifies a string or an array of strings that is the intended audience of the JWT. Must be set to, or contain, the authorization server’s token endpoint.

    • exp. Specifies the expiration time of the JWT in Unix time.

      Providing a JWT with an expiry time greater than 30 minutes causes AM to return a JWT expiration time is unreasonable error message.

    • iss. Specifies the unique identifier of the JWT issuer. This could be the client or a third party.

      The identifier must match the issuer field configured in the trusted JWT issuer agent.

    • sub. Specifies the principal who is the subject of the JWT. It must be a string that identifies the resource owner.

      You can configure the trusted JWT issuer agent to check a different claim for the principal. For example, the preferred_username from an ID token.

      In this case, the JWT would contain both the sub and the preferred_username claims.

      For more information, refer to Configure a trusted JWT issuer agent.

      The following is an example of the payload of a basic JWT:

      {
        "aud": [
          "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"
        ],
        "iss": "https://www.example.com/issuer",
        "exp": 1555530663,
        "sub": "demo"
      }

      For an example of a JWT containing different claims as supported by the trusted JWT issuer agent, refer to Configure a trusted JWT issuer agent.

      For more information about JWTs, refer to the RFC 7523 standard.

  3. The client includes the JWT and a client assertion type in the call to the OAuth 2.0 endpoint in the following parameters:

    • grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer

    • assertion=my-JWT

    For example:

    $ curl \
    --request POST \
    --data "client_id=myClient" \
    --data "client_secret=forgerock" \
    --data "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer" \
    --data "assertion=eyAiYWxnIjogIlJTMjU2IiB9.eyAic3ViIjogImp3…​"
    --data "redirect_uri=http://www.example.com" \
    --data "scope=write" \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"

    For information about the parameters supported by the /oauth2/access_token endpoint, refer to /oauth2/access_token.

    For information about client authentication methods, refer to OAuth 2.0 client authentication.

  4. AM validates the JWT following the guidance specified in section 3 of the RFC7523 and also performs the following additional checks:

    1. Decodes the payload and compares the value of the iss claim with the value of the JWT Issuer field in the list of trusted JWT issuer agents.

    2. Validates the JWT signature either with the keys exposed on the trusted issue agent’s JWK URI, or with the keys configured in the JWK Set field of the agent.

    If AM cannot validate the JWT it will return an error, such as JWT signature is invalid.

  5. The authorization server issues an access token to the client.

  6. The client requests access to the protected resources from the resource server.

  7. The resource server contacts the authorization server to validate the access token.

  8. The authorization server validates the token and responds to the resource server.

  9. If the token is valid, the resource server allows the client to access the protected resources.

Configure a trusted JWT issuer agent

Perform the steps in this procedure to configure a trusted JWT issuer agent:

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

  2. Add a new trusted JWT issuer agent.

  3. Complete the following fields to create the agent:

    • In the Agent ID field, give the trusted JWT issuer agent a name.

      For example, myJWTAgent.

    • In the JWT Issuer field, provide the URI of the JWT issuer.

      This URI must match the value of the issuer (the iss claim) in the JWTs.

    • Select Create.

      You are presented with a screen with additional information regarding the agent.

  4. Review the trusted JWT issuer agent information.

    You must, configure either the JWKs URI or the JWK Set fields, as follows:

    • JWKs URI: specifies a URI in the JWT issuer that exposes the verification keys that AM will use to validate the JWT signature. For example, http://www.example.com/issuer/jwk_uri.

      If you configure this field, ensure the following properties are configured with sensible values for your environment:

      • JWKs URI content cache timeout in ms

      • JWKs URI content cache miss cache time

    • JWK set: Specifies a JWK set containing the verification keys to validate the JWT signature.

      The following is an example of an elliptic curve JWK set:

      {
        "keys": [{
           "kty": "EC",
           "crv": "P-256",
           "x": "i-rdOmi5lC3pn3y5sTgYiLLFVFY7XxDLinWneHEaAXA",
           "y": "mxmqqauiq44INgyyPP2vATt3IkDL_6W5CAcfAMSZl8k",
           "kid": "signing_key",
           "x5c": [
               "MIIBSjCB76ADAgEC.....955PByPrflZkQOC/g==" ]
        }]
      }

      For more information about the contents of the JWK set, refer to the JSON Web Key (JWK) specification.

    You can store more than one key in the JWK set. However, it is easier to implement key rotation exposing the validation keys on the URI instead.

  5. Configure the following values to suit your environment:

    • Consented Scopes Claim. The name of a JWT claim that indicates which scopes the resource owner consented to. The claim in the JWT can contain either a JSON array or a space-separated allowlist of scopes that the resource owner has consented to.

      For example, if you configure the scp claim name in this field and the JWT contains the claim "scp":"read", but you request both the read and write scopes, AM will only grant the read scope.

      Leave this field blank to allow any scope.

      The following are example JWTs containing a claim that specifies scopes:

      {
         "aud": [
             "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"
         ],
         "iss": "https://www.example.com/issuer",
         "exp": 1555530663,
         "sub": "demo",
         "scope": ["read", "write"]
      }

      In this case, the scope claim is a JSON array of scopes.

      {
         "aud": [
             "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"
         ],
         "iss": "https://www.example.com/issuer",
         "exp": 1555530663,
         "sub": "demo",
         "scp": "read write"
      }

      In this case, the scp claim is a space-separated list of scopes.

    • Resource Owner Identity Claim. Claim in the JWT that identifies the resource owner in AM. By default, the sub claim.

      Note that even if you configure the trusted JWT issuer agent to verify a different claim, such as the preferred_username claim, the sub claim must still exist in the JWT.

    • Allowed Subjects. List of subjects this JWT issuer is allowed to provide consent for.

      For example, if you configure the demo user in this field but the JWT subject value is demo2, AM will not grant the access token.

      Leave it blank to provide consent to any user.

  6. Save your changes.

    The trusted JWT issuer agent is ready for use.

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

Token exchange

AM supports RFC 8693, OAuth 2.0 Token Exchange for OAuth 2.0 and OpenID Connect tokens:

Supported OAuth 2.0 token exchange
From/to Access token ID token Refresh tokens1 SAML assertion

Access token

ID token

1 You cannot exchange a token directly for a refresh token. When AM issues refresh tokens (default), it also issues them on token exchange.

Clients can exchange tokens only at the OAuth 2.0 provider that issued them.

This restriction applies to AM domains and to realms. For example, a token issued by https://openam.example.com/openam/oauth2 cannot be exchanged at https://am.example.com/am/oauth2.

Differences with normal token issuance:

  • AM copies claims and values that must not change, such as subject and issuer claims, from the subject token to the new token.

    AM ignores irrelevant claims, such as those missing from the resulting token type, and claims that cannot be inferred from the subject token, such as those present in the resulting token, but not in the subject token.

  • AM does not copy scopes, but derives them from the scope implementation.

    For details, refer to OAuth 2.0 scopes.

  • AM adds the act and may_act claims when relevant.

  • Token exchange involves no user interaction.

    There is no way to request consent for expanded scopes or claims. The client application must ensure user consent beforehand or must ensure an expanded scope or claim is unrelated to the user’s resources.

Use cases

OAuth2.0 clients exchange tokens for impersonation or delegation.

Impersonation

To impersonate means to pretend you are someone else when performing a job or duty.

Use impersonation for token exchange when it is not necessary to maintain separation between the user and the client.

The client obtains a subject token with the user’s authorization. It exchanges this token for a new token it can use directly to access a protected resource. Due to the risk of identity theft, allow token impersonation across trusted systems only.

To try token exchange with impersonation, refer to Demonstrate impersonation.
Example with an access token

A user chooses to transfer money using their bank application, an OAuth 2.0 client. The user authenticates to the application and trusts the application to act on their behalf when accessing the internal banking system to perform transactions. When the user authenticates, the application gets a subject token with change_data, create_accounts, read_accounts, and transfer scopes. The scopes represent all banking services available through the application.

The user chooses to transfer money, which requires only the transfer scope. To reduce the security risk, the application exchanges the broad-scope access token for a restricted access token with only the transfer scope, which it uses to access the transfer service:

oauth2-token-exchange-1
Example with an ID token

The client could request an ID token instead of an access token.

When the user authenticates, the application gets an ID token as the subject token. The ID token attests to the user’s identity and authorization, but does not include scopes to access banking services. The user chooses to transfer money, and the application exchanges the ID token for an expanded access token with the transfer scope, which it uses to access the transfer service:

oauth2-token-exchange-2

Delegation

To delegate means to give a job or duty to someone else who performs the job on your behalf.

Use delegation for token exchange when maintaining separation between the user and the client is important. This approach is more secure when the token must traverse third-party systems.

To try token exchange with delegation, refer to Demonstrate delegation.

In delegation, the client has two tokens:

  • A subject token obtained with the user’s authorization.

  • An actor token obtained for itself or a user it represents.

The client exchanges both tokens for a new token it can use to access the protected resource.

The new token has an act (actor) claim. The act claim, visible on introspection, signals to the resource server that the client using the token is not the user. A resource server can adapt its behavior as necessary.

The following example shows the act claim field of an access token:

"act": {
  "sub": "(act!delegateClient)"
}

The sub field specifies the subject of the actor token.

Example with an actor access token

A user phones a call center about a problem with their water supply. The operator who responds verifies the user’s identity and creates an ID token as the subject token. The operator also creates an access token as the actor token for themselves.

The operator exchanges both tokens for an access token with the repair scope restricted to booking a repair. The operator would need a different token to end the user’s contract, for example. When they book a repair for the user, both the operator and the user are reflected in the repair request:

oauth2-token-exchange-3
Example with an actor ID token

The operator could request an actor ID token instead of an access token:

oauth2-token-exchange-4

Terminology

Act claim

Token claim identifying a delegate acting on behalf of another identity.

AM automatically adds this claim as needed when issuing a token.

Actor token

The access or ID token representing a delegate acting on behalf of another identity.

Exchanged token

The new access or ID token resulting from token exchange.

Exchanged tokens do not expire at the same time as their subject tokens. They expire after the amount of time specified in the Access Token Lifetime (seconds) or the OpenID Connect JWT Token Lifetime (seconds) settings of the OAuth 2.0 provider service or client configuration.

Expanded token

An access token with scopes or claims not present in the subject token.

An exchanged token can have different scopes and claims from the subject token. Expanded tokens work well when exchanging ID tokens for access tokens, for example, where scopes and claims differ.

May act claim

Token claim specifying who is allowed to act for the identity on behalf of whom the request is made.

Only the identity specified in the may_act claim can exchange tokens for another token.

You must write a script to add this claim as needed when issuing a token. For details, refer to Authorize exchange.

Restricted token

An access token with narrower scopes or claims than those of the subject token.

Instead of gathering consent for different sets of scopes and claims, clients gather consent for a broad range initially and then restrict scope during token exchange.

Subject token

The access or ID token representing the identity on behalf of whom the request is made.

The client can obtain the subject token with any supported OAuth 2.0 or OpenID Connect flow.

Configuration

Token exchange configuration requires:

  • A script to authorize exchange.

  • Settings in the OAuth 2.0 provider or the OAuth 2.0 client application configuration.

Authorize exchange

A claim on the original token authorizes specified clients and actors to perform the exchange.

You write a script AM runs when issuing tokens to set the claim.

The may_act claim

The may_act claim on a token identifies the authorized actor who can exchange the token. AM sets this claim when issuing the original token.

  • For impersonation, the may_act claim must specify the client ID of the authorized actor.

  • For delegation, the may_act claim must specify the client ID and the sub (subject) of the actor token.

AM rejects token exchange requests from clients or actors who are not authorized by the may_act claim.

The following example claim allows:

  • An impersonationClient to exchange the token and impersonate the user.

  • A delegateClient to exchange the token to act on the user’s behalf using the original token and an actor token issued directly to the client with the client credentials grant.

"may_act": {
  // String or array of client IDs who can exchange the token:
  "client_id": ["impersonationClient", "delegateClient"],
  // String or array identifying the actor token subject(s) for delegation:
  "sub": "(age!delegateClient)"
}

The subject ("sub") claim has the format (type!subject), where:

  • subject is the ID for the identity, such as a username or a client ID.

  • type can be one of the following:

    • age. Specifies that the subject is an OAuth 2.0/OpenID Connect-related user-agent or client. For example, an OAuth 2.0 client, a Remote Consent Service agent, and a Web and Java Agent internal client.

    • usr. Specifies that the subject is a user/identity.

The subject claim (age!delegateClient) specifies the delegateClient OAuth 2.0 client application. An example user subject claim is (usr!bjensen).

May act scripts

AM has no default functionality to authorize token exchange for specific clients.

Instead, AM uses a script you write to set the may_act claim. The script runs when issuing a token. It is an OAuth2 May Act type script.

The following example JavaScript produces the previous example claim without the comments:

(function () {
    var frJava = JavaImporter(
        org.forgerock.json.JsonValue
    );

    var mayAct = frJava.JsonValue.json(frJava.JsonValue.object())
    mayAct.put('client_id', ['impersonationClient', 'delegateClient'])
    mayAct.put('sub', '(age!delegateClient)')
    token.setMayAct(mayAct)
}());

For a commented example, refer to the sample may act script.

AM does not support wildcards in the client_id and sub fields. Your scripts must enumerate clients and actors.

The script does not specify the token type. The client requesting an exchange token optionally specifies the token type.

May act script variables

AM binds the following variables into OAuth2 May Act scripts:

clientProperties

A map of properties configured in the relevant client profile. Only present if AM correctly identified the client.

The keys in the map are as follows:

clientId

The URI of the client.

allowedGrantTypes

The list of the allowed grant types for the client. For details, refer to the Javadoc for GrantType.

allowedResponseTypes

The list of the allowed response types for the client.

allowedScopes

The list of the allowed scopes for the client.

customProperties

A map of any custom properties added to the client.

These properties can include lists or maps as sub-maps. For example, the script includes customMap[Key1]=Value1 as customMap > Key1 > Value1 in the object.

To add custom properties to a client, use the AM admin UI. Go to OAuth 2.0 > Clients > Client ID > Advanced, and update the Custom Properties field.

identity

Contains a representation of the identity of the resource owner.

logger

Write a message to the AM debug log.

AM logs token exchange operations under the AM-TOKEN-EXCHANGE audit event. You can track new tokens using the value of their auditTrackingId claim.

requestProperties

A map of the properties present in the request. Always present.

The keys in the map are as follows:

requestUri

The URI of the request.

realm

The realm to which the request was made.

requestParams

The request parameters and posted data. Each value in this map is a list of one or more properties.

To mitigate the risk of reflection-type attacks, use OWASP best practices when handling these properties.

scopes

Contains a set of the requested scopes. For example:

[ "read", "transfer", "download" ]
scriptName

The display name of the script. Always present.

session

Contains a representation of the user’s session object if the request contained a session cookie.

token

Contains a representation of the token to be updated. The token is a mutable object; changes update the resulting token.

Use the token.setMayAct(JsonValue value) method to add a may_act claim to a token.

OAuth 2.0 provider settings

The OAuth 2.0 provider settings govern token exchange behavior for all clients in the realm. To access the settings in the AM admin UI, go to Realms > Realm Name > Services > OAuth2 Provider.

The relevant settings are:

Core tab
  • OAuth2 Access Token May Act Script: Use the selected script to set the may_act claim on all access tokens.

  • OIDC ID Token May Act Script: Use the selected script to set the may_act claim on all ID tokens.

Choose --- Select a script --- to prevent AM from setting the claim.

Advanced tab
  • Grant Types: Add the Token Exchange type to permit token exchange requests.

  • Token Exchanger Plugins: Remove any token exchange combinations you do not want to allow.

  • Token Validator Plugins: If necessary, remove validations that tokens meet the criteria for exchange.

Client settings

Individual OAuth 2.0 client settings govern authentication levels granted to exchanged tokens and can override OAuth 2.0 provider settings. To access the settings in the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID.

The relevant settings are:

Advanced tab
  • Token Exchange Auth Level: The authentication level granted to exchanged tokens when the subject token had no auth_level claim. This setting always applies to exchanged ID tokens.

  • Grant Types: Add the Token Exchange type to permit token exchange requests.

OAuth2 Provider Overrides tab
  • Enable OAuth2 Provider Overrides: Use these settings instead of those on the OAuth2 Provider service.

  • OAuth2 Access Token May Act Script: Use the selected script to set the may_act claim on access tokens.

  • OIDC ID Token May Act Script: Use the selected script to set the may_act claim on ID tokens.

For the may act script settings, choose --- Select a script --- to prevent AM from setting the claim.

Request parameters

Token exchange requests target the /oauth2/access_token endpoint. The requests use the following specific parameters:

Parameter Description

grant_type

Required.

Use grant_type=urn:ietf:params:oauth:grant-type:token-exchange.

subject_token

Required.

The original token to exchange.

Example: subject_token=RzOn3NbDyebd5hFVvzVrE2kox1A-lQ

subject_token_type

Required.

The type of subject token, either access token or ID token. One of:

  • subject_token_type=urn:ietf:params:oauth:token-type:access_token

  • subject_token_type=urn:ietf:params:oauth:token-type:id_token

actor_token

Required for delegation.

The token representing the delegate.

Example: actor_token=wNv5kr5QaugeY2IqptR3Zg7AEvg

actor_token_type

Required for delegation.

The type of actor token, either access token or ID token. One of:

  • actor_token_type=urn:ietf:params:oauth:token-type:access_token

  • actor_token_type=urn:ietf:params:oauth:token-type:id_token

requested_token_type

Optional.

The type of requested exchanged token, either access token or ID token. One of:

  • requested_token_type=urn:ietf:params:oauth:token-type:access_token (default)

  • requested_token_type=urn:ietf:params:oauth:token-type:id_token

Token exchange and the security token service

Both OAuth 2.0 and the AM security token service (STS) transform tokens.

The implementations and capabilities are different:

  • The STS service lets AM establish cross-domain trust federation relationships. To do this, AM provides a REST STS framework loosely based on the SOAP WS-Trust specification.

    You must build, deploy, and maintain the STS service yourself.

    The REST STS service supports username/password, SSO tokens, X.509 certificates, and ID tokens as input tokens, and SAML v2.0 assertions and ID tokens as output tokens.

    Due to its transformation capabilities, the STS service is more suitable to helping federate legacy platforms.

  • The OAuth 2.0 token exchange specification uses the OAuth 2.0 provider service to transform OAuth 2.0-related tokens.

    Use the OAuth 2.0 token exchange in OAuth 2.0/OpenID Connect platforms.

Demonstrate impersonation

This page demonstrates token exchange with impersonation.

Prepare the demonstration

Start by preparing the demonstration:

May act script

The script adds a may_act claim to the subject token.

  1. In the AM admin UI, select Realm > Realm Name > Scripts + New Script.

  2. In the New Script window, name the script May act and set Script Type to OAuth2 May Act.

  3. In the edit window, save the following JavaScript:

    (function () {
        var frJava = JavaImporter(
            org.forgerock.json.JsonValue
        );
    
        var mayAct = frJava.JsonValue.json(frJava.JsonValue.object())
        mayAct.put('client_id', 'impersonationClient')
        token.setMayAct(mayAct)
    }());

    This script generates a may_act claim to permit the impersonating actor client to exchange the subject token.

Subject client

The OAuth 2.0 client profile in this example overrides the AM OAuth 2.0 provider settings. This lets you test the script without affecting access tokens issued to other clients.

  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

    Scopes

    change_data
    create_accounts
    read_accounts
    transfer

  2. Switch to the Advanced tab, enable Implied consent, and save your work:

  3. Override OAuth 2.0 provider settings for this client.

    Switch to the OAuth2 Provider Overrides tab, update the following settings and save your work:

    Enable OAuth2 Provider Overrides

    Enabled

    OAuth2 Access Token May Act Script

    May act

    OIDC ID Token May Act Script

    May act

Actor client

Create a confidential OAuth 2.0 client account for the service that acts on behalf of the user.

  1. In the AM admin UI, select Realm > Realm Name > Applications > OAuth 2.0 > Clients > + Add Client.

  2. Create a new confidential client with the following settings:

    Client ID

    impersonationClient

    Client Secret

    forgerock

    Grant Types

    Client Credentials
    Refresh Token
    Token Exchange

    Scopes

    transfer

Resource owner

An OAuth 2.0 client requests the access token on behalf of a resource owner.

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

  2. Record the username and password.

Test the demonstration

After preparing the demonstration, test your work using HTTP calls to REST endpoints.

The demonstration uses the Authorization code grant flow followed by token exchange:

  • The resource owner authenticates to obtain an SSO token.

  • The subject client relies on Implied Consent being enabled. It assumes the resource owner grants the client access.

  • The subject client requests the authorization code and exchanges it for an access token. Your script sets the may_act claim in the access token.

  • The actor client exchanges the subject token for an access token.

Follow these steps:

  1. Authenticate as the resource owner:

    curl \
    --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://openam.example.com:8443/openam/json/realms/root/realms/alpha/authenticate'
    {"tokenId":"<resource-owner-tokenId>","successUrl":"/openam/console","realm":"/alpha"}
  2. Request the authorization code as the subject client:

    curl \
    --dump-header - \
    --request POST \
    --Cookie 'iPlanetDirectoryPro=<resource-owner-tokenId>' \
    --data 'scope=change_data create_accounts read_accounts transfer' \
    --data 'response_type=code' \
    --data 'client_id=myClient' \
    --data 'csrf=<resource-owner-tokenId>' \
    --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'
    …​
    location: https://www.example.com:443/callback?code=<authorization-code>&iss=https%3A%2F%2F…​
    …​
  3. Exchange the authorization code for an access token as the subject client:

    curl \
    --request POST \
    --user 'myClient:forgerock' \
    --data 'grant_type=authorization_code' \
    --data 'code=<authorization-code>' \
    --data 'redirect_uri=https://www.example.com:443/callback' \
    'https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token'
    {
      "access_token": "<access-token>",
      "refresh_token": "<refresh-token>",
      "scope": "change_data transfer create_accounts read_accounts",
      "token_type": "Bearer",
      "expires_in": 3599
    }

    Your script has set the may_act claim, which is not directly visible. To see the may_act claim, you must introspect the access token.

  4. Request an exchanged token as the actor client:

    curl \
    --request POST \
    --user 'impersonationClient:forgerock' \
    --data 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
    --data 'scope=transfer' \
    --data 'subject_token=<access-token>' \
    --data 'subject_token_type=urn:ietf:params:oauth:token-type:access_token' \
    'https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token'
    {
      "access_token": "<exchanged-token>",
      "refresh_token": "<new-refresh-token>",
      "issued_token_type": "urn:ietf:params:oauth:token-type:access_token",
      "scope": "transfer",
      "token_type": "Bearer",
      "expires_in": 3599
    }

    The issued_token_type shows this is an exchanged token.

Demonstrate delegation

This page demonstrates token exchange with delegation.

Prepare the demonstration

Start by preparing the demonstration:

May act script

The script adds a may_act claim to the subject token.

  1. In the AM admin UI, select Realm > Realm Name > Scripts + New Script.

  2. In the New Script window, name the script May act and set Script Type to OAuth2 May Act.

  3. In the edit window, save the following JavaScript:

    (function () {
        var frJava = JavaImporter(
            org.forgerock.json.JsonValue
        );
    
        var mayAct = frJava.JsonValue.json(frJava.JsonValue.object())
        mayAct.put('client_id', 'delegateClient')
        mayAct.put('sub', '(act!delegateClient)')
        token.setMayAct(mayAct)
    }());

    This script generates a may_act claim to permit the delegate actor client to exchange the subject token, provided it also supplies an actor token where it is the subject.

Subject client

The OAuth 2.0 client profile in this example overrides the AM OAuth 2.0 provider settings. This lets you test the script without affecting access tokens issued to other clients.

  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

    Scopes

    change_contract
    repair

  2. Switch to the Advanced tab, enable Implied consent, and save your work:

  3. Override OAuth 2.0 provider settings for this client.

    Switch to the OAuth2 Provider Overrides tab, update the following settings, and save your work:

    Enable OAuth2 Provider Overrides

    Enabled

    OAuth2 Access Token May Act Script

    May act

    OIDC ID Token May Act Script

    May act

Actor client

Create a confidential OAuth 2.0 client account for the service that acts on behalf of the user.

  1. In the AM admin UI, select Realm > Realm Name > Applications > OAuth 2.0 > Clients > + Add Client.

  2. Create a new confidential client with the following settings:

    Client ID

    delegateClient

    Client Secret

    forgerock

    Grant Types

    Client Credentials
    Refresh Token
    Token Exchange

    Scopes

    repair

Resource owner

An OAuth 2.0 client requests the access token on behalf of a resource owner.

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

  2. Record the username and password.

Test the demonstration

After preparing the demonstration, test your work using HTTP calls to REST endpoints.

The demonstration uses the Authorization code grant and and Client credentials grant flows followed by token exchange:

  • The resource owner authenticates to obtain an SSO token.

  • The subject client relies on Implied Consent being enabled. It assumes the resource owner grants the client access.

  • The subject client requests the authorization code and exchanges it for an access token. Your script sets the may_act claim in the access token.

  • The actor client requests an actor token with its client credentials.

  • The actor client exchanges the subject token and actor token for an ID token.

Follow these steps:

  1. Authenticate as the resource owner:

    curl \
    --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://openam.example.com/openam/json/realms/root/realms/alpha/authenticate'
    {"tokenId":"<resource-owner-tokenId>","successUrl":"/openam/console","realm":"/alpha"}
  2. Request the authorization code as the subject client:

    curl \
    --dump-header - \
    --request POST \
    --Cookie 'iPlanetDirectoryPro=<resource-owner-tokenId>' \
    --data 'scope=change_contract repair' \
    --data 'response_type=code' \
    --data 'client_id=myClient' \
    --data 'csrf=<resource-owner-tokenId>' \
    --data 'redirect_uri=https://www.example.com:443/callback' \
    --data 'state=abc123' \
    --data 'decision=allow' \
    'https://openam.example.com/openam/oauth2/realms/root/realms/alpha/authorize'
    …​
    location: https://www.example.com:443/callback?code=<authorization-code>&iss=https%3A%2F%2F…​
    …​
  3. Exchange the authorization code for an access token as the subject client:

    curl \
    --request POST \
    --user 'myClient:forgerock' \
    --data 'grant_type=authorization_code' \
    --data 'code=<authorization-code>' \
    --data 'redirect_uri=https://www.example.com:443/callback' \
    'https://openam.example.com/openam/oauth2/realms/root/realms/alpha/access_token'
    {
      "access_token": "<subject-access-token>",
      "refresh_token": "<refresh-token>",
      "scope": "change_contract repair",
      "token_type": "Bearer",
      "expires_in": 3599
    }

    Your script has set the may_act claim, which is not directly visible. To see the may_act claim, you must introspect the access token.

  4. Request an access token as the actor client:

    curl \
    --request POST \
    --user 'delegateClient:forgerock' \
    --data 'grant_type=client_credentials' \
    --data 'scope=repair' \
    'https://openam.example.com/openam/oauth2/realms/root/realms/alpha/access_token'
    {"access_token":"<actor-access-token>","scope":"repair","token_type":"Bearer","expires_in":3599}
  5. Request an exchanged token as the actor client:

    curl \
    --request POST \
    --user 'delegateClient:forgerock' \
    --data 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
    --data 'scope=repair' \
    --data 'subject_token=<subject-access-token>' \
    --data 'subject_token_type=urn:ietf:params:oauth:token-type:access_token' \
    --data 'actor_token=<actor-access-token>' \
    --data 'actor_token_type=urn:ietf:params:oauth:token-type:access_token' \
    --data 'requested_token_type=urn:ietf:params:oauth:token-type:id_token' \
    'https://openam.example.com/openam/oauth2/realms/root/realms/alpha/access_token'
    {
      "access_token": "<exchanged-id-token>",
      "refresh_token": "<new-refresh-token>,"
      "issued_token_type": "urn:ietf:params:oauth:token-type:id_token",
      "scope": "repair",
      "token_type": "Bearer",
      "expires_in": 3599
    }

    The issued_token_type shows this is an exchanged token.

OAuth 2.0 endpoints

Client applications can use the following OAuth 2.0 authorization server endpoints:

Endpoint Description

Register a pushed authorization request and get a request URI (RFC 9126 PAR endpoint)

Obtain consent and an authorization grant (RFC 6749 authorization endpoint)

Initiate backchannel authorization (Backchannel flow endpoint)

Obtain an access token (RFC 6749 token endpoint)

Obtain a device code (Device flow endpoint)

Obtain consent and authorization grant (Device flow endpoint)

Revoke access tokens and refresh tokens (RFC 7009 endpoint)

Retrieve metadata about a token, such as approved scopes and the context in which the token was issued (RFC 7662 endpoint)

Retrieve metadata about a macaroon, and add caveats.

For reference documentation on related endpoints, refer to:

OAuth 2.0 endpoint parameters

Requests to OAuth 2.0 endpoints use the following parameters.

Refer to the individual OAuth 2.0 endpoint pages to determine the required and optional parameters for each endpoint.

acr_values

The OpenID Connect authentication context class reference values. OpenID Connect (OIDC) flows only.

Authentication context class reference values communicate acceptable Levels of Assurance (LoAs) users must satisfy when authenticating to the OpenID provider. For details, refer to Authentication requirements.

actor_token

The token representing a delegate acting on behalf of another identity in Token exchange.

actor_token_type

The type of the actor token:

  • urn:ietf:params:oauth:token-type:access_token

  • urn:ietf:params:oauth:token-type:id_token

auth_chain

A string naming the journey or chain to authenticate the resource owner for Resource owner password credentials grant. The journey or chain must permit username-password authentication without UI interaction. Otherwise, the request results in an HTTP 500 Internal Server Error.

Default: The default authentication journey or chain for the realm.

claims

A JSON object containing the user attributes to return in the ID token. OIDC flows only.

client_assertion

A signed JSON Web Token (JWT) to use as client credentials for JWT profile authentication.

client_assertion_type

The type of assertion for JWT profile authentication.

Set client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer.

client_id

A unique string identifier for the application making the request.

For a pushed authorization request or a JWT-secured authorization request (RFC 9101), this value must match the client_id claim in the request object.

client_secret

A string password credential for the confidential client application making the request.

Use this parameter for client authentication with Form parameters (HTTP POST).

Do not use with the cnf_key parameter.

cnf_key

A base64-encoded JSON Web Key (JWK) for JWK-based proof-of-possession or a base64-encoded SHA-256 hash of the DER-encoded X.509 certificate for Certificate-bound proof-of-possession.

Do not use with the client_secret parameter.

code_challenge

A generated code verifier string for RFC 7636 Proof Key for Code Exchange (PKCE).

code_challenge_method

A string specifying the method to derive the PKCE code challenge:

  • plain (default; plaintext code challenge )

  • S256 (recommended; hashed code challenge)

code_verifier

A random string correlating a PKCE authorization request with the token request.

csrf

The SSO token string linking the request to user session to protect against Cross-Site Request Forgery (CSRF) attacks.

This parameter duplicates the value of the session cookie, the resource owner’s SSO token.

Built-in consent pages include this parameter once the resource owner has authenticated, and send it with the resource owner’s consent. Custom consent pages and flows that do not use a browser must set this parameter explicitly unless you use a Remote consent. For an example, refer to the Authorization code grant.

decision

A string indicating whether the resource owner consents to the requested access:

  • allow to grant consent

  • Any other value denies consent

grant_type

A string specifying the type of grant to acquire an access token:

authorization_code

For authorization code grants.

client_credentials

For the Client credentials grant.

password

For the Resource owner password credentials grant.

refresh_token

To refresh an access token.

urn:ietf:params:oauth:grant-type:device_code

For the Device flow. AM also supports the earlier http://oauth.net/grant_type/device/1.0 specification.

urn:ietf:params:oauth:grant-type:saml2-bearer

For the SAML v2.0 profile for authorization grant.

urn:ietf:params:oauth:grant-type:jwt-bearer

For the JWT profile for OAuth 2.0 authorization grant.

urn:ietf:params:oauth:grant-type:token-exchange

For the Token exchange.

urn:ietf:params:oauth:grant-type:uma-ticket

For the UMA grant flow.

urn:openid:params:grant-type:ciba

For the Backchannel request grant.

id_token_hint

A previously issued ID token passed as a hint about the end user’s session with the client. OIDC flows only.

Set the response_type and prompt parameters to none when using this parameter. For details, refer to Session Management Draft 10.

login_hint

A string specifying the ID used to log in. OIDC flows only.

The ID depends on the authentication journey.

When provided as part of the OpenID Connect authentication request, an HttpOnly cookie (only sent over HTTPS) named oidcLoginHint gets the value of login_hint. For details, refer to GSMA Mobile Connect.

nonce

A string linking the client session with the ID token to mitigate against replay attacks. OIDC flows only.

prompt

A space-separated, case-sensitive list of ASCII strings that indicates whether to prompt the end user for authentication and consent. OIDC flows only.

consent

Prompt the end user for consent even if a consent response was previously saved.

login

Prompts the end user to authenticate using the journey or chain specified with the service parameter. When the user re-authenticates with a:

  • Journey: AM destroys the original session and creates a new one for the new journey.

  • Chain: AM updates the original session to reflect the new authentication state.

Default: The default journey or chain for the realm.

none

Do not display authentication or consent pages. Use this only when you set id_token_hint and response_type=none.

redirect_uri

The URI to return the resource owner to after authorization is complete.

Default: A value from the client profile Redirection URIs setting in the AM admin UI.

response_mode

A string specifying the mechanism for returning response parameters:

form_post

Return a self-submitting form that contains the code instead of redirecting to the redirect URL with the code as a string parameter. For details, refer to OAuth 2.0 Form Post Response Mode.

fragment

Return parameters encoded in the URL fragment; default when response_type=token.

fragment.jwt

Return a JWT in a fragment.

jwt

Return parameters in a JWT; in a query string for the code response type, or appended to the fragment for the token response type.

A JWT-secured authorization response (JARM) returns authorization response parameters in a signed, optionally encrypted, JWT.

Configure the algorithms to secure the JWT in the AM admin UI under Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Signing and Encryption.

In addition to claims specific to the response type, such as code or access_token, the JWT contains these mandatory claims:

  • iss: the URL of the issuer—​the authorization server that generated the response

  • aud: the audience—​the client ID intended as the response recipient

  • exp: the expiration of the JWT—​10 minutes is the recommended maximum

On error, the JWT contains:

  • An error string

  • A state string if specified by the client

  • An error description

query

Return parameters encoded in the query string; default when response_type=code.

query.jwt

Return a JWT in a query parameter. Do not use this with id_token or token response types unless the response JWT is encrypted.

For details, refer to Response Modes. AM publishes supported response modes as response_modes_supported through the /oauth2/.well-known/openid-configuration endpoint.

response_type

A string specifying the response expected from the authorization server:

code

An authorization code for an authorization code grant

code id_token

An authorization code and an ID token for a hybrid grant

code token

An authorization code and an access token for a hybrid grant

code token id_token

An authorization code, an access token, and an ID token for a hybrid grant

id_token

An ID token for an implicit grant

none

Do not issue any token or code in the response; for use with id_token_hint only

token

An access token for an implicit grant

token id_token

An access token and an ID token for an implicit grant

request

A base64url-encoded JWT whose claims are required for an OIDC flow, a JWT-secured authorization (JAR) request (RFC 9101), or a pushed authorization request (PAR) (RFC 9126).

This JWT is called the request object.

Request object validation rules depend on the type of request and the OAuth 2.0 provider configuration. The validation rules apply whether you pass the request object by value with the request parameter or as a reference with the request_uri parameter:

General validation rules

These rules apply for all request objects:

  • If the request object is signed or encrypted, you must include the iss and aud parameters, as shown in the Example request object.

    For the public keys to encrypt a request object JWT, make a request to the realm’s /oauth2/connect/jwk_uri endpoint.

  • The exp (expiration time) and nbf (not before) claims set the timeframe when the request object is valid.

    If the OAuth 2.0 provider settings declare them mandatory, you must include the exp and nbf claims.

    If specified, validation uses these claims even when the OAuth 2.0 provider settings do not require them.

    To ensure the values meet the requirements for the Financial-grade API (FAPI) security profile, refer to the OAuth 2.0 provider configuration reference.

  • Compressed JWTs must not be larger than 32 KiB (32768 bytes) when uncompressed.

JAR validation rules

These rules apply when the request object does not contain OIDC-specific parameters or when the OAuth 2.0 provider setting Request Object Processing Specification specifies JAR processing:

  • The request object must be signed. It may be encrypted.

  • The request object must include a client_id matching the client_id parameter of the request.

  • The authorization request uses only the request object claims, even when the request specifies the same claims in query string parameters.

OIDC validation rules

These rules apply for OIDC requests when the OAuth 2.0 provider setting Request Object Processing Specification specifies OIDC (default):

  • The request object does not require signing or encryption.

  • You may send query string parameters and a request object in the same request.

    You can keep sensitive information protected in the request object, and keep parameters that change frequently, such as nonce and state, visible and mutable across calls.

    The claims in the request object supersede the query string parameters.

  • You must include the response_type and client_id as query string parameters, even if you include them in the request object.

    Their values in the request object must match those passed as query string parameters.

  • You must include the openid scope as a query string parameter, even if you include it in the request object.

    The scope claim may differ from the scope query string parameter. Use this to protect application-related scopes in the request object, but process the request as part of an OpenID Connect flow.

PAR validation rules

These rules apply for pushed authorization request objects:

  • The request object must be signed. It may be encrypted.

  • You must include the client_id even though it is also a required query string parameter.

  • The response_type claim in the request object passed by value takes the place of the response_type query string parameter.

  • You must include claims for all other parameters required for the successful completion of the grant flow.

    For example, include the code_challenge for an Authorization code grant with PKCE flow.

  • When you include the request object, omit all other parameters except to authenticate the client.

    The request object must include claims for all other request details. Otherwise, the response is an Invalid parameter scope error.

Example request object

The following example JWT request object includes OIDC claims and iss, aud, nbf, and exp claims. AM ignores keys specified in JWT headers, such as jku and jwe:

{
  "client_id": "myClient",
  "iss": "myClient",
  "aud": "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha",
  "nbf": 1675351332,
  "exp": 1675351692,
  "redirect_uri": "https://www.example.com:8443",
  "scope": "openid profile",
  "claims": {
    "id_token": {
      "acr": {
        "essential": true,
        "values": ["example_journey1", "example_journey2"]
      }
    }
  }
}

To pass the request object by value, specify the encoded JWT as shown in this example OIDC call:

https://openam.example.com:8443/openam/oauth2/realms/root/authorize? \
&request=eyJhbGciOiJSUzI1NiIsImtpZCI6ImsyYmRjIn0.ew0KICJpc3MiOiAiczZCaGRSa3.... \
&client_id=myClient \
&scope=openid profile \
&response_type=code%20id_token \
&nonce=abc123 \
&state=123abc

request_uri

A reference to JWT request object(s).

  • For PAR flows, this references the data at the time of the PAR request.

    The authorization request fails if the request URI has expired.

  • For OIDC flows and JAR requests, this references an array of URIs to retrieve request objects whose claims constitute the request parameters.

    You must pre-register the URIs in the client profile. In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Advanced > Request uris. Each request URI must not exceed 512 ASCII characters and must use either HTTP or HTTPS; for example, https://www.example.com:8443/JWTs/myJWT.

    AM caches the request objects to avoid requesting them too often. To force AM to flush the cache, add a unique fragment to the request_uri parameter; for example, ?request_uri=https://www.example.com:8443/JWTs/myJWT#foo.

requested_token_type

The type of token requested for Token exchange:

  • urn:ietf:params:oauth:token-type:access_token (default)

  • urn:ietf:params:oauth:token-type:id_token

save_consent=on means save the scopes the resource owner’s consented to.

Saving consent requires prior configuration. For details, refer to Store consent decisions.

scope

A string specifying the permissions the client application requests from the resource owner. Separate scopes with spaces.

Some grants, such as the authorization code grant, do not call the token endpoint with the scope. The scope is defined in the authorization code. For details, refer to the documentation for the flow under OAuth 2.0 grant flows.

Default: The default scopes specified in the client profile or the OAuth 2.0 provider configuration.

service

A string naming the journey or chain to authenticate the resource owner.

Default: The default authentication journey or chain for the realm.

For details, refer to Authentication parameters.

state

A string value to maintain state between the request and the callback.

During authentication, the client sends this parameter to the authorization server. The authorization server sends it back unchanged in the response.

Use the value to ensure the response belongs to the user who initiated the requests. This mitigates against CSRF attacks.

Use a base64-encoded string of data that is unique to a user and to this request.

subject_token

The original token to exchange in Token exchange.

subject_token_type

The type of the subject token:

  • urn:ietf:params:oauth:token-type:access_token

  • urn:ietf:params:oauth:token-type:id_token

ui_locales

A string indicating the end user’s preferred languages for the user interface. OIDC flows only.

The ui_locales parameter is a space-separated list ordered by preference; for example, en fr-CA fr.

/oauth2/par

The /oauth2/par endpoint is the OAuth 2.0 pushed authorization request (PAR) endpoint defined in RFC 9126.

Use this endpoint to push an authorization request payload directly to the authorization server for the following flows:

Specify the realm in the request URL; for example:

https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/par

The PAR endpoint supports the following parameters:

Parameter Description Required

acr_values

The OpenID Connect authentication context class reference values.

Yes, if required by the OpenID Connect provider

claims

The user attributes to be returned in the ID token.

No

client_assertion

A signed JSON Web Token (JWT) to use as client credentials.

Yes, for JWT profile authentication

client_assertion_type

The type of assertion, client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer.

Yes, for JWT profile authentication

client_id

Uniquely identifies the application making the request.

Yes, even when it is also included in a request object

client_secret

The password for a confidential client.

Yes, when authenticating with Form parameters (HTTP POST)

code_challenge

The code verifier generated for the PKCE flow.

Yes, for confidential clients and for all clients using the Authorization code grant with PKCE flow

code_challenge_method

The method to derive the code challenge.

Yes, when the code_challenge is hashed (recommended)

csrf

The SSO token string linking the request to the user session to protect against Cross-Site Request Forgery attacks.

Yes, when gathering consent without a remote consent service

decision

Specifies whether the resource owner consents to the requested access.

Yes, when gathering consent unless consent is already saved for the scope

id_token_hint

Previously issued ID token previously passed as a hint about the end user’s session with the client.

No

login_hint

String value that can be set to the ID the user uses to log in.

No

nonce

String value that associates the client session with the ID token.

No

prompt

Specifies whether to prompt the end user for authentication and consent.

No

redirect_uri

The URI to return the resource owner to after authorization is complete.

No

request

A base64url-encoded JWT with the claims required for PAR validation.(1)

Yes

response_mode

Specifies the mechanism for returning response parameters.

No

response_type

The type of response expected from the authorization server.

Yes

save_consent

Specifies whether to store a resource owner’s consented scopes.

No

scope

The scopes linked to the permissions requested by the client from the resource owner.

No

service

The authentication journey to use when authenticating the resource owner.

No

state

The value to maintain state between the request and the callback.

No, but strongly recommended

ui_locales

The end user’s preferred languages for the user interface.

No

(1) When you use a request object, define all the request parameters as claims in the JWT. Use only the following client authentication parameters alongside the request:

client_assertion
client_assertion_type
client_id
client_secret

Otherwise, the response is an Invalid parameter scope error.

The following is an example of a PAR request object:

{
  "client_id": "myClient",
  "nbf": 1594140030,
  "redirect_uri": "https://www.example.com:8443",
  "scope" : "write",
  "exp": 1594140390,
  "response_type" : "code",
  "code_challenge" :  "QR1D-7w1-rOQvlFe1CeqZigqaIpmZXatDMVvZ50o",
  "code_challenge_method" : "S256"
}

/oauth2/authorize

The /oauth2/authorize endpoint is the OAuth 2.0 authorization endpoint defined in RFC 6749.

Use this endpoint to gather consent and authorization from the resource owner for the following flows:

Specify the realm in the request URL; for example:

https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/authorize

The authorization endpoint supports the following parameters:

Parameter Description Required

acr_values

The OpenID Connect authentication context class reference values.

Yes, if required by the OpenID Connect provider

claims

The user attributes to be returned in the ID token.

No

client_id

Uniquely identifies the application making the request.

Yes

code_challenge

The code verifier generated for the PKCE flow.

Yes, for the Authorization code grant with PKCE flow

code_challenge_method

The method to derive the code challenge.

Yes, when the code_challenge is hashed (recommended)

csrf

The SSO token string linking the request to the user session to protect against Cross-Site Request Forgery attacks.

Yes, when gathering consent without a remote consent service

decision

Specifies whether the resource owner consents to the requested access.

Yes, when gathering consent unless consent is already saved for the scope

id_token_hint

Previously issued ID token passed as a hint about the end user’s session with the client.

No

login_hint

String value that can be set to the ID the user uses to log in.

No

nonce

String value that associates the client session with the ID token.

No

prompt

Specifies whether to prompt the end user for authentication and consent.

No

redirect_uri

The URI to return the resource owner to after authorization is complete.

No

response_mode

Specifies the mechanism for returning response parameters.

No

response_type

The type of response expected from the authorization server.

Yes

request

The JWT request object.

Yes, for JAR request and OIDC flows requiring a request object and providing no request_uri

request_uri

For PAR or OIDC flows, a reference to JWT request object(s).

Yes, for JAR request and OIDC flows requiring a request object and providing no request

save_consent

Specifies whether to store a resource owner’s consented scopes.

No

scope

The scopes linked to the permissions requested by the client from the resource owner.

No

service

The authentication journey to use when authenticating the resource owner.

No

state

The value to maintain state between the request and the callback.

No, but strongly recommended

ui_locales

The end user’s preferred languages for the user interface.

No

/oauth2/bc-authorize

The /oauth2/bc-authorize endpoint is the backchannel authorization endpoint for OpenID Connect Client Initiated Backchannel Authentication Flow.

Use this endpoint to initiate backchannel authorization with the resource owner with the following flow:

Specify the realm in the request URL; for example:

https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/bc-authorize

The endpoint supports the following parameters:

Parameter Description Required

client_assertion(1)

A signed JSON Web Token (JWT) to use as client credentials.

Yes, for JWT profile authentication

client_assertion_type

The type of assertion, client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer.

Yes, for JWT profile authentication

client_id

Uniquely identifies the application making the request.

Yes

client_secret

The password for a confidential client.

Yes, when authenticating with Form parameters (HTTP POST)

(1) The endpoint requires a signed JWT with these 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.

"aud": "https://openam.example.com:8443/openam/oauth2"

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": 1675681183

id_token_hint

An ID token identifying the principal and subject of the JWT (the end user).

Required when not using login_hint.

"id_token_hint": "<id-token>"

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

Required when not using id_token_hint.

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

/oauth2/access_token

The /oauth2/access_token endpoint is the OAuth 2.0 token endpoint (RFC 6749).

Use this endpoint to acquire an access or refresh token with the following flows:

Specify the realm in the request URL; for example:

https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token

The access_token endpoint supports the following parameters:

Parameter Description Required

actor_token

The token representing a delegate acting on behalf of another identity.

Yes, for Token exchange

actor_token_type

The type of actor token.

Yes, for Token exchange

auth_chain

A string naming the journey to authenticate the resource owner.

No, only for Resource owner password credentials grant

assertion

A string holding a base64-encoded then URL-encoded SAML v2.0 assertion

Yes, when grant_type=urn:ietf:params:oauth:grant-type:saml2-bearer

client_assertion

A signed JSON Web Token (JWT) to use as client credentials.

Yes, for JWT profile authentication

client_assertion_type

The type of assertion, client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer.

Yes, for JWT profile authentication

client_id

Uniquely identifies the application making the request.

Yes

client_secret

The password for a confidential client; do not use with cnf_key.

Yes, when authenticating with Form parameters (HTTP POST)

cnf_key

A base64-encoded JSON Web Key (JWK) or hash of the X.509 certificate; do not use with client_secret.

Yes, for Proof-of-possession.

code

A string holding the authorization code for an authorization code grant.

Yes, when grant_type=authorization_code

code_verifier

A random string correlating a PKCE authorization request with the token request.

Yes, for flows with PKCE

device_code

A string holding the device code requested from the user for a device flow.

Yes, when grant_type=urn:ietf:params:oauth:grant-type:device_code

grant_type

A string specifying the type of grant to acquire an access token.

Yes

password

A string holding the resource owner password for the Resource owner password credentials grant.

Yes, when grant_type=password

redirect_uri

The URI to return the resource owner to after authorization is complete.

Yes, when grant_type=authorization_code and it was included earlier in the flow

refresh_token

The refresh to get a new access token.

Yes, for Refresh tokens

requested_token_type

The type of token requested in exchange.

No, but recommended for Token exchange

scope

The scopes linked to the permissions requested by the client from the resource owner.

No

subject_token

The original token to exchange.

Yes, for Token exchange

subject_token_type

The type of subject token.

Yes, for Token exchange

username

A string holding the resource owner username for the Resource owner password credentials grant.

Yes, when grant_type=password

/oauth2/device/code

The Device flow endpoint defined in RFC 8628 OAuth 2.0 Device Authorization Grant.

Client devices use this endpoint in the following flows to get the codes and information required to obtain the resource owner’s consent for device access:

Specify the realm in the request URL; for example:

https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/device/code

The device code endpoint supports the following parameters:

Parameter Description Required

acr_values

The OpenID Connect authentication context class reference values.

Yes, if required by the OpenID Connect provider

claims

The user attributes to be returned in the ID token.

No

client_id

Uniquely identifies the application making the request.

Yes

code_challenge

The code verifier generated for the PKCE flow.

Yes, for the Authorization code grant with PKCE flow

code_challenge_method

The method to derive the code challenge.

Yes, when the code_challenge is hashed (recommended)

login_hint

String value that can be set to the ID the user uses to log in.

No

nonce

String value that associates the client session with the ID token.

No

prompt

Specifies whether to prompt the end user for authentication and consent.

No

scope

The scopes linked to the permissions requested by the client from the resource owner.

No

state

The value to maintain state between the request and the callback.

No, but strongly recommended

ui_locales

The end user’s preferred languages for the user interface.

No

/oauth2/device/user

This is the Device flow endpoint for user interaction. Client devices use this endpoint to exchange a user code with consent from the resource owner to access the resources in the following flows:

Client devices use this endpoint to confirm the resource owner’s consent in the following flows:

Specify the realm in the request URL; for example:

https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/device/user

The device user endpoint supports the following parameters:

Parameter Description Required

csrf

The SSO token string linking the request to the user session to protect against Cross-Site Request Forgery attacks.

Yes, when gathering consent without a remote consent service

decision

Specifies whether the resource owner consents to the requested access.

Yes, when gathering consent unless consent is already saved for the scope

save_consent

Specifies whether to store a resource owner’s consented scopes.

No

scope

The scopes linked to the permissions requested by the client from the resource owner.

No

user_code

The user code confirmed by the resource owner.

Yes

/oauth2/token/revoke

Endpoint defined in RFC 7009 Token Revocation to revoke access tokens and refresh tokens.

When you revoke a refresh token, you revoke all tokens issued with the same authorization grant. If you obtained multiple access tokens for a single user with different authorization grants, you must revoke the tokens separately to invalidate each one.

Specify the realm in the request URL; for example:

https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/token/revoke

The revoke token endpoint supports the following parameters:

Parameter Description Required

client_assertion

A signed JSON Web Token (JWT) to use as client credentials.

Yes, for JWT profile authentication

client_assertion_type

The type of assertion, client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer.

Yes, for JWT profile authentication

client_id

Uniquely identifies the application making the request.

Yes

client_secret

The password for a confidential client.

Yes, when authenticating with Form parameters (HTTP POST)

token

The access token or refresh token to revoke.

Yes

The following example revokes a refresh token:

$ curl \
--request POST \
--user "myClient:forgerock" \
--data "client_id=myClient" \
--data "token=<refresh-token>" \
"https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/token/revoke"
{}

/oauth2/introspect

The /oauth2/introspect endpoint is defined in RFC 7662 OAuth 2.0 Token Introspection.

A resource server uses this endpoint to retrieve details about a token, such as:

  • The approved scopes

  • The user who authorized the client to obtain the token

  • The expiry time

  • The proof-of-possession JSON Web Key (JWK)

The resource server must authenticate to access this endpoint.

Specify the realm in the request URL; for example:

https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/introspect

The default settings for this endpoint do not allow:

  • HTTP GET requests

  • Use of token as a query parameter

To change this behavior for compatibility, use the org.forgerock.openam.introspect.token.query.param.allowed advanced server property.

The token introspection endpoint supports the following parameters:

Parameter Description Required

client_assertion

A signed JSON Web Token (JWT) to use as client credentials.

Yes, for JWT profile authentication

client_assertion_type

The type of assertion, client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer.

Yes, for JWT profile authentication

client_id

Uniquely identifies the application making the request.

Yes

client_secret

The password for a confidential client.

Yes, when authenticating with Form parameters (HTTP POST)

token

The token to introspect.

Yes

Example

The following example demonstrates token introspection:

$ curl \
--request POST \
--user "myClient:forgerock" \
--data "token=<access-token>" \
"https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/introspect"
{
  "active": true,
  "scope": "profile",
  "realm": "/alpha",
  "client_id": "myClient",
  "user_id": "a0325ea4-9d9b-4056-931b-ab64704cc3da",
  "username": "a0325ea4-9d9b-4056-931b-ab64704cc3da",
  "token_type": "Bearer",
  "exp": 1675703376,
  "sub": "a0325ea4-9d9b-4056-931b-ab64704cc3da",
  "subname": "a0325ea4-9d9b-4056-931b-ab64704cc3da",
  "iss": "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha",
  "auth_level": 0,
  "authGrantId": "sReMmkL05mN4xtDMQdVrpjXB_go",
  "auditTrackingId": "1d7a3317-03a9-4461-9d12-745f886019c2-5860187",
  "expires_in": 3575
}

Introspect special tokens

  • To introspect macaroon access tokens containing third-party caveats, use the X-Discharge-Macaroon header to pass the discharge macaroon.

  • To introspect UMA RPT tokens, use the PAT of the resource owner in an authorization: Bearer header to authenticate to the endpoint.

Response signing and encryption

The default introspection response is a plain JSON object.

AM also supports the JWT Response for OAuth Token Introspection Internet-Draft, which adds signed JWT or signed and encrypted JWT responses.

A client application can request a signed JWT by adding an Accept: application/jwt header to the request.

To enable signing and encryption for all requests, follow these steps:

  1. In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Client ID > Advanced and select the response type in the Token introspection response format drop-down list.

  2. If necessary to configure signing and encryption, configure the following properties:

    Token introspection response signing algorithm

    Default: RS256

    Token introspection response encryption algorithm

    Default: RSA-OAEP-256

    Token introspection encrypted response encryption algorithm

    Default: A128CBC-HS256

  3. Save your work.

Requests for plain JSON now return errors.

Response content

The following table describes fields you may find in the introspection response:

Field Description

active

Whether the token is active (true) or not (false).

auth_level

The AM authentication level for the resource owner who granted access to the token.

client_id

The client the token was issued to.

cnf

The confirmation key claim.

The jwk type contains the decoded JWK for the access token in the JWK-based proof-of-possession flow.

exp

Expiration time in seconds since January 1, 1970 UTC.

expires_in

Expiration time in seconds from now; the value decreases with every request to AM.

Unlike the calculated value, the expiration time stored in the token does not change.

For client-side tokens, AM only returns this to a client in the same realm as the resource owner.

iss

The token issuer.

macaroon

The macaroon the token validates, including any caveats.

permissions

(UMA only) An array containing the following:

  • RPT token expiration time (exp)

  • Resource scopes of the token

  • Resource ID

scope

The space-separated list of the scopes associated with the token.

sub

The subject of the access token.

The subject claim is in the format (type!subject), where:

  • subject is the identifier of the user/identity, or the name of the OAuth 2.0/OpenID Connect client that is the subject of the token.

  • type can be one of the following:

    • age. Specifies that the subject is an OAuth 2.0/OpenID Connect-related user-agent or client. For example, an OAuth 2.0 client, a Remote Consent Service agent, and a Web and Java Agent internal client.

    • usr. Specifies that the subject is a user/identity.

For example, (usr!demo), or (age!myOAuth2Client).

token_type

The type of token.

user_id

Deprecated form of username.

username

The user who authorized the client to obtain the token.

/json/token/macaroon

The /json/token/macaroon endpoint lets you inspect and manipulate macaroon tokens.

Specify the realm in the request URL; for example:

https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/token/macaroon

This endpoint supports these parameters:

Field Description

action=inspect

Return details about the macaroon.

action=restrict

Add a caveat to the macaroon, returning a new macaroon.

You can manipulate macaroons locally using a macaroon library. Anyone in possession of a macaroon token can inspect and restrict the macaroon securely.

The following example restricts the scope of a macaroon token and inspects the result. The original scope of the unrestricted token is openid profile:

$ curl \
--request POST \
--header "Content-Type: application/json" \
--header "cache-control: no-cache" \
--data '{
  "macaroon": "<macaroon-token>",
  "caveat": {"type": "first-party", "identifier": {"scope": "profile"}}
}' \
'https://openam.example.com:8443/openam/json/realms/root/realms/alpha/token/macaroon?_action=restrict'
{
  "macaroon": "<restricted-macaroon-token>"
}

$ curl \
--request POST \
--header "Content-Type: application/json" \
--header "cache-control: no-cache" \
--data '{"macaroon": "<restricted-macaroon-token>"}' \
'https://openam.example.com:8443/openam/json/realms/root/realms/alpha/token/macaroon?_action=inspect'
{
  "identifier": "<identifier>",
  "location": "",
  "caveats": [{
    "type": "first-party",
    "identifier": {
      "scope": "profile"
    }
  }],
  "signature": "<signature>"
}

OIDC clients must ensure the following information is present in the JSON:

  • The openid scope; for example, "scopes": ["profile", "openid"].

  • The id_token response type; for example, "response_types": ["code", "id_token code"].

Legacy OAuth 2.0 endpoints

AM exposes the following legacy endpoints:

OAuth 2.0 administration endpoints
Endpoint Description

Retrieve metadata about a token, revoke access and refresh tokens (AM-specific endpoint, legacy)

Validate tokens and retrieve token metadata, such as scopes, to determine how to respond to requests for protected resources (AM-specific endpoint, legacy)

/frrest/oauth2/token (Legacy)

This AM-specific OAuth 2.0 token administration endpoint lets you read, list, and delete (revoke) OAuth 2.0 tokens. OAuth 2.0 clients can also manage their own tokens.

The /frrest/oauth2/token endpoint is labelled as legacy and does not support client-side OAuth 2.0 tokens.

Use the following endpoints instead:

To list the contents of a specific token, send an HTTP GET request to /frrest/oauth2/token/token-id as follows:

$ curl \
--request POST \
--data "grant_type=password" \
--data "username=demo" \
--data "password=Ch4ng31t" \
--data "scope=cn" \
--data "client_id=myClient" \
--data "client_secret=forgerock" \
"https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"
{
    "scope": "cn",
    "expires_in": 60,
    "token_type": "Bearer",
    "access_token": "f5fb4833-ba3d-41c8-bba4-833b49c3fe2c"
}
$ curl \
--request GET \
--header "iplanetDirectoryPro: AQIC5wM2LY4Sfcxs…​EwNDU2NjE0*" \
https://openam.example.com:8443/openam/frrest/oauth2/token/f5fb4833-ba3d-41c8-bba4-833b49c3fe2c
{
    "expireTime": [
        "1418818601396"
    ],
    "tokenName": [
        "access_token"
    ],
    "scope": [
        "cn"
    ],
    "grant_type": [
        "password"
    ],
    "clientID": [
        "myClientID"
    ],
    "parent": [],
    "id": [
        "f5fb4833-ba3d-41c8-bba4-833b49c3fe2c"
    ],
    "tokenType": [
        "Bearer"
    ],
    "redirectURI": [],
    "nonce": [],
    "realm": [
        "/alpha"
    ],
    "userName": [
        "demo"
    ]
}

To list the tokens for the current user, send an HTTP GET request to /frrest/oauth2/token/?_queryId=access_token, including the SSO token of the current user in a header. The following example shows a search for the demo user’s access tokens:

$ curl \
 --request GET \
 --header "iplanetDirectoryPro: AQIC5wM2LY4Sfcw…​" \
 "https://openam.example.com:8443/openam/frrest/oauth2/token/?_queryId=access_token"
{
    "result": [
    {
      "_rev": "1753454107",
      "tokenName": [
        "access_token"
      ],
      "expireTime": "Indefinitely",
      "scope": [
        "openid"
      ],
      "grant_type": [
        "password"
      ],
      "clientID": [
        "myClientID"
      ],
      "tokenType": [
        "Bearer"
      ],
      "redirectURI": [],
      "nonce": [],
      "realm": [
        "/alpha"
      ],
      "userName": [
        "bjensen"
      ],
      "display_name": "",
      "scopes": "openid"
    },
    {
      "_rev": "1753454107",
      "tokenName": [
        "access_token"
      ],
      "expireTime": "Indefinitely",
      "scope": [
        "openid"
      ],
      "grant_type": [
        "password"
      ],
      "clientID": [
        "myClientID"
      ],
      "tokenType": [
        "Bearer"
      ],
      "redirectURI": [],
      "nonce": [],
      "realm": [
        "/alpha"
      ],
      "userName": [
        "bjensen"
      ],
      "display_name": "",
      "scopes": "openid"
    }
  ],
  "resultCount": 2,
  "pagedResultsCookie": null,
  "totalPagedResultsPolicy": "NONE",
  "totalPagedResults": -1,
  "remainingPagedResults": -1
}

To list the tokens for a specific user, send an HTTP GET request to /frrest/oauth2/token/?_queryId=userName=_username_,realm=/_realm_, where string is the user, such as bjensen, and realm is the subrealm in which the user is located. You do not have to include the realm parameter if the user is in the top-level realm.

Include the SSO token of an administrative user, such as amAdmin, in a header. For example:

$ curl \
  --request GET \
  --header "iplanetDirectoryPro: AQIC5wM2LY4Sfcxs…​EwNDU2NjE0*" \
  "https://openam.example.com:8443/openam/frrest/oauth2/token/?_queryId=userName=bjensen,realm=alpha"
{
    "result": [
    {
      "_id": "2aaddde8-586b-4cb7-b431-eb86af57aabc",
      "_rev": "-549186065",
      "tokenName": [
        "access_token"
      ],
      "expireTime": "Indefinitely",
      "scope": [
        "openid"
      ],
      "grant_type": [
        "password"
      ],
      "authGrantId": [
        "50e9f80b-d193-4aeb-93e9-e383ea2cabd3"
      ],
      "clientID": [
        "myClientID"
      ],
      "parent": [],
      "refreshToken": [
        "5e1423a2-d2cd-40d5-8f54-5b695836cd44"
      ],
      "id": [
        "2aaddde8-586b-4cb7-b431-eb86af57aabc"
      ],
      "tokenType": [
        "Bearer"
      ],
      "auditTrackingId": [
        "6ac90d13-9cac-444b-bfbc-c7aca16713de-777"
      ],
      "redirectURI": [],
      "nonce": [],
      "realm": [
        "/alpha"
      ],
      "userName": [
        "bjensen"
      ],
      "display_name": "",
      "scopes": "openid"
    },
    {
      "_id": "5e1423a2-d2cd-40d5-8f54-5b695836cd44",
      "_rev": "1171292923",
      "tokenName": [
        "refresh_token"
      ],
      "expireTime": "Oct 18, 2016 10:51 AM",
      "scope": [
        "openid"
      ],
      "grant_type": [
        "password"
      ],
      "authGrantId": [
        "50e9f80b-d193-4aeb-93e9-e383ea2cabd3"
      ],
      "clientID": [
        "myClientID"
      ],
      "authModules": [],
      "id": [
        "5e1423a2-d2cd-40d5-8f54-5b695836cd44"
      ],
      "tokenType": [
        "Bearer"
      ],
      "auditTrackingId": [
        "6ac90d13-9cac-444b-bfbc-c7aca16713de-776"
      ],
      "redirectURI": [],
      "realm": [
        "/alpha"
      ],
      "userName": [
        "bjensen"
      ],
      "acr": [],
      "display_name": "",
      "scopes": "openid"
    },
  ],
  "resultCount": 2,
  "pagedResultsCookie": null,
  "totalPagedResultsPolicy": "NONE",
  "totalPagedResults": -1,
  "remainingPagedResults": -1
}

To delete (revoke) a token, perform an HTTP DELETE on /frrest/oauth2/token/token-id, including the SSO token of an administrative user, such as amAdmin, as in the following example:

$ curl \
--request POST \
--data "grant_type=password" \
--data "username=demo" \
--data "password=Ch4ng31t" \
--data "scope=cn" \
--data "client_id=myClient" \
--data "client_secret=forgerock" \
"https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"
{
    "scope": "cn",
    "expires_in": 60,
    "token_type": "Bearer",
    "access_token": "f5fb4833-ba3d-41c8-bba4-833b49c3fe2c"
}
$ curl \
 --request DELETE \
 --header "iplanetDirectoryPro: AQIC5wM2LY4Sfcxs…​EwNDU2NjE0*" \
 "https://openam.example.com:8443/openam/frrest/oauth2/token/f5fb4833-ba3d-41c8-bba4-833b49c3fe2c"
{
    "success": "true"
}

/oauth2/tokeninfo (Legacy)

AM-specific endpoint used to validate tokens and to retrieve information out of them, such as scopes, the grant type used when issuing the token, or the token expiration time.

The /oauth2/tokeninfo endpoint is labelled as legacy.

To validate tokens and retrieve information with a spec-based endpoint, see /oauth2/introspect.

Resource servers—or any party having the token ID—can obtain token information through this endpoint without authenticating.

The token information endpoint supports the following query parameter:

access_token

Specifies the token ID.

Required: Yes.

The following example shows AM issuing an access token, and then returning token information:

$ curl \
--request POST \
--data "grant_type=password" \
--data "username=demo" \
--data "password=Ch4ng31t" \
--data "scope=write" \
--data "client_id=myClient" \
--data "client_secret=forgerock" \
"https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"
{
  "access_token": "sbQZuveFumUDV5R1vVBl6QAGNB8",
  "scope": "write",
  "token_type": "Bearer",
  "expires_in": 3599
}
$ curl \
--request GET \
--header "Authorization: Bearer sbQZuveFumUDV5R1vVBl6QAGNB8" \
"https://openam.example.com:8443/openam/oauth2/tokeninfo"
{
   "access_token":"sbQZuveFumUDV5R1vVBl6QAGNB8",
   "grant_type":"password",
   "auth_level":0,
   "scope":[
      "write"
   ],
   "realm":"/alpha",
   "token_type":"Bearer",
   "expires_in":2491,
   "write":"",
   "client_id":"myClient"
}

Note that AM returns a JSON object with the following properties:

access_token

Specifies the token ID.

grant_type

Specifies the OAuth 2.0 grant flow used to issue the token.

auth_level

Specifies the authentication level of the resource owner that authenticated to authorize the token.

scope

Specifies a JSON structure containing the scopes associated with the token.

realm

Specifies the realm from which the token was obtained.

token_type

Specifies the type of token.

expires_in

Specifies the time, in seconds, that the token is valid for. This value is set at token creation time, and it depends on the configuration of the OAuth2 Provider Service.

During the introspection call, AM calculates the amount of seconds the token is still valid for and returns it in the expires_in object. Therefore, repeated calls to the endpoints return different values for the object.

However, the actual value of the expires_in object in the token does not change. Inspecting the token without using AM will show the value set at token creation time.

AM does not return this object for client-side tokens issued to a client configured in a different realm that the resource owner’s.

client_id

Specifies the client that requested the token.

OAuth 2.0 administration REST endpoints

AM exposes the following administration and supporting REST endpoints:

OAuth 2.0 administration and supporting endpoints
Endpoint Description

Register, list, and delete OAuth 2.0 clients (AM specific-endpoint)

Retrieve data for UMA resources registered to a particular user (AM-specific endpoint)

List OAuth 2.0 clients holding active tokens granted by specific resource owners, and delete tokens for a combination of resource owner and client (AM-specific endpoint)

/realm-config/agents/OAuth2Client

AM-specific endpoint that lets AM and agent administrators create, list, and delete OAuth 2.0 clients.

Use the AM API explorer for detailed information about the parameters supported by this endpoint, and to test it against your deployed AM instance.

In the AM admin UI, click the Help icon, and go to API Explorer > /realm-config > /agents > /OAuth2Client.

Create an OAuth 2.0 client

This example registers a basic OAuth 2.0 client named myClient in the alpha realm. Provide the SSO token of an administrative user as a header, and append the name of the client to the URL.

Example
$ curl \
--request PUT \
--header "Accept-API-Version: resource=1.0" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "iplanetDirectoryPro: AQIC5wM…​3MTYxOA..*" \
--data '{
   "coreOAuth2ClientConfig":{
      "agentgroup":"",
      "status":{
         "inherited":true,
         "value":"string"
      },
      "userpassword":"forgerock",
      "clientType":{
         "inherited":false,
         "value":"Confidential"
      },
      "redirectionUris":{
         "inherited":false,
         "value":[
            "https://www.example.com:443/callback"
         ]
      },
      "scopes":{
         "inherited":false,
         "value":[
            "write",
            "read"
         ]
      },
      "defaultScopes":{
         "inherited":true,
         "value":[
            "write"
         ]
      },
      "clientName":{
         "inherited":true,
         "value":[
            "My Test Client"
         ]
      }
   },
   "advancedOAuth2ClientConfig":{
      "name":{
         "inherited":false,
         "value":[
            null
         ]
      },
      "grantTypes":{
         "inherited":true,
         "value":[
            "authorization_code",
            "client_credentials"
         ]
      },
      "tokenEndpointAuthMethod":{
         "inherited":true,
         "value":"client_secret_basic"
      }
   }
}' \
"https://openam.example.com:8443/openam/json/realms/root/realms/alpha/realm-config/agents/OAuth2Client/myClient"
{
   "_id":"myClient",
   "_rev":"-60716879",
   "advancedOAuth2ClientConfig":{
      "descriptions":{
         "inherited":false,
         "value":[

         ]
      },

…​

      "clientType":{
         "inherited":false,
         "value":"Confidential"
      },
…​
      "_type":{
      "_id":"OAuth2Client",
      "name":"OAuth2 Clients",
      "collection":true
   }
}

Update an OAuth 2.0 client

To update an existing OAuth 2.0 client, use a similar PUT request to the create request. Make sure you include all the attributes to be retained in the client configuration. If you omit an attribute in the JSON payload, the request effectively deletes that attribute from the client.

Query OAuth 2.0 clients

This example lists the OAuth 2.0 clients in the alpha realm. Provide the SSO token of an administrative user as a header.

Example
$ curl \
--request GET \
--header "Accept-API-Version: resource=1.0" \
--header "iplanetDirectoryPro: AQIC5wM…​3MTYxOA..*" \
"https://openam.example.com:8443/openam/json/realms/root/realms/alpha/realm-config/agents/OAuth2Client?_queryFilter=true"
{
  "result": [
    {
      "_id": "myClient",
      "_rev": "-1788958356",
      "overrideOAuth2ClientConfig": {
        "issueRefreshToken": true,
        "validateScopePluginType": "PROVIDER",
        "tokenEncryptionEnabled": false,
        "evaluateScopePluginType": "PROVIDER",
        "oidcMayActScript": "[Empty]",
        "oidcClaimsScript": "[Empty]",
        "accessTokenModificationPluginType": "PROVIDER",
        "authorizeEndpointDataProviderClass": "org.forgerock.oauth2.core.plugins.registry.DefaultEndpointDataProvider",
        "oidcClaimsPluginType": "PROVIDER",
        "providerOverridesEnabled": false,
        "authorizeEndpointDataProviderScript": "[Empty]",
        "statelessTokensEnabled": false,
        "authorizeEndpointDataProviderPluginType": "PROVIDER",
        "remoteConsentServiceId": null,
        "enableRemoteConsent": false,
        "validateScopeClass": "org.forgerock.oauth2.core.plugins.registry.DefaultScopeValidator",
        "usePolicyEngineForScope": false,
        "evaluateScopeClass": "org.forgerock.oauth2.core.plugins.registry.DefaultScopeEvaluator",
        "overrideableOIDCClaims": [],
        "accessTokenMayActScript": "[Empty]",
        "evaluateScopeScript": "[Empty]",
        "clientsCanSkipConsent": false,
        "accessTokenModificationScript": "[Empty]",
        "issueRefreshTokenOnRefreshedToken": true,
        "validateScopeScript": "[Empty]"
      },
      "advancedOAuth2ClientConfig": {
        "logoUri": [],
        "subjectType": "public",
        "clientUri": [],
        "tokenExchangeAuthLevel": 0,
        "responseTypes": [
          "code",
          "token",
          "id_token",
          "code token",
          "token id_token",
          "code id_token",
          "code token id_token",
          "device_code",
          "device_code id_token"
        ],
        "mixUpMitigation": false,
        "customProperties": [],
        "javascriptOrigins": [],
        "policyUri": [],
        "softwareVersion": null,
        "sectorIdentifierUri": null,
        "tosURI": [],
        "tokenEndpointAuthMethod": "client_secret_basic",
        "isConsentImplied": false,
        "refreshTokenGracePeriod": 0,
        "softwareIdentity": null,
        "grantTypes": [
          "authorization_code"
        ],
        "require_pushed_authorization_requests": false,
        "descriptions": [],
        "requestUris": [],
        "name": [],
        "contacts": [],
        "updateAccessToken": null
      },
      "signEncOAuth2ClientConfig": {
        "tokenEndpointAuthSigningAlgorithm": "RS256",
        "idTokenEncryptionEnabled": false,
        "tokenIntrospectionEncryptedResponseEncryptionAlgorithm": "A128CBC-HS256",
        "requestParameterSignedAlg": null,
        "authorizationResponseSigningAlgorithm": "RS256",
        "clientJwtPublicKey": null,
        "idTokenPublicEncryptionKey": null,
        "mTLSSubjectDN": null,
        "jwkStoreCacheMissCacheTime": 60000,
        "jwkSet": null,
        "idTokenEncryptionMethod": "A128CBC-HS256",
        "jwksUri": null,
        "tokenIntrospectionEncryptedResponseAlg": "RSA-OAEP-256",
        "authorizationResponseEncryptionMethod": null,
        "userinfoResponseFormat": "JSON",
        "mTLSCertificateBoundAccessTokens": false,
        "publicKeyLocation": "jwks_uri",
        "tokenIntrospectionResponseFormat": "JSON",
        "requestParameterEncryptedEncryptionAlgorithm": "A128CBC-HS256",
        "userinfoSignedResponseAlg": null,
        "idTokenEncryptionAlgorithm": "RSA-OAEP-256",
        "requestParameterEncryptedAlg": null,
        "authorizationResponseEncryptionAlgorithm": null,
        "mTLSTrustedCert": null,
        "jwksCacheTimeout": 3600000,
        "userinfoEncryptedResponseAlg": null,
        "idTokenSignedResponseAlg": "RS256",
        "userinfoEncryptedResponseEncryptionAlgorithm": "A128CBC-HS256",
        "tokenIntrospectionSignedResponseAlg": "RS256"
      },
      "coreOpenIDClientConfig": {
        "claims": [],
        "backchannel_logout_uri": null,
        "defaultAcrValues": [],
        "jwtTokenLifetime": 0,
        "defaultMaxAgeEnabled": false,
        "clientSessionUri": null,
        "defaultMaxAge": 600,
        "postLogoutRedirectUri": [],
        "backchannel_logout_session_required": false
      },
      "coreOAuth2ClientConfig": {
        "status": "Active",
        "clientName": [],
        "clientType": "Confidential",
        "loopbackInterfaceRedirection": false,
        "defaultScopes": [],
        "agentgroup": null,
        "refreshTokenLifetime": 0,
        "scopes": [],
        "accessTokenLifetime": 0,
        "redirectionUris": [],
        "authorizationCodeLifetime": 0
      },
      "coreUmaClientConfig": {
        "claimsRedirectionUris": []
      },
      "_type": {
        "_id": "OAuth2Client",
        "name": "OAuth2 Clients",
        "collection": true
      }
    }
  ],
  "resultCount": 1,
  "pagedResultsCookie": null,
  "totalPagedResultsPolicy": "EXACT",
  "totalPagedResults": 1,
  "remainingPagedResults": -1
}

Delete an OAuth 2.0 client

This example deletes an OAuth 2.0 client named myClient in the alpha realm. Provide the SSO token of and administrative user as a header, and append the name of the client to the URL.

Example
$ curl \
--request DELETE \
--header "Accept-API-Version: resource=1.0" \
--header "iplanetDirectoryPro: AQIC5wM…​3MTYxOA..*" \
"https://openam.example.com:8443/openam/json/realms/root/realms/alpha/realm-config/agents/OAuth2Client/myClient"
{
    "_id": "myClient",
    "_rev": "-614477476",
    ...
}

/users/user/oauth2/resources/sets

AM-specific endpoint for viewing and updating a resource registered to a particular user.

Use the AM API explorer for detailed information about the parameters supported by this endpoint, and to test it against your deployed AM instance.

In the AM admin UI, click the Help icon, and go to API Explorer > /users > /{user} > /oauth2 > /resources > /sets.

To call the endpoint, you must compose the path to the realm where the resource is registered.

This example reads an OAuth 2.0 resource and related policy in the alpha realm.

Note that you must provide the SSO token of an administrative user or of the resource owner as a header, and that the name of the resource owner (demo, in this example) is part of the URL:

$ curl \
--request GET \
--header "iPlanetDirectoryPro: AQIC5wM2LY4Sfcxs…​EwNDU2NjE0*" \
"https://openam.example.com:8443/openam/json/realms/root/realms/alpha/users/demo\
/oauth2/resources/sets/43225628-4c5b-4206-b7cc-5164da81decd0"
{
    "scopes": [
         "http://photoz.example.com/dev/scopes/view",
         "http://photoz.example.com/dev/scopes/comment"
    ],
    "_id": "43225628-4c5b-4206-b7cc-5164da81decd0",
    "resourceServer": "UMA-Resource-Server",
    "name": "My Videos",
    "icon_uri": "http://www.example.com/icons/cinema.png",
    "policy": {
        "permissions": [
            {
                "subject": "user.1",
                "scopes": [
                    "http://photoz.example.com/dev/scopes/view"
                ]
            },
            {
                "subject": "user.2",
                "scopes": [
                    "http://photoz.example.com/dev/scopes/comment",
                    "http://photoz.example.com/dev/scopes/view"
                ]
            }
        ]
    },
    "type": "http://www.example.com/rsets/videos"
}

You can specify the fields that are returned with the _fields query string filter. For example, ?_fields=scopes, resourceServer, name.

On success, an HTTP 200 OK status code is returned, with a JSON body representing the resource. If a policy relating to the resource exists, a representation of the policy is also returned in the JSON.

If the specified resource does not exist, an HTTP 404 Not Found status code is returned, as follows:

{
    "code": 404,
    "reason": "Not Found",
    "message": "No resource set with id, bad-id-3e28-4c19-8a2b-36fc24c899df0, found."
}

If the SSO token used is not that of the resource owner or an administrator, an HTTP 403 Forbidden status code is returned, as follows:

{
    "code": 403,
    "reason": "Forbidden",
    "message": "User, user.1, not authorized."
}

/users/user/oauth2/applications

AM-specific endpoint for listing clients holding tokens granted by specific resource owners, and for deleting tokens for a combination of a resource owner and client.

Use the AM API explorer for detailed information about the parameters supported by this endpoint, and to test it against your deployed AM instance.

In the AM admin UI, click the Help icon, and go to API Explorer > /users > /{user} > /oauth2 > /applications.

To call the endpoint, you must compose the path to the realm where the client is registered.

This example lists all the clients holding tokens granted in the alpha realm by the demo user. Note that you must provide the SSO token of an administrative user or of the resource owner as a header, and that the name of the resource owner (demo) is part of the URL:

$ curl \
--request GET \
--header "Accept-API-Version: resource=1.1" \
--header "iplanetDirectoryPro: Ua6fsH2vjgHqVY…​" \
"https://openam.example.com:8443/openam/json/realms/root/realms/alpha/users/demo/oauth2/applications?_queryFilter=true"

On success, AM returns an HTTP 200 code and a JSON structure containing information about the tokens, such as the client ID they belong to, the granted scopes, and their expiration time:

{
   "result":[
      {
         "_id":"myClient",
         "_rev":"22274676",
         "name":null,
         "description":"This field describes myClient",
         "scopes":{
            "write":"write"
         },
         "expiryDateTime":"2018-11-14T10:48:55.395Z",
         "logoUri":null
      }
   ],
   "resultCount":1,
   "pagedResultsCookie":null,
   "totalPagedResultsPolicy":"NONE",
   "totalPagedResults":-1,
   "remainingPagedResults":-1

The following example shows how to delete all tokens held by the client myClient granted in the alpha realm by the demo user. Note that you must provide the SSO token of an administrative user or of the resource owner as a header, and that the name of the resource owner (demo) and the name of the client (myClient) are part of the URL:

$ curl \
--request DELETE \
--header "Accept-API-Version: resource=1.1" \
--header "iplanetDirectoryPro: Ua6fsH2vjgHqVY…​" \
"https://openam.example.com:8443/openam/json/realms/root/realms/alpha/users/demo/oauth2/applications/myClient"

On success, AM returns an HTTP 200 code and a JSON structure containing information about the deleted tokens, such as the client ID they belonged to, the scopes they granted, and their expiration time:

{
  "_id": "myClient",
  "_rev": "22274676",
  "name": null,
  "description":"This field describes myClient",
  "scopes": {
    "write": "write"
  },
  "expiryDateTime": "2018-11-14T10:48:55.395Z",
  "logoUri": null
}

Customize OAuth 2.0

AM includes several plugin points that let you extend OAuth 2.0 authorization server functionality, such as modifying access tokens or customizing how AM processes scopes.

Supported plugin points

The following table describes the OAuth 2.0 plugin points supported in AM.

Plugin Description

Modify the OAuth2 access token before the token is persisted or returned to the client.

Return additional data from an authorization request.

Evaluate and return an OAuth2 access token’s scope information.

Customize the set of requested scopes for authorize, access token, refresh token and back channel authorize requests.

Fetch the resource owner’s information based on an issued access token.

How to build and use a custom OAuth 2.0 plugin

AM supports two types of custom plugin: scripted and Java. The following sections describe how to deploy a custom plugin according to your implementation type.

Customize with a script

AM provides a scripting engine and template scripts for you to extend OAuth 2.0 behavior by running scripts stored as configuration, rather than by updating code. Creating and modifying plugin scripts enables rapid development without the need to change or recompile core AM.

Create or modify an OAuth 2.0 plugin script

To create or edit a script that is saved for the current realm, or modify a default script that is available to all realms, you can either:

For more information, refer to Scripting.

Configure AM to use an OAuth 2.0 plugin script

After creating your plugin script, you must configure AM to use the plugin.

  1. In the AM admin UI, go to Realms > Realm Name > Services > OAuth2 Provider > Plugins to configure a specific OAuth 2.0 provider.

    To set your plugin as the default for all new OAuth2 providers, go to Configure > Global Services > OAuth2 Provider > Plugins.

    Alternatively, to configure plugins at the client level, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > OAuth2 Provider Overrides.

  2. Set the Plugin Type attribute to SCRIPTED.

  3. Set the Script attribute to the name of the script you want to use.

    For example, for the scope validation plugin, select the name of your script from the Scope Validation Script drop-down list. This list contains all the scripts that are saved for the current realm for the particular plugin type, including the default scripts that AM provides. In the case of the scope validation plugin, the list displays all scripts of type OAuth2 Validate Scope.

    For further details about setting plugin configuration, refer to the OAuth2 provider configuration and Client overrides.

  4. Save your changes.

Customize with Java

Write a Java class that implements one of the org.forgerock.oauth2.core.plugins interfaces. AM provides sample code and some default implementation classes for each of the plugin interfaces.

Create and deploy a Java OAuth 2.0 plugin
  1. Create a custom Java class that implements the appropriate plugin interface, and package in a JAR file.

    To use an existing example, download the sample code and build a JAR file by following the steps described in How do I access and build the sample code provided for AM? in the Knowledge Base.

  2. Copy the built JAR file to the /WEB-INF/lib folder where you deployed AM.

  3. Restart AM or the container in which it runs.

Configure AM to use a Java OAuth 2.0 plugin

After creating your plugin, you must configure AM to use the plugin.

  1. In the AM admin UI, go to Realms > Realm Name > Services > OAuth2 Provider > Plugins to configure a specific OAuth 2.0 provider.

    To set your plugin as the default for all new OAuth2 providers, go to Configure > Global Services > OAuth2 Provider > Plugins.

    Alternatively, to configure plugins at the client level, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > OAuth2 Provider Overrides.

  2. Set the Plugin Type attribute to JAVA.

  3. Set the Plugin Implementation Class attribute.

    For example, for the scope evaluation plugin, type the fully qualified name of your plugin class in the Scope Evaluation Plugin Implementation Class field.

    For further details about setting plugin configuration, refer to the OAuth2 provider configuration and Client overrides.

  4. Save your changes.

OAuth 2.0 scripting API

For information about the API available for implementing scripts, refer to:

  • Accessing HTTP Services

  • Debug logging

  • The AccessToken interface provides methods that let you view or modify the data associated with an access token.

  • The AMIdentity interface represents an identity that is managed by AM.

  • The SSOToken interface contains SSO token and authentication information, as well as session-related properties.

The following properties are common to all OAuth 2.0 scripts and always present for all script types. Refer to individual plugins for additional properties specific to the script type.

Binding Information

httpClient

An HTTP client for making external HTTP requests.

logger

The logger instance specific to the script type. Use the logger to write a message to the AM debug log.

For more information, refer to Debug Logging.

scriptName

The display name of the script.

Access token modification

Use this extension point to modify the key-value pairs in an OAuth 2.0 access token. For example, you could make a REST call to an external service, and add or change a key-value pair in the access token based on the response, before issuing the token to the resource owner.

Default script

To view the default script, including the available script properties, refer to oauth2-access-token-modification.groovy.

To view or modify the default script in the AM admin UI, go to Realms > Realm Name > Scripts and select OAuth2 Access Token Modification Script.

Java interface

org.forgerock.oauth2.core.plugins.AccessTokenModifier

Java sample
Show Sample Code
/*
 * Copyright 2021-2022 ForgeRock AS. All Rights Reserved
 *
 * Use of this code requires a commercial software license with ForgeRock AS.
 * or with one of its affiliates. All use shall be exclusively subject
 * to such license between the licensee and ForgeRock AS.
 */

package org.forgerock.openam.examples;

import org.forgerock.oauth2.core.AccessToken;
import org.forgerock.oauth2.core.OAuth2Request;
import org.forgerock.oauth2.core.plugins.AccessTokenModifier;

/**
 * Custom implementation of the Access Token Modifier
 * plugin interface {@link org.forgerock.oauth2.core.plugins.AccessTokenModifier}
 *
 * <li>
 * In this example the {@code modifyAccessToken} method adds an additional field to the token.
 * </li>
 *
 */
public class CustomAccessTokenModifier implements AccessTokenModifier {

    @Override
    public void modifyAccessToken(AccessToken accessToken, OAuth2Request request) {
        //Field to always include in token
        accessToken.setField("additional", "field");
    }
}

About modifying access tokens

You can modify both client-side and server-side access tokens. Modifications are stored permanently in either the issued JWT for client-side tokens, or in the CTS for server-side access tokens. You can also modify macaroons used in place of regular tokens. In this case, you implement the plugin to modify the key pairs in the token, and optionally, to add caveats. For more information, refer to the MacaroonToken interface.

When issuing modified access tokens, consider the following important points:

  • Removing or changing native properties may render the access token unusable.

    AM requires that certain native properties are present in the access token in order to consider it valid. Removing or modifying these properties may cause the OAuth 2.0 flows to break.

    Native properties are marked in the AM Public API Javadoc with a warning about loss of functionality if they are edited or removed.

  • Modifying access tokens affects the size of the client-side token or server-side entry.

    Changes made to OAuth 2.0 access tokens directly impacts the size of the server-side tokens, or the size of the JSON web tokens (JWT) if client-side tokens are enabled.

    You must ensure that the token size remains within your client or user-agent size limits.

    For more information, refer to Token storage location.

Example access token modification plugin

Complete the following steps to implement a custom access token modification script that sets additional properties in the access token:

To configure AM to use a Java access token modification plugin, refer to Configure AM to use a Java OAuth 2.0 plugin.

Prepare AM to modify access tokens

The script requires that the authenticated user of the access token has an email address and telephone number in their profile. The script adds the values of these fields to the access token.

  1. Log in as an AM administrator, for example, amAdmin.

  2. Add an email address and telephone number value to the demo user’s profile.

    The access token modification script injects the values provided into the OAuth 2.0 access token before it is issued to the resource owner.

    1. Select Realms > Realm Name > Identities.

    2. On the Identities tab, select the demo user.

    3. In Email Address, enter a valid address. For example, demo.user@example.com.

    4. In Telephone Number, enter a value. For example, 44 117 496 0228.

    5. Save your changes.

  3. Modify the default access token modification script to set additional fields.

    1. Go to Realms > Realm Name > Scripts, and click OAuth2 Access Token Modification Script.

    2. In the Script field:

      • Uncomment the following line, by surrounding with a pair of */ and /* strings:

        /* ... */
        accessToken.setField("hello", "world")
        /* ... */
      • Similarly, uncomment these lines:

        /* ... */
        def attributes = identity.getAttributes(["mail", "telephoneNumber"].toSet())
        accessToken.setField("mail", attributes["mail"])
        accessToken.setField("phone", attributes["telephoneNumber"])
        /* ... */

        To include additional data in the /oauth2/access_token response, edit your script to call the addExtraData method. For example:

        accessToken.addExtraData("hello", "world")

        This returns the data as part of the response body in the following way:

        {
          "access_token":"sbQZuveFumUDV5R1vVBl6QAGNB8",
          "hello":"world",
          "scope":"write",
          "token_type":"Bearer",
          "expires_in":3599
        }
    3. Save your changes.

Configure AM to use the custom access token modification script

Perform this task to set up an OAuth 2.0 provider that uses the modified default access token modification script.

  1. Log in to the AM admin UI as an administrator.

    For example, amAdmin.

  2. Configure the provider to ensure the following properties are set:

    • Access Token Modification Plugin Type to SCRIPTED.

    • Access Token Modification Plugin Script to OAuth2 Access Token Modification Script.

    By default, a new OAuth 2.0 provider uses the default access token modification script.

  3. Save your changes.

Create an OAuth2 client for authorization

Create an OAuth 2.0 client to use in the authorization request.

  1. In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients, and click Add Client.

  2. Enter the following values:

    • Client ID: myClient

    • Client secret: forgerock

    • Redirection URIs: https://www.example.com:443/callback

    • Scope(s): access|Access to your data

  3. Click Create.

AM is now configured to issue access tokens using the default access token modification script. As the demo user, you can now obtain an access token to test the script functionality.

Try the custom access token modification script

This section demonstrates obtaining an OAuth 2.0 access token that was modified by a script.

First, use the Authorization code grant flow to authenticate with AM as the resource owner, allow the client to access profile data, and receive the authorization code.

Next, exchange the authorization code for an access token.

The access token was altered by the default access token modification script to include:

  • The resource owner’s telephone number and email address, taken from their profile in AM, which is acting as the authorization server.

  • A hello:world key-value pair.

Finally, use the introspect endpoint to verify that the access token includes the modified values.

Obtain an authorization code
  1. In a web browser, go to the /oauth2/authorize endpoint, including the parameters and values configured for the OAuth 2.0 client in the previous section.

    Make sure you specify the correct realm in the endpoint. For example, if the OAuth 2.0 provider is configured for the /alpha realm, then use /oauth2/realms/root/realms/alpha/authorize.

    For example:

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

    Note that the URL is split for readability purposes.

    The AM login page is displayed.

  2. Log in as the demo user, with password Ch4ng31t.

    The AM OAuth 2.0 consent page is displayed.

  3. Review the requested scopes, and click Allow.

    AM redirects the browser to the location specified in the redirect_uri parameter, https://www.example.com:443/callback in this example, and appends a number of query parameters.

    For example:

    OAuth 2.0 authorization code in browser URL bar.
  4. Record the value of the code query parameter.

    This is the authorization code and is exchanged for an access token in the next procedure.

Exchange an authorization code for an access token
  1. Send a POST request to the /oauth2/access_token endpoint, including the authorization code obtained in the previous procedure, and the parameters and values configured for the OAuth 2.0 client earlier.

    For example:

    $ curl \
      --request POST \
      --data "grant_type=authorization_code" \
      --data "code=tH_s2obVRt2_yB6x4OxH1J3eMkU" \
      --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"
    {
      "access_token": "sbQZuveFumUDV5R1vVBl6QAGNB8",
      "scope": "access",
      "token_type": "Bearer",
      "expires_in": 3599
    }
  2. Record the value of the access_token property.

    This is the access token; the access token modification script modified the properties. Follow the steps in the next procedure to introspect the token to verify the properties were modified.

Introspect an access token to verify access token modification
  1. Send a POST request to the /oauth2/introspect endpoint, including the access token obtained in the previous procedure, and the credentials of the OAuth 2.0 client.

    For example:

    $ curl \
      --request POST \
      --data "client_id=myClient" \
      --data "client_secret=forgerock" \
      --data "token=sbQZuveFumUDV5R1vVBl6QAGNB8" \
      "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/introspect"
    {
      "active": true,
      "scope": "access",
      "client_id": "myClient",
      "user_id": "demo",
      "username":"demo",
      "token_type": "Bearer",
      "exp": 1556289970,
      "sub": "(usr!demo)",
      "subname": "demo",
      "iss": "https://openam.example.com:8443/openam/oauth2",
      "auth_level": 0,
      "auditTrackingId": "c6e22be7-6166-402b-9d72-a03134f08c22-8605",
      "hello": "world",
      "mail": [
        "demo.user@example.com"
      ],
      "phone": [
        "+44 117 496 0228"
      ]
    }

    Notice that the output includes a hello:world key-value pair, as well as mail and phone properties, containing values taken from the user’s profile data.

Access token modification scripting API

The following properties are available to access token modification scripts:

Binding Description

accessToken

The OAuth 2.0 access token. For details, refer to AccessToken.

clientProperties

A map of properties configured in the client profile. Only present if the client was correctly identified.

The map has the following keys:

allowedGrantTypes

List of the grant types allowed for the client. For details, refer to GrantType.

allowedResponseTypes

The permitted response types as an array of strings

allowedScopes

The permitted scope types as an array of strings

clientId

The client’s URI for the request locale.

customProperties

A map of any custom properties added to the client.

Lists or maps are included as sub-maps. For example, a custom property of customMap[Key1]=Value1 is returned as customMap > Key1 > Value1.

To add custom properties to a client, use the AM admin UI. Go to OAuth 2.0 > Clients > Client ID > Advanced, and update the Custom Properties field.

Add custom properties as shown in these examples:

customproperty=custom-value1
customList[0]=customList-value-0
customMap[key1]=customMap-value-1

Scripts can then access the custom properties in the following way:

var customProperties = clientProperties.get("customProperties");
var property = customProperties.get("myProperty");

The map is null if AM did not successfully identify the client.

httpClient

An HTTP client for making external HTTP requests.

identity

Represents an identity that AM can access. For details, refer to AMIdentity.

The logger instance for the script.

Logger names use the format scripts.OAUTH2_ACCESS_TOKEN_MODIFICATION.<script UUID>.(<script name>).

Refer to Debug logging.

requestProperties

A map of the properties present in the request.

The map has the following keys:

requestUri

The URI as a string

realm

The realm as a string

requestParams

A map of request parameters and posted data, where each value is an array of parameters.

To mitigate the risk of reflection-type attacks, use OWASP best practices when handling these parameters. Refer to Unsafe use of Reflection.

scriptName

The display name of the script.

scopes

An array of the requested scopes; for example:

["read", "transfer", "download"].

session

The user’s session object if the request contains a session cookie.

For details, refer to SSOToken.

Authorize endpoint data provider

Use this plugin to configure the OAuth2 provider to return additional data from an authorization request, such as data from the user’s session or from an external service.

Default script

To view the default script, including the available script properties, refer to oauth2-authorize-endpoint-data-provider.js.

To view or modify the default script in the AM admin UI, go to Realms > Realm Name > Scripts and select OAuth2 Authorize Endpoint Data Provider Script.

Java interface

org.forgerock.oauth2.core.plugins.AuthorizeEndpointDataProvider

Java sample
Show Sample Code
/*
 * Copyright 2021-2022 ForgeRock AS. All Rights Reserved
 *
 * Use of this code requires a commercial software license with ForgeRock AS.
 * or with one of its affiliates. All use shall be exclusively subject
 * to such license between the licensee and ForgeRock AS.
 */

package org.forgerock.openam.examples;

import java.util.HashMap;
import java.util.Map;

import org.forgerock.oauth2.core.OAuth2Request;
import org.forgerock.oauth2.core.Token;
import org.forgerock.oauth2.core.plugins.AuthorizeEndpointDataProvider;

/**
 * Custom implementation of the Authorize Endpoint Data Provider
 * plugin interface {@link org.forgerock.oauth2.core.plugins.AuthorizeEndpointDataProvider}
 *
 * <li>
 * The {@code provide} method returns hard coded additional value.
 * </li>
 *
 */
public class CustomAuthorizeEndpointDataProvider implements AuthorizeEndpointDataProvider {

    @Override
    public Map<String, String> provide(Map<String, Token> tokens, OAuth2Request request) {
        Map<String, String> customMapping = new HashMap<String, String>();
        customMapping.put("additional", "field");
        return customMapping;
    }
}

Example authorization endpoint data provider plugin

Complete the following steps to implement an authorization endpoint data provider script that returns custom user session data:

To configure AM to use a Java authorization endpoint data provider plugin, refer to Configure AM to use a Java OAuth 2.0 plugin.

Configure the authorization endpoint data provider script

This task describes how to modify the default script to retrieve additional fields. To create a new script instead, refer to Manage scripts (UI), and reference the new script name when you configure the provider.

  1. In the AM admin UI, go to Realms > Realm Name > Scripts, and click OAuth2 Authorize Endpoint Data Provider Script.

  2. In the Script field:

    • Enable the script by removing, or commenting out as in this example, the following block comments surrounding the function, on lines 40 and 90:

      // /* EXAMPLE
      ...
      // */
    • For the purposes of this simple test, comment out the call to add data from a third party service:

      //addAdditionalDataFromExternalService();
  3. Save your changes.

The default authorization endpoint data provider script is now amended to return a static key/value pair, "hello": "world", and to get the user’s IP address from the session data.

Configure AM to use the authorization endpoint data provider script

Perform this task to set up an OAuth2 provider to use the authorization endpoint data provider script.

  1. Log in to the AM admin UI as an administrator.

    For example, amAdmin.

  2. Configure the provider to ensure the following properties are set:

    • Authorize Endpoint Data Provider Plugin Type to SCRIPTED.

    • Authorize Endpoint Data Provider Script to OAuth2 Authorize Endpoint Data Provider Script.

      If you created a new script rather than editing the default, you need to reference the new script name here.

  3. Save your changes.

Create an OAuth2 client for authorization

Create an OAuth 2.0 client to use in the authorization request.

  1. In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients, and click Add Client.

  2. Enter the following values:

    • Client ID: myClient

    • Client secret: forgerock

    • Redirection URIs: https://www.example.com:443/callback

    • Scope(s): access|Access to your data

  3. Click Create.

AM is now prepared for you to perform an OAuth2 authorization request to try the sample plugin.

Try the sample authorization endpoint data provider plugin

  1. Log in to AM as the demo user, for example:

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

    Note the SSO token value returned as tokenId in the output.

  2. Invoke the authorization server’s /oauth2/authorize endpoint specifying the SSO token value in a cookie, and the following parameters:

    • client_id=myClient

    • response_type=code

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

    • decision=allow

    • csrf=SSO-token

    For example:

    $ curl --dump-header - \
    --request POST \
    --Cookie "iPlanetDirectoryPro=AQIC5wM…​TU3OQ*" \
    --data "scope=access" \
    --data "response_type=code" \
    --data "client_id=myClient" \
    --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"

    If the authorization server is able to authenticate the user and the client, it returns a successful HTTP 302 response, for example:

    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&ipAddress=127.0.0.1&scope=access&iss=https%3A%2F%2Fopenam.example.com%3A8443%2Fopenam%2Foauth2&hello=world&state=abc123&client_id=myClient
    Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept
    Content-Length: 0

    As the example output indicates, the parameters injected by the authorization endpoint data provider script, ipAddress=127.0.0.1 and hello=world, are both appended to the redirect URL.

Authorization endpoint data provider scripting API

The following properties are available to authorization endpoint data provider scripts.

Binding Description

httpClient

An HTTP client for making external HTTP requests.

The logger instance for the script.

Logger names use the format scripts.OAUTH2_AUTHORIZE_ENDPOINT_DATA_PROVIDER.<script UUID>.(<script name>).

Refer to Debug logging.

scriptName

The display name of the script.

session

The user’s session object if the request contains a session cookie.

For details, refer to SSOToken.

Scope evaluation

This extension point retrieves and evaluates the scope information for an OAuth2 access token.

The default scopes implementation in AM treats scopes as profile attributes for the resource owner. When a resource server or other entity uses the access token to get token information from AM, AM populates the scopes with profile attribute values. For example, if one of the scopes is mail, AM sets mail to the resource owner’s email address in the token information returned.

The plugin lets you extend or modify this behavior by writing your own scope evaluator plugin to populate the scopes with custom values.

Default script

To view the default script, including the available script properties, refer to oauth2-evaluate-scope.js

To view or modify the default script in the AM admin UI, go to Realms > Realm Name > Scripts and select OAuth2 Evaluate Scope Script.

Java interface

org.forgerock.oauth2.core.plugins.ScopeEvaluator

Java sample
Show Sample Code
/*
 * Copyright 2021-2022 ForgeRock AS. All Rights Reserved
 *
 * Use of this code requires a commercial software license with ForgeRock AS.
 * or with one of its affiliates. All use shall be exclusively subject
 * to such license between the licensee and ForgeRock AS.
 */

package org.forgerock.openam.examples;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.forgerock.oauth2.core.AccessToken;
import org.forgerock.oauth2.core.plugins.ScopeEvaluator;

/**
 * Custom implementation of the Scope Evaluator
 * plugin interface {@link org.forgerock.oauth2.core.plugins.ScopeEvaluator}
 *
 * <li>
 * The {@code evaluateScope} method populates scope values to return.
 * </li>
 *
 */
public class CustomScopeEvaluator implements ScopeEvaluator {

    @Override
    public Map<String, Object> evaluateScope(AccessToken token) {
        return mapScopes(token);
    }

    /**
     * Set read and write permissions according to scope.
     *
     * @param token The access token presented for validation.
     * @return The map of read and write permissions,
     *         with permissions set to {@code true} or {@code false},
     *         as appropriate.
     */
    private Map<String, Object> mapScopes(AccessToken token) {
        Set<String> scopes = token.getScope();
        Map<String, Object> map = new HashMap<String, Object>();
        final String[] permissions = {"read", "write"};

        for (String scope : permissions) {
            if (scopes.contains(scope)) {
                map.put(scope, true);
            } else {
                map.put(scope, false);
            }
        }
        return map;
    }
}

Example scope evaluator plugin

This example uses the Java sample provided by AM. Complete the following steps to implement a custom scope evaluator Java plugin that sets read and write values in the access token according to the scope information.

To configure AM to use a scripted scope evaluator plugin, refer to the steps in Configure AM to use a scripted OAuth 2.0 plugin.

Create and deploy the sample scope evaluator Java plugin

  1. Clone the sample code and build a JAR file by following the steps described in How do I access and build the sample code provided for AM? in the Knowledge Base.

    Files Included in the Sample
    pom.xml

    Apache Maven project file for the module.

    This file specifies how to build the sample, and specifies its dependencies on AM components.

    src/main/java/org/forgerock/openam/examples/CustomScopeEvaluator.java

    Sample class for the Scope Evaluator OAuth 2.0 plugin.

    After you successfully build the project, you find the openam-scope-sample-7.3.0.jar in the openam-samples/openam-scope-sample/target directory of the project.

  2. Copy the built JAR file to the /WEB-INF/lib folder where you deployed AM.

  3. Restart AM or the container in which it runs.

Configure AM to use the custom scope evaluator plugin

Perform this task to set up an OAuth 2.0 provider that uses the sample scope evaluator Java implementation.

  1. Log in to the AM admin UI as an administrator.

    For example, amAdmin.

  2. Configure the provider to ensure the following properties are set:

    • Scope Evaluation Plugin Type to JAVA.

    • Scope Evaluation Plugin Implementation Class to org.forgerock.openam.examples.CustomScopeEvaluator.

    By default, a new OAuth 2.0 provider uses the default Java implementation.

  3. Save your changes.

Create an OAuth2 client

Create an OAuth 2.0 client to use in the client credentials grant flow.

  1. In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients, and click Add Client.

  2. Enter the following values:

    • Client ID: myClient

    • Client secret: forgerock

    • Redirection URIs: https://www.example.com:443/callback

    • Scope(s): read write

  3. Click Create.

  4. In Advanced > Grant Types, add Client Credentials.

  5. Save your changes.

AM is now configured for you to try the sample scope evaluator script.

Try the custom scope evaluator Java plugin

To try the custom scope evaluator plugin, use the Client credentials grant flow.

  1. Send a POST request to the /oauth2/access_token endpoint, specifying the grant type as client_credentials, scope as read, and your client details.

    For example:

    $ curl \
    --request POST \
    --data "grant_type=client_credentials" \
    --data "client_id=myClient" \
    --data "client_secret=forgerock" \
    --data "scope=read" \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"
    {
      "access_token": "M3M2Jb2SMjvgWhzNas2SVy2LALg",
      "scope": "read",
      "token_type": "Bearer",
      "expires_in": 3599
    }
  2. Call the oauth2/tokeninfo endpoint to inspect the custom scope values. Include the access token obtained in the previous request.

    For example:

    $ curl \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/tokeninfo\
    ?access_token=M3M2Jb2SMjvgWhzNas2SVy2LALg"
    {
      "access_token": "M3M2Jb2SMjvgWhzNas2SVy2LALg",
      "read": true,
      "grant_type": "client_credentials",
      "auditTrackingId": "f9a8395d-1bac-4cba-8b09-8cc336dc49e2-6810",
      "scope": ["read"],
      "realm": "/alpha",
      "token_type": "Bearer",
      "expires_in": 3583,
      "authGrantId": "l3355H89FDSWsfdKJmvWssGk_oE",
      "write": false,
      "client_id": "myClient"
    }

    As this example indicates, the requested scope read is authorized, but the write scope has not been authorized.

Scope evaluator plugin scripting API

The following properties are available to scope evaluator scripts.

Binding Description

accessToken

The OAuth 2.0 access token. For details, refer to AccessToken.

httpClient

An HTTP client for making external HTTP requests.

identity

Represents an identity that AM can access. For details, refer to AMIdentity.

The logger instance for the script.

Logger names use the format scripts.OAUTH2_EVALUATE_SCOPE.<script UUID>.(<script name>).

Refer to Debug logging.

scriptName

The display name of the script.

Scope validation

Use this plugin to configure the OAuth2 provider to validate the set of requested scopes against the allowed scopes and, optionally, to modify the list of valid scopes.

The plugin comprises four functions or methods that let you customize the validation of scopes at the following endpoints:

Function / Method Endpoint

validateAuthorizationScope

/authorize

validateAccessTokenScope

/authorize and /access_token

validateRefreshTokenScope

/refresh

validateBackChannelAuthorizationScope

/bc_authorize

Default script

To view the default script, including the available script properties, refer to oauth2-validate-scope.js.

To view or modify the default script in the AM admin UI, go to Realms > Realm Name > Scripts and select OAuth2 Validate Scope Script.

Java interface

org.forgerock.oauth2.core.plugins.ScopeValidator

Java sample
Show Sample Code
/*
 * Copyright 2021-2022 ForgeRock AS. All Rights Reserved
 *
 * Use of this code requires a commercial software license with ForgeRock AS.
 * or with one of its affiliates. All use shall be exclusively subject
 * to such license between the licensee and ForgeRock AS.
 */

package org.forgerock.openam.examples;

import java.util.HashSet;
import java.util.Set;

import org.forgerock.oauth2.core.ClientRegistration;
import org.forgerock.oauth2.core.OAuth2Request;
import org.forgerock.oauth2.core.exceptions.ServerException;
import org.forgerock.oauth2.core.plugins.ScopeValidator;

/**
 * Custom implementation of the Scope Validator
 * plugin interface {@link org.forgerock.oauth2.core.plugins.ScopeValidator}
 *
 * <li>
 * The {@code validateAuthorizationScope} method
 * adds default scopes, or any allowed scopes provided.
 * </li>
 *
 * <li>
 * The {@code validateAccessTokenScope} method
 * adds default scopes, or any allowed scopes provided.
 * </li>
 *
 * <li>
 * The {@code validateRefreshTokenScope} method
 * adds the scopes from the access token,
 * or any requested scopes provided that are also in the access token scopes.
 * </li>
 *
 *  * <li>
 *  * The {@code validateBackChannelAuthorizationScope} method
 *  * adds default scopes, or any allowed scopes provided.
 *  * </li>
 *
 */
public class CustomScopeValidator implements ScopeValidator {

    @Override
    public Set<String> validateAuthorizationScope(ClientRegistration clientRegistration, Set<String> scope,
            OAuth2Request oAuth2Request) throws ServerException {

        if (scope == null || scope.isEmpty()) {
            return clientRegistration.getDefaultScopes();
        }

        Set<String> scopes = new HashSet<String>(clientRegistration.getAllowedScopes());
        scopes.retainAll(scope);
        return scopes;
    }

    @Override
    public Set<String> validateAccessTokenScope(ClientRegistration clientRegistration,
            Set<String> scope, OAuth2Request request) throws ServerException {

        if (scope == null || scope.isEmpty()) {
            return clientRegistration.getDefaultScopes();
        }

        Set<String> scopes = new HashSet<String>(clientRegistration.getAllowedScopes());
        scopes.retainAll(scope);
        return scopes;
    }

    @Override
    public Set<String> validateRefreshTokenScope(ClientRegistration clientRegistration,
            Set<String> requestedScope, Set<String> tokenScope, OAuth2Request request) {

        if (requestedScope == null || requestedScope.isEmpty()) {
            return tokenScope;
        }

        Set<String> scopes = new HashSet<String>(tokenScope);
        scopes.retainAll(requestedScope);
        return scopes;
    }

    @Override
    public Set<String> validateBackChannelAuthorizationScope(ClientRegistration clientRegistration,
            Set<String> requestedScopes, OAuth2Request request) throws ServerException {

        if (requestedScopes == null || requestedScopes.isEmpty()) {
            return clientRegistration.getDefaultScopes();
        }

        Set<String> scopes = new HashSet<>(clientRegistration.getAllowedScopes());
        scopes.retainAll(requestedScopes);
        return scopes;
    }
}

Example scope validator plugin

Complete the following steps to implement a scope validator script that modifies the list of valid scopes.

To configure AM to use a Java scope validator plugin, refer to Configure AM to use a Java OAuth 2.0 plugin.

Configure the scope validator script

This task describes how to modify the default script to add an extra scope value. To create a new script instead, refer to Manage scripts (UI), and reference the new script name when you configure the provider.

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

  2. In the Script field:

    • Update the script by inserting the following line of code preceding return scopes; on line 69:

       scopes.add("customscope");
  3. Save your changes.

The default scope validator script is now amended to add customscope to the requested scopes.

Configure AM to use the custom scope validator script

Perform this task to set up the OAuth2 provider to use the scope validator script.

  1. Log in to the AM admin UI as an administrator.

    For example, amAdmin.

  2. Configure the provider to ensure the following properties are set:

    • Scope Validator Plugin Type to SCRIPTED.

    • Scope Validator Script to OAuth2 Scope Validator Script.

    If you created a new script rather than editing the default, you must reference the new script name here.

  3. Save your changes.

Create an OAuth2 client

Create an OAuth 2.0 client to use in the client credentials grant flow.

  1. In the AM console, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients, and click Add Client.

  2. Enter the following values:

    • Client ID: myClient

    • Client secret: forgerock

    • Redirection URIs: https://www.example.com:443/callback

    • Scope(s): access

  3. In Advanced > Grant Types, add Client Credentials.

  4. Click Create.

  5. Save your changes.

AM is now configured for you to try the sample scope validator script.

Try the custom scope validator plugin script

To try your custom script, use the Client credentials grant flow.

  1. Send a POST request to the /oauth2/access_token endpoint, specifying the grant type as client_credentials, scope as access, and your client details.

    For example:

    $ curl \
    --request POST \
    --data "grant_type=client_credentials" \
    --data "client_id=myClient" \
    --data "client_secret=forgerock" \
    --data "scope=access" \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"
    {
      "access_token": "M3M2Jb2SMjvgWhzNas2SVy2LALg",
      "scope": "access",
      "token_type": "Bearer",
      "expires_in": 3599
    }
  2. Call the oauth2/tokeninfo endpoint to inspect the custom scope values. Include the access token value obtained in the previous request.

    For example:

    $ curl \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/tokeninfo\
    ?access_token=M3M2Jb2SMjvgWhzNas2SVy2LALg"
    {
      "access_token": "M3M2Jb2SMjvgWhzNas2SVy2LALg",
      "access": "",
      "grant_type": "client_credentials",
      "auditTrackingId": "f9a8395d-1bac-4cba-8b09-8cc336dc49e2-6810",
      "scope": ["access", "customscope"],
      "realm": "/alpha",
      "token_type": "Bearer",
      "expires_in": 3583,
      "authGrantId": "l3355H89FDSWsfdKJmvWssGk_oE",
      "customscope": "",
      "client_id": "myClient"
    }

    Verify that the response contains both the requested scope and the additional scope, customscope.

Scope validator scripting API

The following properties are available to scope validator scripts.

Binding Description

allowedScopes

The set of scope strings AM allows this client to request.

defaultScopes

The set of scope strings configured as defaults for this client.

httpClient

An HTTP client for making external HTTP requests.

Write a message to the AM debug log.

Logger names use the format scripts.OAUTH2_VALIDATE_SCOPE.<script UUID>.(<script name>).

Refer to Debug logging.

requestedScopes

The set of scope strings in the client request.

scriptName

The display name of the script.

OIDC user info claims

This plugin extension point is invoked when issuing an ID token or during a request to the /userinfo OIDC endpoint. Use this script to retrieve claim values based on an issued access token.

Default script

To view the default script, including the available script properties, refer to oidc-claims-extension.groovy.

To view or modify the default script in the AM admin UI, go to Realms > Realm Name > Scripts and select OIDC Claims Script.

Java interface

org.forgerock.oauth2.core.plugins.UserInfoClaimsPlugin

Java sample
Show Sample Code
/*
 * Copyright 2021-2022 ForgeRock AS. All Rights Reserved
 *
 * Use of this code requires a commercial software license with ForgeRock AS.
 * or with one of its affiliates. All use shall be exclusively subject
 * to such license between the licensee and ForgeRock AS.
 */

package org.forgerock.openam.examples;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.forgerock.oauth2.core.AccessToken;
import org.forgerock.oauth2.core.ClientRegistration;
import org.forgerock.oauth2.core.OAuth2Request;
import org.forgerock.oauth2.core.UserInfoClaims;
import org.forgerock.oauth2.core.plugins.UserInfoClaimsPlugin;

/**
 * Custom implementation of the User Info Claims
 * plugin interface {@link org.forgerock.oauth2.core.plugins.UserInfoClaimsPlugin}
 *
 * <li>
 * The {@code getUserInfo} method
 * populates scope values and sets the resource owner ID to return.
 * </li>
 *
 */
public class CustomUserInfoClaimsPlugin implements UserInfoClaimsPlugin {

    @Override
    public UserInfoClaims getUserInfo(ClientRegistration clientRegistration, AccessToken token, OAuth2Request request) {
        Map<String, Object> response = mapScopes(token);
        response.put("sub", token.getResourceOwnerId());
        UserInfoClaims userInfoClaims = new UserInfoClaims(response, null);
        return userInfoClaims;
    }

    /**
     * Set read and write permissions according to scope.
     *
     * @param token The access token presented for validation.
     * @return The map of read and write permissions,
     *         with permissions set to {@code true} or {@code false},
     *         as appropriate.
     */
    private Map<String, Object> mapScopes(AccessToken token) {
        Set<String> scopes = token.getScope();
        Map<String, Object> map = new HashMap<String, Object>();
        final String[] permissions = {"read", "write"};

        for (String scope : permissions) {
            if (scopes.contains(scope)) {
                map.put(scope, true);
            } else {
                map.put(scope, false);
            }
        }
        return map;
    }
}

Example user info claims plugin

Complete the following steps to implement an example user info claims script that adds a custom claim to the profile scope:

This example is implemented using a script. For a version that uses Java, refer to How do I add custom claims to the OIDC Claims Script? in the Knowledge Base.

Configure the user info claims script

This task describes how to modify the default script to map a custom claim. To create a new script instead, refer to the steps described in Manage scripts (UI), and reference the new script name when you configure the provider.

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

  2. In the Script field:

    • Add a new claim to the script. As a simple example, insert myTestName after the name claim in the claimAttributes section, as follows:

      claimAttributes = [
          "email": userProfileClaimResolver.curry("mail"),
          ...
          "name": userProfileClaimResolver.curry("cn"),
          "myTestName": userProfileClaimResolver.curry("cn")
      ]
    • Add the new claim to the profile scope in the claims map:

      scopeClaimsMap = [
          "email": [ "email" ],
          ...
          "profile": [ "given_name", "zoneinfo", "family_name", "locale", "name", "myTestName" ]

      For a more complex example of customizing the user info claims script, refer to How do I add a session property claim to the OIDC Claims Script? in the Knowledge Base.

      You can also use the script to override the claims included in an ID token. For example, you can add a post_logout_url claim that redirects a user’s browser to the URL specified in the claim, when that user signs out of an End User UI.

      The following example adds a final item to claimAttributes to return https://forgerock.com as the post_logout_url claim. Adapt the method used to return the appropriate URL for your application:

      +

      claimAttributes = [
              //...,
              "post_logout_url": { claim, identity -> return [(claim.getName()): "https://forgerock.com"] }
      ]

      Add the claim for the fr:idm:* scope as a final item in the scopeClaimsMap:

      +

      scopeClaimsMap = [
              //...,
              "fr:idm:*": [ "post_logout_url" ]
      ]

      For more information, refer to How do I override claims in the OIDC ID token in Identity Cloud or AM? in the Knowledge Base.

  3. Save your changes.

The default user info claims script is now amended to retrieve a custom claim for the profile scope.

This script accesses the /userinfo endpoint and retrieves claims from the profile scope only. To retrieve all scopes and claims, use the /introspect endpoint.

Configure AM to use the user info claims script

Perform this task to set up an OAuth2 provider to use your custom script.

  1. Log in to the AM admin UI as an administrator.

    For example, amAdmin.

  2. Configure the provider to ensure the following properties are set:

    • OIDC Claims Plugin Type to SCRIPTED.

    • OIDC Script to OIDC Claims Script.

    If you created a new script rather than editing the default, you must reference the new script name here.

  3. Save your changes.

Create an OAuth2 client for authorization

Create a public OAuth 2.0 client to use in the authorization request.

  1. In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients, and click Add Client.

  2. Enter the following values:

    • Client ID: myClient

    • Client secret: forgerock

    • Redirection URIs: https://www.example.com:443/callback

    • Scope(s): openid profile

  3. Click Create.

  4. In the Core tab, set Client type to Public.

  5. In the Advanced tab, set the following values:

    • Grant Types: Implicit

    • Token Endpoint Authentication Method: none

    • Grant Types: token id_token

AM is now prepared for you to try the sample user info claims script.

Try the custom user info claims plugin script

To try your custom script, use the Implicit grant flow as demonstrated in the following steps.

  1. Log in to AM as the demo user, for example:

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

    Note the SSO token value returned as tokenId in the output.

  2. Invoke the authorization server’s /oauth2/authorize endpoint specifying the SSO token value in a cookie, and the following parameters as a minimum:

    • client_id=myClient

    • response_type=token id_token

    • scope=openid profile

    • nonce=your nonce value

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

    • decision=allow

    • csrf=SSO-token

      For example:

      $ curl --dump-header - \
      --Cookie "iPlanetDirectoryPro=AQIC5wM…​TU3OQ*" \
      --request POST \
      --data "client_id=myClient" \
      --data "response_type=token id_token" \
      --data "scope=openid profile" \
      --data "state=123abc" \
      --data "nonce=abc123" \
      --data "decision=allow" \
      --data "csrf=AQIC5wM…​TU3OQ*" \
      --data "redirect_uri=https://www.example.com:443/callback" \
      "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/authorize"

      If the authorization server successfully authenticates the user, note the value of the access token appended to the redirection URI in the response.

  3. Call the /oauth2/userinfo endpoint to inspect the custom claim values, including the access token obtained from the previous request.

    For example:

    $ curl --request GET --header "Authorization: Bearer az91IvnIQ-uP3Eqw5QqaXXY_DCo" \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/userinfo"
    {
      "given_name":"Demo First Name",
      "family_name":"Demo Last Name",
      "name":"demo",
      "myTestName":"demo",
      "sub":"(usr!demo)",
      "subname":"demo"
    }

    Verify that the response contains the custom claim added by the script (myTestName in this example).

OIDC user info claims scripting API

The following properties are available to user info claims scripts.

Binding Information

claims

A map of the claims the server provides by default. For example:

{
  "sub": "248289761001",
  "updated_at": "1450368765"
}

claimLocales

An array of string values from the claims_locales parameter.

For details, refer to Claims Languages and Scripts in the OpenID Connect Core 1.0 specification.

claimObjects

The default OpenID Connect 1.0 claims provided by AM.

clientProperties

A read-only map of the following client properties. Only present if AM identified the client specified in the request.

allowedGrantTypes

List of the grant types allowed for the client. For details, refer to GrantType.

allowedResponseTypes

The list of the allowed response types for the client.

allowedScopes

The list of the allowed scopes for the client.

clientId

The client’s URI for the request locale.

customProperties

A map of any custom properties added to the client.

Lists or maps are included as sub-maps. For example, a custom property of customMap[Key1]=Value1 is returned as customMap > Key1 > Value1.

To add custom properties to a client, use the AM admin UI. Go to OAuth 2.0 > Clients > Client ID > Advanced, and update the Custom Properties field. Add custom properties as shown in these examples:

customproperty=custom-value1
customList[0]=customList-value-0
customMap[key1]=customMap-value-1

Scripts can then access the custom properties in the following way:

var customProperties = clientProperties.get("customProperties");
var property = customProperties.get("myProperty");

The map is null if AM did not successfully identify the client.

httpClient

An HTTP client for making external HTTP requests.

identity

Represents an identity that AM can access. For details, refer to AMIdentity.

The logger instance for the script.

Logger names use the format scripts.OIDC_CLAIMS.<script UUID>.(<script name>).

Refer to Debug logging.

requestedClaims

A map of requested claims. This is empty unless the request includes the claims query string parameter and AM is configured to support its use.

To configure AM in the AM admin UI, go to Realms > Realm Name > Services > OAuth2 Provider > Advanced OpenID Connect. Enable Enable "claims_parameter_supported" and save your change.

For details about the claims query string parameter, refer to Requesting Claims using the "claims" Request Parameter in the OpenID Connect Core 1.0 specification.

Example:

{
  "given_name": {
    "essential": true,
    "values": [
      "Demo User",
      "D User"
    ]
  },
  "nickname": null,
  "email": {
    "essential": true
  }
}

requestedTypedClaims

A list of the requested claims objects. This is empty unless the request includes the claims query string parameter and Enable "claims_parameter_supported" is enabled in the AM admin UI.

A claim with a single value means the script should return only that value.

requestProperties

A read-only map of the following request properties.

requestUri

The URI as a string.

realm

The realm as a string.

requestParams

A map of request parameters and posted data, where each value is an array of parameters.

To mitigate the risk of reflection-type attacks, use OWASP best practices when handling these parameters. Refer to Unsafe use of Reflection.

scopes

The set of scope strings in the client request.

scriptName

The display name of the script.

session

The user’s session object. For details, refer to SSOToken.