OAuth 2.0
This guide covers concepts, configuration, and usage procedures for working with OAuth 2.0 and ForgeRock Access Management.
AM as the authorization server
How AM plays the role of the authorization server.
Configure AM for OAuth 2.0
Configure AM as an OAuth 2.0 authorization server.
OAuth 2.0 grant flows
Discover the OAuth 2.0 flows and how to implement them in AM.
OAuth 2.0 endpoints
About endpoints AM exposes as an OAuth 2.0 authorization server.
OAuth 2.0 consent
Allow OAuth 2.0 clients to skip consent, and users to save and revoke consent.
OAuth 2.0 scopes
Learn about scopes and how to configure them in AM.
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:
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:
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:
Feature | Details |
---|---|
|
|
|
|
OAuth 2.0 token exchange |
|
Other OAuth 2.0 standards |
|
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:
|
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:
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 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.
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:
-
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 tohttp://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.
-
Configure one AM server as an OAuth 2.0 authorization service, which is described in Authorization server configuration.
-
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.
-
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.
-
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:
-
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 userdemo
passwordCh4ng31t
. 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.Figure 4. Accessing the Apache Tomcat examples -
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
. -
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 tocn|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.
-
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
.-
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. -
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 userdemo
, passwordCh4ng31t
), AM displays an authorization decision page.Figure 5. The authorization decision page displayed to the resource ownerWhen 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.
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.
-
In the AM admin UI, go to Realms > Realm Name > Services, and click Add a Service.
-
From the drop-down list, select the OAuth2 Provider service, leave the remaining fields empty, and click Create.
-
On the OAuth 2.0 provider page, select the Advanced tab.
-
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:
-
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
andnone
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.
-
-
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 thathostname
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) andauditTrackingId
(defined by default in AM) cannot be persisted.
-
-
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.
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:
|
|
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: |
|
Decide how to manage consent You can:
|
|
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:
-
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.
-
Go to Realms > Realm Name > Identity Stores > Identity Store Name > Authentication Configuration.
-
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.
-
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.
-
-
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:
-
For a specific access token REST request.
Set the
auth_chain
parameter. -
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. -
Individually for a realm.
Go to Realms > Realm Name > Authentication > Settings > Core, and set the
Organization Authentication Configuration
property. -
Globally, for all realms.
Go to Configure > Authentication > Core Attributes > Core, and set the
Organization Authentication Configuration
property.
For more information, see Configure sensible default authentication services.
-
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:
-
In the AM admin UI, go to Realms > Realm Name > Services > OAuth2 Provider.
-
On the Core tab, enable Use Client-Side Access & Refresh Tokens.
-
Enable Issue Refresh Tokens and/or Issue Refresh Tokens on Refreshing Access Tokens.
-
Save your changes.
-
Configure client-side token denylisting.
For more information, see Client-side OAuth 2.0 token denylist.
-
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.
For more information, see Client-side OAuth 2.0 token encryption and Client-side OAuth 2.0 token digital signatures.
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. |
-
In the AM admin UI, go to Configure > Global Services > OAuth2 Provider.
-
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
-
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
-
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
-
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.
-
Go to Realms > Realm Name > Services > OAuth2 Provider.
-
On the Core tab, enable Use Client-Side Access & Refresh Tokens.
-
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.
-
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:
-
Go to Realms > Realm Name > Services, and click OAuth2 Provider.
-
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
HS512am.services.oauth2.stateless.signing.RSA
rsajwtsigningkey
PS256
PS384
PS512
RS256
RS384
RS512By 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.
-
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 |
---|---|---|
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:
-
Client A is registered in the
/customers/NA
realm, and it is issued a token there. -
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:
-
Client A is registered in the
/customers/NA
realm, and it is issued a token there. -
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:
-
For examples of requesting scopes from the authorization server, refer to any of the grant flows in OAuth 2.0 grant flows.
-
To create your own implementation of the scope handler, refer to Customize OAuth 2.0.
-
To configure AM to grant scopes dynamically by evaluating authorization policies at runtime, refer to Authorization and policy decisions and Dynamic OAuth 2.0 authorization.
Manage consent
Many OAuth 2.0 and OIDC flows require user consent to grant the client access to the user’s resources.
Implied consent
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:
-
In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Advanced.
-
Select Implied Consent.
-
Save your changes.
-
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.
Gather consent
Configure how the client application appears to the user. The following alternatives are available:
-
Customize the built-in consent screen:
-
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.
-
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.
Store consent decisions
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:
-
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.
-
In the AM admin UI, go to Realms > Realm Name > Services > OAuth2 Provider and select the Consent tab.
-
In the Saved Consent Attribute field, add the name of the attribute you created, such as
custom_consent
. -
Save your changes.
To force AM to prompt for consent for a specific client request, add the prompt=consent parameter.
|
Remote consent
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 thesave_consent
property in the consent response from the RCS must also befalse
. 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, orfalse
if they did not.If
save_consent_enabled
was set tofalse
in the request,save_consent
must also befalse
. 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 |
|
Enable remote consent and specify the agent profile in AM’s OAuth 2.0 provider service. |
|
Configure the remote consent service with AM’s 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:
-
In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Remote Consent, and click Add Remote Consent Agent.
-
Enter an agent ID, for example,
myRCSAgent
, and click Create. -
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.
-
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
, andA256GCM
- AES in Galois Counter Mode (GCM) authenticated encryption mode. -
A128CBC-HS256
,A192CBC-HS384
, andA256CBC-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
, andA256GCM
- AES in Galois Counter Mode (GCM) authenticated encryption mode. -
A128CBC-HS256
,A192CBC-HS384
, andA256CBC-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 inJWKs
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
-
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:
-
In the AM admin UI, go to Realms > Realm Name > Services > OAuth2 Provider.
-
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
.
-
-
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
Figure 8. Configure RCS in an OAuth 2.0 provider -
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:
-
As an administrative user, for example,
amAdmin
log in to the instance that acts as the example remote consent service. -
Go to Realms > Realm Name > Services, and click Add a Service.
-
From the Choose a service type drop-down list, select Remote Consent Service.
-
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.
-
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.
-
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, configurehttps://rcs.example.com:8443/openam/oauth2/consent/jwk_uri
in the Json Web Key URI field. -
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.
-
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 serviceNote 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:
-
Using the AM admin UI.
For details, refer to Create a client profile.
-
Programmatically.
For details, refer to Dynamic client registration.
Create a client profile
-
In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients.
-
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.
-
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*/
, orhttps://[::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
, oren_US_WIN
. If you omit thelocale
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 ofread|
would allow the client to use theread
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
orscope|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
orlocale|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
, oren_US_WIN
. If thelocale
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
orlocale|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
, oren_US_WIN
. If thelocale
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 defaultAuthorization 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 aclient_secret
value. -
client_secret_post
. Clients authenticate with AM (as an authorization server) by including the client credentials in the request body after receiving aclient_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 ofredirect_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
, orsub
, 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
, oren_US_WIN
. If you omit thelocale
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 ofname|
lets the client use thename
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 of0
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 individualacr
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
orclient_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
, whenAuthorization 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
, andA256GCM
- AES in Galois Counter Mode (GCM) authenticated encryption mode. -
A128CBC-HS256
,A192CBC-HS384
, andA256CBC-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.
Refer to Advanced OpenID Connect.
- 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.
Refer to Advanced OpenID Connect.
- 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.
Refer to Advanced OpenID Connect.
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.The JWT response format follows the JWT Response for OAuth Token Introspection Internet Draft.
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.
Refer to Advanced OpenID Connect.
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
RS512am.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.
Refer to Advanced OpenID Connect.
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.
Refer to Advanced OpenID Connect.
AM supports the following encryption methods:
-
A128GCM
,A192GCM
, andA256GCM
- AES in Galois Counter Mode (GCM) authenticated encryption mode. -
A128CBC-HS256
,A192CBC-HS384
, andA256CBC-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 defaultoauth2Scopes
policy set. - Access Token Modification Plugin Type
-
This setting determines the type of plugin that is invoked:
-
SCRIPTED
to run the script defined inAccess Token Modification Script
. -
JAVA
to run the class defined inAccess 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 toSCRIPTED
.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 whenAccess Token Modification Plugin Type
is set toJAVA
.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 inOIDC Claims Script
. -
JAVA
to run the class defined inOIDC 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 toSCRIPTED
.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 whenOIDC Claims Plugin Type
is set toJAVA
.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 inScope Evaluation Script
. -
JAVA
to run the class defined inScope 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 setsmail
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 inScope Validation Script
. -
JAVA
to run the class defined inScope 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 inAuthorize Endpoint Data Provider Script
. -
JAVA
to run the class defined inAuthorize 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
orazp
.
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?
-
-
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
-
In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients.
-
On the Groups tab, click + Add Group, and click Create.
-
Adjust the configuration as needed, saving changes on each tab.
Inherit group settings
-
In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID.
-
On the Core tab, select the Group in the drop-down.
-
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.
Figure 9. Inheriting group settings -
Inherit settings by clicking their inheritance icons .
The icon changes to , indicating the setting is inherited.
-
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:
-
Go to Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Advanced.
-
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 For example, a client with ID
|
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:
-
Go to Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Advanced.
-
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:
-
Go to Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Advanced.
-
Add Grant Types:
JWT Bearer
. -
Set Token Endpoint Authentication Method to
private_key_jwt
. -
Save your work before switching tabs.
-
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:
-
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-----
-
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:
-
Set Public key selector to
JWKs
. -
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:
-
Set Public key selector to
JWKs_URI
. -
Paste the URI to the JWK set into the Json Web Key URI field.
-
-
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:
-
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.
-
The issuer returns a signed JWT to the client.
-
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
-
-
AM validates the JWT using the public key from the client profile.
-
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 | ||
---|---|---|---|
|
The authorization server that is the intended audience of the JWT;
must be the AM token endpoint, such as
|
||
|
The expiration time. This must be at most 30 minutes in the future.
If not, AM returns a |
||
|
The unique identifier of the issuer that digitally signs the JWT:
|
||
|
A random, unique identifier for the JWT. Required if the client requests the |
||
|
The principal who is the subject of the JWT; must be the |
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.
For details, refer to How do I access and build the sample code provided for AM (All versions)? in the Knowledge Base.
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.
-
If you have not already done so, create an OAuth 2.0 client profile in AM.
For more information, see Client application registration.
-
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.
-
-
Import the certificates belonging to the certificate authorities you want the instance of AM to trust.
-
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.
-
-
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.
-
-
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:
-
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. -
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. -
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.
-
If you have not already done so, create an OAuth 2.0 client profile in AM.
For more information, see Client application registration.
-
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:
-
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.
-
-
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.
-
-
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.
-
-
-
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. |
-
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 usesgrant_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 }
-
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:
-
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.-
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:
-
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.
-
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.
-
-
The client requests access to the protected resources from the resource server.
-
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.
-
-
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.
-
The resource server sends the challenge to the client.
-
The client solves the challenge using its private key.
-
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
-
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
-
Under the Advanced tab, add Grant Type:
Client Credentials
and save your work.
Get an access token
-
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.
-
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" } }
-
Base64-encode your JWK, as in the following example:
ewogICJqd2siOiB7CiAgICAia3R5IjogIkVDIiwKICAgICJ1c2UiOiAiZW5jIiwKICAgICJjc nYiOiAiUC0yNTYiLAogICAgImtpZCI6ICJteVB1YmxpY0pzb25XZWJLZXkiLAogICAgIngiOi AiRDVrTnFvR1piTFphNzd4ZGg0SFNsU1pJSmNIeE53NFVQMHBnZDV3Ylh2VSIsCiAgICAieSI 6ICJ0WDNTblJaZ1VPeTQ4RlYwWFRDdGFRTkxHX0R4WEdiY1ZrOTRLdnB5WHJrIgogIH0KfQ==
-
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
-
The client uses the access token to request a protected resource on the resource server.
This step is not shown in the demonstration.
-
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" }
-
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.
-
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.
Certificate-Bound Proof-of-Possession Flow Explained
-
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.
-
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 typex5t#S256
, which contains the base64URL-encoded SHA-256 hash of the DER-encoding of the full X.509 certificate. -
-
The client, communicating over mTLS, requests access to the protected resources from the resource server.
-
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 thecnf
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.
-
-
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:
-
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.
-
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.
-
-
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.
-
-
Configure the client for mutual TLS authentication.
For more information, see Mutual TLS.
-
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 }
-
-
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 typex5t#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:
-
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 theTrusted 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.
-
-
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.
-
-
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 }
-
-
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 typex5t#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
-
Create a confidential OAuth 2.0 client account.
-
In the AM admin UI, select Realm > Realm Name > Applications > OAuth 2.0 > Clients and click + Add Client.
-
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:
-
In the AM admin UI, select Identities > + Add Identity and fill the required fields.
-
Record the username and password.
Get an access token
-
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"}
-
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… …
-
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
}
|
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:
|
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:
-
In the AM admin UI, go to Realms > Realm Name > Services > OAuth2 Provider.
-
On the Core tab, enable Use Macaroon Access and Refresh Tokens and save your changes.
-
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 useV1
when you require compatibility with older macaroon libraries. -
Set the OAuth2 Token Signing Algorithm to
HS256
or stronger. -
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:
Client Type | Which Grant to use? | Description |
---|---|---|
The client is a web application running on a server.
For example, a |
(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. For more information, see Certificate-bound proof-of-possession and JWK-based proof-of-possession. |
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.
-
Download and install Postman.
-
Download the ForgeRock OAuth 2.0 and OpenID Connect Collection.
-
Import the collection in Postman:
-
Go to File > Import … > Upload Files.
-
Select the collection you downloaded, and click Open. Then, click Import.
-
-
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
-
-
/oauth2/userinfo (OpenID Connect [OIDC])
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:
-
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.
-
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
-
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.
-
The client redirects the resource owner’s user-agent to the authorization server.
-
The authorization server authenticates the resource owner, confirms resource access, and gathers consent if not previously saved.
-
The authorization server redirects the resource owner’s user agent to the client.
-
During the redirection process, the authorization server appends an authorization code.
-
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.
-
If the authorization code is valid, the authorization server returns an access token (and a refresh token, if configured) to the client.
-
The client requests access to the protected resource from the resource server.
-
The resource server contacts the authorization server to validate the access token.
-
The authorization server validates the token and responds to the resource server.
-
If the token is valid, the resource server allows the client to access the protected resource.
OIDC
-
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.
-
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…
-
…to the OP.
-
The OP authenticates the end user, confirms resource access, and gathers consent if necessary.
-
The OP redirects the end user’s user-agent to the RP.
-
During the redirection process, the OP appends an authorization code.
-
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.
-
If the authorization code is valid, the OP returns an access token and an ID token to the RP.
-
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.
-
If the RP requires additional claims, it sends a request to the /oauth2/userinfo endpoint with the access token for authorization.
-
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
andprofile
(for OIDC) -
Response Types:
code
-
Grant Types:
Authorization Code
For more information, refer to Client application registration.
-
Get an authorization code using a browser
-
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. -
-
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. -
On a successful login, the authorization server presents the AM consent screen unless AM is configured to use implied consent.
Figure 13. OAuth 2.0 consent screen -
Click Allow to consent.
The authorization server redirects the resource owner to the URL specified in the
redirect_uri
parameter. -
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…
-
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
-
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" }
-
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… …
-
-
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
-
-
/oauth2/userinfo (OpenID Connect [OIDC])
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
-
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.
-
The client redirects the resource owner’s user-agent to the authorization server.
-
The authorization server authenticates the resource owner, confirms resource access, and gathers consent if not previously saved.
-
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.
-
During the redirection process, the authorization server appends an authorization code to the request to the client.
-
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.
-
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.
-
The client requests access to the protected resource from the resource server.
-
The resource server contacts the authorization server to validate the access token.
-
The authorization server validates the token and responds to the resource server.
-
If the token is valid, the resource server allows the client to access the protected resource.
OIDC
-
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.
-
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.
-
The RP redirects the end user’s user-agent with
code_challenge
andcode_challenge_method
… -
…to the OP.
-
The OP authenticates the end user, confirms resource access, and gathers consent if necessary.
-
On success, the OP stores the code challenge and its method.
-
The OP redirects the end user’s user-agent to the redirection URI, usually at the RP.
-
During the redirection process, the OP appends an authorization code.
-
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.
-
The OP verifies the code challenge it stored using the validation code, and verifies the authorization code.
-
If the codes are valid, the OP issues an access token and an ID token to the RP.
-
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.
-
If the RP requires additional claims, it sends a request to the /oauth2/userinfo endpoint with the access token for authorization.
-
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
andprofile
(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
-
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. -
-
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. -
On a successful login, the authorization server presents the AM consent screen unless AM is configured to use implied consent.
Figure 14. OAuth 2.0 consent screen -
Click Allow to consent.
The authorization server redirects the resource owner to the URL specified in the
redirect_uri
parameter. -
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…
-
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
-
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" }
-
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 thecode_challenge
parameter, AM will honor the code exchange regardless of theCode 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… …
-
-
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
- Endpoints
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
-
The client pushes a request to the PAR endpoint, providing both client and request details.
-
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.
-
The client receives a request to access a protected resource. To access the resources, the client requires authorization from the resource owner.
-
The client redirects the resource owner’s user-agent to the authorization server.
-
The authorization server authenticates the resource owner, confirms resource access, and gathers consent if not previously saved.
-
The client requests an authorization code, typically through a web browser, by passing in the request_uri and client_id.
-
The client_id is validated against the request, and if successful, the authorization code is returned to the client.
-
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.
-
If the authorization code is valid, the authorization server returns an access token (and a refresh token, if configured) to the client.
-
The client requests access to the protected resources from the resource server.
-
The resource server contacts the authorization server to validate the access token.
-
The authorization server validates the token and responds to the resource server.
-
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
-
Ensure the client has retrieved a request URI by following the steps described in Get a PAR request URI.
-
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. -
-
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. -
On a successful login, the authorization server presents the AM consent screen unless AM is configured to use implied consent.
Figure 16. OAuth 2.0 consent screen -
Click Allow to consent.
The authorization server redirects the resource owner to the URL specified in the
redirect_uri
parameter. -
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…
-
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
-
Ensure the client has retrieved a request URI by following the steps described in Get a PAR request URI.
-
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" }
-
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… …
-
-
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
-
-
/oauth2/userinfo (OpenID Connect [OIDC])
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
-
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.
-
The client redirects the resource owner’s user-agent or opens a new frame to the AM authorization service.
-
The authorization server authenticates the resource owner, confirms resource access, and gathers consent if not previously saved.
-
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.
-
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.
-
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.
-
The user-agent executes the script and retrieves the access token.
-
The user-agent returns the access token to the client.
-
The client requests access to the protected resource presenting the access token to the resource server.
-
The resource server contacts the authorization server to validate the access token.
-
The authorization server validates the token and responds to the resource server.
-
If the token is valid, the resource server allows the client to access the protected resource.
OIDC
-
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.
-
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 thenonce
parameter. -
The OP authenticates the end user, confirms resource access, and gathers consent if necessary.
-
On success, the OP returns access and ID tokens to the user-agent in the redirection URI.
-
The user-agent extracts the tokens from the URI.
In this example, the user-agent follows the redirection to the RP without the tokens.
-
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.
-
The user-agent executes the script and retrieves the tokens.
-
The user-agent returns the tokens to the RP.
-
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.
-
If the RP requires additional claims, it sends a request to the /oauth2/userinfo endpoint with the access token for authorization.
-
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
andprofile
(for OIDC) -
Response Types:
token
andtoken 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:
-
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
andprofile
(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
andresponse_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. -
-
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:
Figure 17. OAuth 2.0 consent screen -
The resource owner selects the
Allow
button to grant consent for thewrite
scope.The authorization server redirects the resource owner to the URL specified in the
redirect_uri
parameter. -
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
-
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" }
-
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
andprofile
(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
andresponse_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
- Endpoints
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).
ROPC grant flow explained
-
The resource owner provides the client with their username and password.
-
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.
-
If the credentials are valid, the authorization server returns an access token to the client.
-
The client requests access to the protected resources presenting the access token to the resource server.
-
The resource server contacts the authorization server to validate the access token.
-
The authorization server validates the token and responds to the resource server.
-
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 theExample
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:
-
For a specific access token REST request.
Set the
auth_chain
parameter. -
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. -
Individually for a realm.
Go to Realms > Realm Name > Authentication > Settings > Core, and set the
Organization Authentication Configuration
property. -
Globally, for all realms.
Go to Configure > Authentication > Core Attributes > Core, and set the
Organization Authentication Configuration
property.
For more information, see Configure sensible default authentication services.
-
-
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:
-
The resource owner provides their credentials to the client. This is done outside the scope of this procedure.
-
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
- Endpoints
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.
Client credentials grant flow explained
-
The client sends its credentials to the authorization server to get authenticated, and requests an access token.
-
If the client credentials are valid, the authorization server returns an access token to the client.
-
The client requests access to the protected resources from the resource server.
-
The resource server contacts the authorization server to validate the access token.
-
The authorization server validates the token and responds to the resource server.
-
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.
-
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.
Device flow explained
-
The client device requests a device code from AM.
-
AM returns a device code, a user code, a URL for entering the user code, and an interval, in seconds.
-
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.
-
The client device begins to continuously poll AM to see if authorization has been completed.
-
If the user has not yet completed the authorization, AM returns an HTTP 403 status code, with an
authorization_pending
message. -
The user follows the instructions from the client device to enter the user code by using a separate device.
-
If the user code is valid, AM redirects the resource owner for authentication.
-
Upon authentication, the user is prompted to confirm the user code. The page is pre-populated with the one entered before.
-
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. -
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:
-
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.
-
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:
-
To grant access to the client using a browser, see Grant consent with a user code using a browser in the device flow.
-
To grant access to the client without using a browser, see Grant consent with a user code without using a browser in the device flow.
-
-
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.
For more information, see Poll for authorization in the OAuth 2.0 device flow.
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:
-
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" }
-
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 theclient_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:
-
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
. -
The resource owner logs in to the authorization server using, for example, the
demo
user credentials. -
The resource owner enters their user code:
Figure 21. OAuth 2.0 User Code -
The resource owner authorizes the device flow client by allowing the requested scopes:
Figure 22. OAuth 2.0 Consent PageIf the client uses implied consent, AM does not display this screen.
-
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:
Figure 23. OAuth 2.0 Done PageThe 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:
-
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.
Device flow with PKCE explained
-
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.
-
The client device requests a device code from AM, appending the code challenge previously generated to the request.
-
AM returns a device code, a user code, a URL for entering the user code, and an interval, in seconds.
-
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.
-
The client device begins to continuously poll AM to see if authorization has been completed, appending the code verifier previously generated.
-
If the user has not yet completed the authorization, AM returns an HTTP 403 status code, with an
authorization_pending
message. -
The user follows the instructions from the client device to enter the user code by using a separate device.
-
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.
-
Upon authentication, the user is prompted to confirm the user code. The page is pre-populated with the one entered before.
-
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. -
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 thecode_challenge
parameter, AM will honor the code exchange regardless of theCode 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:
-
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.
-
-
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:
-
To grant access to the client using a browser, see Grant consent with a user code using a browser in the device flow with PKCE.
-
To grant access to the client without using a browser, see Grant consent with a user code without using a browser in the device flow with PKCE.
-
-
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:
-
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" }
-
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 theclient_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:
-
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
. -
The resource owner logs in to the authorization server using, for example, the
demo
user credentials. -
The resource owner enters their user code:
Figure 25. OAuth 2.0 User Code -
The resource owner authorizes the device flow client by allowing the requested scopes:
Figure 26. OAuth 2.0 Consent PageIf the client uses implied consent, AM does not display this screen.
-
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:
Figure 27. OAuth 2.0 Done PageThe 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:
-
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
- Endpoints
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:
-
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.
-
The SAML v2.0 identity provider returns the signed assertion to the client.
-
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"
-
-
The AM authorization server validates the assertion. If the assertion is valid, the authorization server returns an access token to the client.
-
The client request access to the protected resources from the resource server.
-
The resource server contacts the authorization server to validate the access token.
-
The authorization server validates the token and responds to the resource server.
-
If the token is valid, the resource server allows the client to access the protected resources.
JWT profile for OAuth 2.0 authorization grant
- Endpoints
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.
-
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.
-
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 thepreferred_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.
-
-
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.
-
-
AM validates the JWT following the guidance specified in section 3 of the RFC7523 and also performs the following additional checks:
-
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. -
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
. -
-
The authorization server issues an access token to the client.
-
The client requests access to the protected resources from the resource server.
-
The resource server contacts the authorization server to validate the access token.
-
The authorization server validates the token and responds to the resource server.
-
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:
-
In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Trusted JWT Issuer.
-
Add a new trusted JWT issuer agent.
-
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.
-
-
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.
-
-
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 theread
andwrite
scopes, AM will only grant theread
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, thesub
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 isdemo2
, AM will not grant the access token.Leave it blank to provide consent to any user.
-
-
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. |
-
Create a trusted JWT issuer script.
-
In the AM admin UI, go to Realms > Realm Name > Scripts and click New Script.
-
Enter a unique name for your script and select
OAuth2 Trusted JWT Issuer
from the Script Type drop-down list. Click Create. -
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; }());
-
Click Save Changes.
-
-
Configure AM to use the script.
-
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.
-
Click Add a Secondary Configuration.
-
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 For example, this JWT references a service account with the identifier
|
Token exchange
AM supports RFC 8693, OAuth 2.0 Token Exchange for OAuth 2.0 and OpenID Connect tokens:
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 |
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
andmay_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:
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:
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:
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 thesub
(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
ascustomMap
>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 theirauditTrackingId
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.
Refer to Unsafe use of Reflection.
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 amay_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 |
---|---|
|
Required. Use |
|
Required. The original token to exchange. Example: |
|
Required. The type of subject token, either access token or ID token. One of:
|
|
Required for delegation. The token representing the delegate. Example: |
|
Required for delegation. The type of actor token, either access token or ID token. One of:
|
|
Optional. The type of requested exchanged token, either access token or ID token. One of:
|
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.
-
In the AM admin UI, select Realm > Realm Name > Scripts + New Script.
-
In the New Script window, name the script
May act
and set Script Type toOAuth2 May Act
. -
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.
-
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
-
Switch to the Advanced tab, enable Implied consent, and save your work:
-
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.
-
In the AM admin UI, select Realm > Realm Name > Applications > OAuth 2.0 > Clients > + Add Client.
-
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
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:
-
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"}
-
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… …
-
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 themay_act
claim, you must introspect the access token. -
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.
-
In the AM admin UI, select Realm > Realm Name > Scripts + New Script.
-
In the New Script window, name the script
May act
and set Script Type toOAuth2 May Act
. -
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.
-
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
-
Switch to the Advanced tab, enable Implied consent, and save your work:
-
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.
-
In the AM admin UI, select Realm > Realm Name > Applications > OAuth 2.0 > Clients > + Add Client.
-
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
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:
-
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"}
-
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… …
-
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 themay_act
claim, you must introspect the access token. -
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}
-
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).
For details, refer to Generate a code verifier and a code challenge.
code_challenge_method
A string specifying the method to derive the PKCE code challenge:
-
plain
(default; plaintext code challenge ) -
S256
(recommended; hashed code challenge)
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
client_credentials
-
For the Client credentials grant.
password
refresh_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
urn:ietf:params:oauth:grant-type:jwt-bearer
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
andresponse_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 thetoken
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
oraccess_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
For details, refer to JWT-Secured Authorization Response Mode for OAuth 2.0 (JARM).
-
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
ortoken
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
andaud
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) andnbf
(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
andnbf
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 theclient_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
andstate
, visible and mutable across calls.The claims in the request object supersede the query string parameters.
-
You must include the
response_type
andclient_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 thescope
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 theresponse_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
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:
-
Authorization code grant (OAuth 2.0 and OIDC)
-
Authorization code grant with PKCE (OAuth 2.0 and OIDC)
-
Implicit grant (OAuth 2.0 and OIDC)
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 |
---|---|---|
The OpenID Connect authentication context class reference values. |
||
The user attributes to be returned in the ID token. |
No |
|
A signed JSON Web Token (JWT) to use as client credentials. |
Yes, for JWT profile authentication |
|
The type of assertion, |
Yes, for JWT profile authentication |
|
Uniquely identifies the application making the request. |
Yes, even when it is also included in a |
|
The password for a confidential client. |
Yes, when authenticating with Form parameters (HTTP POST) |
|
The code verifier generated for the PKCE flow. |
Yes, for confidential clients and for all clients using the Authorization code grant with PKCE flow |
|
The method to derive the code challenge. |
Yes, when the |
|
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 |
|
Specifies whether the resource owner consents to the requested access. |
Yes, when gathering consent unless consent is already saved for the scope |
|
Previously issued ID token previously passed as a hint about the end user’s session with the client. |
No |
|
String value that can be set to the ID the user uses to log in. |
No |
|
String value that associates the client session with the ID token. |
No |
|
Specifies whether to prompt the end user for authentication and consent. |
No |
|
The URI to return the resource owner to after authorization is complete. |
No |
|
A base64url-encoded JWT with the claims required for PAR validation.(1) |
Yes |
|
Specifies the mechanism for returning response parameters. |
No |
|
The type of response expected from the authorization server. |
Yes |
|
Specifies whether to store a resource owner’s consented scopes. |
No |
|
The scopes linked to the permissions requested by the client from the resource owner. |
No |
|
The authentication journey to use when authenticating the resource owner. |
No |
|
The value to maintain state between the request and the callback. |
No, but strongly recommended |
|
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:
-
Authorization code grant (OAuth 2.0 and OIDC)
-
Authorization code grant with PKCE (OAuth 2.0 and OIDC)
-
Authorization code grant with PAR (OAuth 2.0)
-
Implicit grant (OAuth 2.0 and OIDC)
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 |
---|---|---|
The OpenID Connect authentication context class reference values. |
||
The user attributes to be returned in the ID token. |
No |
|
Uniquely identifies the application making the request. |
Yes |
|
The code verifier generated for the PKCE flow. |
Yes, for the Authorization code grant with PKCE flow |
|
The method to derive the code challenge. |
Yes, when the |
|
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 |
|
Specifies whether the resource owner consents to the requested access. |
Yes, when gathering consent unless consent is already saved for the scope |
|
Previously issued ID token passed as a hint about the end user’s session with the client. |
No |
|
String value that can be set to the ID the user uses to log in. |
No |
|
String value that associates the client session with the ID token. |
No |
|
Specifies whether to prompt the end user for authentication and consent. |
No |
|
The URI to return the resource owner to after authorization is complete. |
No |
|
Specifies the mechanism for returning response parameters. |
No |
|
The type of response expected from the authorization server. |
Yes |
|
The JWT request object. |
Yes, for JAR request and OIDC flows requiring a request object and providing no |
|
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 |
|
Specifies whether to store a resource owner’s consented scopes. |
No |
|
The scopes linked to the permissions requested by the client from the resource owner. |
No |
|
The authentication journey to use when authenticating the resource owner. |
No |
|
The value to maintain state between the request and the callback. |
No, but strongly recommended |
|
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:
-
Backchannel request grant (OpenID Connect)
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 |
---|---|---|
A signed JSON Web Token (JWT) to use as client credentials. |
Yes, for JWT profile authentication |
|
The type of assertion, |
Yes, for JWT profile authentication |
|
Uniquely identifies the application making the request. |
Yes |
|
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 |
---|---|---|
|
A string identifying the mechanism for the end user to provide authorization. |
|
|
A string or array of strings indicating the intended audience of the JWT. Must include the authorization server OAuth 2.0 endpoint. |
|
|
A short (100 character max.) string message to display to the user when obtaining authorization. For push notification, messages must:
|
|
|
The expiration time in seconds since January 1, 1970 UTC.
An expiration time more than 30 minutes in the future causes a |
|
|
An ID token identifying the principal and subject of the JWT (the end user). Required when not using |
|
|
The unique identifier of the JWT issuer; must match the client ID in the application profile. |
|
|
A string identifying the principal and subject of the JWT (the end user). Required when not using |
|
|
A string holding a space-separated list of the requested scopes; must include |
|
/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:
-
Authorization code grant (OAuth 2.0 and OIDC)
-
Authorization code grant with PKCE (OAuth 2.0 and OIDC)
-
Authorization code grant with PAR (OAuth 2.0)
-
Client credentials grant (OAuth 2.0)
-
Resource owner password credentials grant (OAuth 2.0)
-
Device flow (OAuth 2.0)
-
SAML v2.0 profile for authorization grant (OAuth 2.0)
-
Token exchange (OAuth 2.0 | OpenID Connect)
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 |
---|---|---|
The token representing a delegate acting on behalf of another identity. |
Yes, for Token exchange |
|
The type of actor token. |
Yes, for Token exchange |
|
A string naming the journey to authenticate the resource owner. |
No, only for Resource owner password credentials grant |
|
|
A string holding a base64-encoded then URL-encoded SAML v2.0 assertion |
Yes, when |
A signed JSON Web Token (JWT) to use as client credentials. |
Yes, for JWT profile authentication |
|
The type of assertion, |
Yes, for JWT profile authentication |
|
Uniquely identifies the application making the request. |
Yes |
|
The password for a confidential client; do not use with |
Yes, when authenticating with Form parameters (HTTP POST) |
|
A base64-encoded JSON Web Key (JWK) or hash of the X.509 certificate; do not use with |
Yes, for Proof-of-possession. |
|
|
A string holding the authorization code for an authorization code grant. |
Yes, when |
A random string correlating a PKCE authorization request with the token request. |
Yes, for flows with PKCE |
|
|
A string holding the device code requested from the user for a device flow. |
Yes, when |
A string specifying the type of grant to acquire an access token. |
Yes |
|
|
A string holding the resource owner password for the Resource owner password credentials grant. |
Yes, when |
The URI to return the resource owner to after authorization is complete. |
Yes, when |
|
|
The refresh to get a new access token. |
Yes, for Refresh tokens |
The type of token requested in exchange. |
No, but recommended for Token exchange |
|
The scopes linked to the permissions requested by the client from the resource owner. |
No |
|
The original token to exchange. |
Yes, for Token exchange |
|
The type of subject token. |
Yes, for Token exchange |
|
|
A string holding the resource owner username for the Resource owner password credentials grant. |
Yes, when |
/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 |
---|---|---|
The OpenID Connect authentication context class reference values. |
||
The user attributes to be returned in the ID token. |
No |
|
Uniquely identifies the application making the request. |
Yes |
|
The code verifier generated for the PKCE flow. |
Yes, for the Authorization code grant with PKCE flow |
|
The method to derive the code challenge. |
Yes, when the |
|
String value that can be set to the ID the user uses to log in. |
No |
|
String value that associates the client session with the ID token. |
No |
|
Specifies whether to prompt the end user for authentication and consent. |
No |
|
The scopes linked to the permissions requested by the client from the resource owner. |
No |
|
The value to maintain state between the request and the callback. |
No, but strongly recommended |
|
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 |
---|---|---|
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 |
|
Specifies whether the resource owner consents to the requested access. |
Yes, when gathering consent unless consent is already saved for the scope |
|
Specifies whether to store a resource owner’s consented scopes. |
No |
|
The scopes linked to the permissions requested by the client from the resource owner. |
No |
|
|
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 |
---|---|---|
A signed JSON Web Token (JWT) to use as client credentials. |
Yes, for JWT profile authentication |
|
The type of assertion, |
Yes, for JWT profile authentication |
|
Uniquely identifies the application making the request. |
Yes |
|
The password for a confidential client. |
Yes, when authenticating with Form parameters (HTTP POST) |
|
|
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 |
---|---|---|
A signed JSON Web Token (JWT) to use as client credentials. |
Yes, for JWT profile authentication |
|
The type of assertion, |
Yes, for JWT profile authentication |
|
Uniquely identifies the application making the request. |
Yes |
|
The password for a confidential client. |
Yes, when authenticating with Form parameters (HTTP POST) |
|
|
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:
-
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.
-
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
-
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 |
---|---|
|
Whether the token is active ( |
|
The AM authentication level for the resource owner who granted access to the token. |
|
The client the token was issued to. |
|
The confirmation key claim. The |
|
Expiration time in seconds since January 1, 1970 UTC. |
|
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. |
|
The token issuer. |
|
The macaroon the token validates, including any caveats. |
|
(UMA only) An array containing the following:
|
|
The space-separated list of the scopes associated with the token. |
|
The subject of the access token. The subject claim is in the format
For example, |
|
The type of token. |
|
Deprecated form of |
|
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 |
---|---|
|
Return details about the macaroon. |
|
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:
|
Legacy OAuth 2.0 endpoints
AM exposes the following legacy 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 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 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:
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 |
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.
-
To view the contents of the default scripts in the AM admin UI, including the available script properties, go to Realms > Realm Name > Scripts and select the script you want to examine.
-
To view all the sample JavaScript and Groovy scripts, refer to Sample scripts.
-
To use a plugin script, follow these steps:
-
To step through an example of a scripted implementation, refer to Access token modification.
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.
-
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.
-
Set the
Plugin Type
attribute toSCRIPTED
. -
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 typeOAuth2 Validate Scope
.For further details about setting plugin configuration, refer to the OAuth2 provider configuration and Client overrides.
-
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.
-
To view the supported plugin interfaces, refer to the Javadoc for the
org.forgerock.oauth2.core.plugins
package. -
To view the sample and custom classes, refer to the details for the individual plugin points.
-
To use a Java plugin, follow these steps:
-
To step through an example of a Java implementation, refer to the Scope evaluation.
Create and deploy a Java OAuth 2.0 plugin
-
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.
-
Copy the built JAR file to the
/WEB-INF/lib
folder where you deployed AM. -
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.
-
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.
-
Set the
Plugin Type
attribute toJAVA
. -
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.
-
Save your changes.
OAuth 2.0 scripting API
For information about the API available for implementing scripts, refer to:
-
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 |
---|---|
|
An HTTP client for making external HTTP requests. |
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. |
|
|
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
- 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.
-
Log in as an AM administrator, for example,
amAdmin
. -
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.
-
Select Realms > Realm Name > Identities.
-
On the Identities tab, select the
demo
user. -
In Email Address, enter a valid address. For example,
demo.user@example.com
. -
In Telephone Number, enter a value. For example,
44 117 496 0228
. -
Save your changes.
-
-
Modify the default access token modification script to set additional fields.
-
Go to Realms > Realm Name > Scripts, and click OAuth2 Access Token Modification Script.
-
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 }
-
-
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.
-
Log in to the AM admin UI as an administrator.
For example,
amAdmin
. -
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.
-
-
Save your changes.
Create an OAuth2 client for authorization
Create an OAuth 2.0 client to use in the authorization request.
-
In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients, and click Add Client.
-
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
-
-
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
-
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.
-
Log in as the
demo
user, with passwordCh4ng31t
.The AM OAuth 2.0 consent page is displayed.
-
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:
-
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
-
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 }
-
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
-
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 asmail
andphone
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 | ||
---|---|---|---|
|
The OAuth 2.0 access token. For details, refer to AccessToken. |
||
|
A map of properties configured in the client profile. Only present if the client was correctly identified. The map has the following keys:
|
||
|
An HTTP client for making external HTTP requests. |
||
|
Represents an identity that AM can access. For details, refer to AMIdentity. |
||
The logger instance for the script. Logger names use the format Refer to Debug logging. |
|||
|
A map of the properties present in the request. The map has the following keys:
|
||
|
The display name of the script. |
||
|
An array of the requested scopes; for example:
|
||
|
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.
-
In the AM admin UI, go to Realms > Realm Name > Scripts, and click OAuth2 Authorize Endpoint Data Provider Script.
-
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();
-
-
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.
-
Log in to the AM admin UI as an administrator.
For example,
amAdmin
. -
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.
-
-
Save your changes.
Create an OAuth2 client for authorization
Create an OAuth 2.0 client to use in the authorization request.
-
In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients, and click Add Client.
-
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
-
-
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
-
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. -
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
andhello=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 |
---|---|
|
An HTTP client for making external HTTP requests. |
The logger instance for the script. Logger names use the format Refer to Debug logging. |
|
|
The display name of the script. |
|
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
- 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
-
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 theopenam-samples/openam-scope-sample/target
directory of the project. -
Copy the built JAR file to the
/WEB-INF/lib
folder where you deployed AM. -
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.
-
Log in to the AM admin UI as an administrator.
For example,
amAdmin
. -
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.
-
-
Save your changes.
Create an OAuth2 client
Create an OAuth 2.0 client to use in the client credentials grant flow.
-
In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients, and click Add Client.
-
Enter the following values:
-
Client ID:
myClient
-
Client secret:
forgerock
-
Redirection URIs:
https://www.example.com:443/callback
-
Scope(s):
read
write
-
-
Click Create.
-
In Advanced > Grant Types, add
Client Credentials
. -
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.
-
Send a POST request to the /oauth2/access_token endpoint, specifying the grant type as
client_credentials
, scope asread
, 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 }
-
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 thewrite
scope has not been authorized.
Scope evaluator plugin scripting API
The following properties are available to scope evaluator scripts.
Binding | Description |
---|---|
|
The OAuth 2.0 access token. For details, refer to AccessToken. |
|
An HTTP client for making external HTTP requests. |
|
Represents an identity that AM can access. For details, refer to AMIdentity. |
The logger instance for the script. Logger names use the format Refer to Debug logging. |
|
|
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 |
---|---|
|
|
|
|
|
|
|
|
- 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
- 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.
-
In the AM admin UI, go to Realms > Realm Name > Scripts, and click OAuth2 Scope Validator Script.
-
In the Script field:
-
Update the script by inserting the following line of code preceding
return scopes;
on line 69:scopes.add("customscope");
-
-
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.
-
Log in to the AM admin UI as an administrator.
For example,
amAdmin
. -
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.
-
-
Save your changes.
Create an OAuth2 client
Create an OAuth 2.0 client to use in the client credentials grant flow.
-
In the AM console, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients, and click Add Client.
-
Enter the following values:
-
Client ID:
myClient
-
Client secret:
forgerock
-
Redirection URIs:
https://www.example.com:443/callback
-
Scope(s):
access
-
-
In Advanced > Grant Types, add
Client Credentials
. -
Click Create.
-
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.
-
Send a POST request to the /oauth2/access_token endpoint, specifying the grant type as
client_credentials
, scope asaccess
, 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 }
-
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 |
---|---|
|
The set of scope strings AM allows this client to request. |
|
The set of scope strings configured as defaults for this client. |
|
An HTTP client for making external HTTP requests. |
Write a message to the AM debug log. Logger names use the format Refer to Debug logging. |
|
|
The set of scope strings in the client request. |
|
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
- 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.
-
In the AM admin UI, go to Realms > Realm Name > Scripts, and click OIDC Claims Script.
-
In the Script field:
-
Add a new claim to the script. As a simple example, insert
myTestName
after thename
claim in theclaimAttributes
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 returnhttps://forgerock.com
as thepost_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 thescopeClaimsMap
:+
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.
-
-
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.
-
Log in to the AM admin UI as an administrator.
For example,
amAdmin
. -
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.
-
-
Save your changes.
Create an OAuth2 client for authorization
Create a public OAuth 2.0 client to use in the authorization request.
-
In the AM admin UI, go to Realms > Realm Name > Applications > OAuth 2.0 > Clients, and click Add Client.
-
Enter the following values:
-
Client ID:
myClient
-
Client secret:
forgerock
-
Redirection URIs:
https://www.example.com:443/callback
-
Scope(s):
openid profile
-
-
Click Create.
-
In the Core tab, set Client type to
Public
. -
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.
-
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. -
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.
-
-
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 | ||
---|---|---|---|
|
A map of the claims the server provides by default. For example:
|
||
|
An array of string values from the For details, refer to Claims Languages and Scripts in the OpenID Connect Core 1.0 specification. |
||
|
The default OpenID Connect 1.0 claims provided by AM. |
||
|
A read-only map of the following client properties. Only present if AM identified the client specified in the request.
|
||
|
An HTTP client for making external HTTP requests. |
||
|
Represents an identity that AM can access. For details, refer to AMIdentity. |
||
The logger instance for the script. Logger names use the format Refer to Debug logging. |
|||
|
A map of requested claims.
This is empty unless the request includes the 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 Example:
|
||
|
A list of the requested claims objects.
This is empty unless the request includes the A claim with a single value means the script should return only that value. |
||
|
A read-only map of the following request properties.
|
||
|
The set of scope strings in the client request. |
||
|
The display name of the script. |
||
|
The user’s session object. For details, refer to SSOToken. |