PingOne Advanced Identity Cloud

Token exchange

PingOne Advanced Identity Cloud supports RFC 8693, OAuth 2.0 Token Exchange for OAuth 2.0 and OpenID Connect tokens:

Table 1. Supported OAuth 2.0 token exchange
From/to Access token ID token Refresh tokens1 SAML assertion

Access token

ID token

1 You can’t exchange a token directly for a refresh token. When PingOne Advanced Identity Cloud 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 PingOne Advanced Identity Cloud domains and to realms. For example, a token issued by https://<tenant-env-fqdn>/am/oauth2/realms/root/realms/alpha can’t be exchanged at https://<tenant-env-fqdn>/am/oauth2/realms/root/realms/bravo.

Differences with normal token issuance:

  • PingOne Advanced Identity Cloud copies claims and values that must not change, such as subject and issuer claims, from the subject token to the new token.

    PingOne Advanced Identity Cloud 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.

  • PingOne Advanced Identity Cloud does not copy scopes, but derives them from the scope implementation.

    For details, refer to Scopes.

  • PingOne Advanced Identity Cloud adds the act and may_act claims when relevant.

  • Token exchange involves no end user interaction.

    There is no way to request consent for expanded scopes or claims. The client application must ensure end user consent beforehand or must ensure an expanded scope or claim is unrelated to the end 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 end user and the client.

The client obtains a subject token with the end 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

An end user chooses to transfer money using their bank application, an OAuth 2.0 client. The end 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 end user authenticates, the application gets an access token with change_data, create_accounts, read_accounts, and transfer scopes. The scopes represent all banking services available through the application.

The end user chooses to transfer money, which requires only the transfer scope. To reduce the security risk, the application exchanges the broad-scope access token for a restricted access token with only the transfer scope, which it uses to access the transfer service:

oauth2-token-exchange-1

Example with an ID token

The client could request an ID token instead of an access token.

When the end 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 end user chooses to transfer money, and the application exchanges the ID token for an expanded access token with the transfer scope, which it uses to access the transfer service:

oauth2-token-exchange-2

Delegation

To delegate means to give a job or duty to someone else who performs the job on your behalf.

Use delegation for token exchange when maintaining separation between the end 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 end user’s authorization.

  • An actor token obtained for itself or the end 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 end user. A resource server can adapt its behavior as necessary.

The following example shows the act claim field of an access token:

"act": {
  "sub": "delegateClient"
}

The sub field specifies the subject of the actor token.

Example with an actor access token

An end 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 end user are reflected in the repair request:

oauth2-token-exchange-3

Example with an actor ID token

The operator could request an actor ID token instead of an access token:

oauth2-token-exchange-4

Terminology

Act claim

Token claim identifying a delegate acting on behalf of another identity.

PingOne Advanced Identity Cloud 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 PingOne Advanced Identity Cloud 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. PingOne Advanced Identity Cloud sets this claim when issuing the original token.

  • For impersonation, the may_act claim must specify the client ID of the authorized actor.

  • For delegation, the may_act claim must specify the client ID and the sub (subject) of the actor token.

PingOne Advanced Identity Cloud 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 end user.

  • A delegateClient to exchange the token to act on the end 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": "delegateClient"
}

May act scripts

PingOne Advanced Identity Cloud has no default functionality to authorize token exchange for specific clients.

Instead, PingOne Advanced Identity Cloud 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', 'delegateClient')
    token.setMayAct(mayAct)
}());

For a commented example, refer to the sample may act script.

PingOne Advanced Identity Cloud doesn’t support wildcards in the client_id and sub fields. Your scripts must enumerate clients and actors.

The script doesn’t specify the token type. The client requesting an exchange token optionally specifies the token type.

May act script variables

PingOne Advanced Identity Cloud binds the following variables into OAuth2 May Act scripts:

clientProperties

A map of properties configured in the relevant client profile. Only present if PingOne Advanced Identity Cloud correctly identified the client.

The keys in the map are as follows:

clientId

The URI of the client.

allowedGrantTypes

The list of the allowed grant types for the client. For details, refer to the Javadoc for GrantType.

allowedResponseTypes

The list of the allowed response types for the client.

allowedScopes

The list of the allowed scopes for the client.

customProperties

A map of any custom properties added to the client.

These properties can include lists or maps as sub-maps. For example, the script includes customMap[Key1]=Value1 as customMap > Key1 > Value1 in the object.

To add custom properties to a client, go to Native Consoles > Access Management > OAuth 2.0 > Clients > Client ID > Advanced and update the Custom Properties field.

identity

The identity of the resource owner.

logger

Write a message to the PingOne Advanced Identity Cloud debug log.

In Advanced Identity Cloud, this corresponds to the am-core log source.

The name of the debug logger starts with scripts.OAUTH2_MAY_ACT.

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.

requestHeaders

The value of the named request header. Returns a map of <String, List<String>> as a native JavaScript object, for example:

var ipAddress = requestProperties.requestHeaders["X-Forwarded-For"][0]

Header names are case-sensitive.

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 end user’s session object if the request contained a session cookie.

token

Contains a representation of the token to be updated. The token is a mutable object; changes update the resulting token.

Use the token.setMayAct(JsonValue value) method to add a may_act claim to a token.

OAuth 2.0 provider settings

The OAuth 2.0 provider settings govern token exchange behavior for all clients in the realm. To access these settings, go to Native Consoles > Access Management > 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 PingOne Advanced Identity Cloud 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 these settings, go to Native Consoles > Access Management > 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 PingOne Advanced Identity Cloud from setting the claim.

Request parameters

Token exchange requests target the /oauth2/access_token endpoint. The requests use the following specific parameters:

Parameter Description

grant_type

Required.

Use grant_type=urn:ietf:params:oauth:grant-type:token-exchange.

subject_token

Required.

The original token to exchange.

Example: subject_token=RzOn3NbDyebd5hFVvzVrE2kox1A-lQ

subject_token_type

Required.

The type of subject token, either access token or ID token. One of:

  • subject_token_type=urn:ietf:params:oauth:token-type:access_token

  • subject_token_type=urn:ietf:params:oauth:token-type:id_token

actor_token

Required for delegation.

The token representing the delegate.

Example: actor_token=wNv5kr5QaugeY2IqptR3Zg7AEvg

actor_token_type

Required for delegation.

The type of actor token, either access token or ID token. One of:

  • actor_token_type=urn:ietf:params:oauth:token-type:access_token

  • actor_token_type=urn:ietf:params:oauth:token-type:id_token

requested_token_type

Optional.

The type of requested exchanged token, either access token or ID token. One of:

  • requested_token_type=urn:ietf:params:oauth:token-type:access_token (default)

  • requested_token_type=urn:ietf:params:oauth:token-type:id_token