---
title: Token exchange
description: AM supports RFC 8693, OAuth 2.0 Token Exchange for OAuth 2.0 and OpenID Connect tokens:
component: pingam
version: 8.1
page_id: pingam:am-oauth2:token-exchange
canonical_url: https://docs.pingidentity.com/pingam/8.1/am-oauth2/token-exchange.html
keywords: ["OAuth 2.0", "OpenID Connect (OIDC)", "Authorization", "Endpoints", "Grant Flow", "Setup &amp; Configuration"]
page_aliases: ["oauth2-guide:oauth2-token-exchange.adoc", "oauth2-guide:token-exchange-configuration.adoc", "oauth2-guide:token-exchange-flows.adoc", "oauth2-guide:scripting-api-may_act.adoc", "oauth2-guide:token-exchange.adoc"]
section_ids:
  use_cases: Use cases
  token-exchange-impersonation: Impersonation
  example_with_an_access_token: Example with an access token
  example_with_an_id_token: Example with an ID token
  token-exchange-delegation: Delegation
  example_with_an_actor_access_token: Example with an actor access token
  example_with_an_actor_id_token: Example with an actor ID token
  terminology: Terminology
  configuration: Configuration
  token-exchange-authorization: Authorize exchange
  the_may_act_claim: The may_act claim
  may_act_scripts: May act scripts
  aud-claim: The aud claim
  the_aud_claim_and_token_introspection: The aud claim and token introspection
  oauth_2_0_provider_settings: OAuth 2.0 provider settings
  client_settings: Client settings
  token_exchange_and_the_security_token_service: Token exchange and the security token service
---

# Token exchange

AM supports RFC 8693, [OAuth 2.0 Token Exchange](https://www.rfc-editor.org/info/rfc8693) for OAuth 2.0 and OpenID Connect tokens:

**Supported OAuth 2.0 token exchange**

| From/to      | Access token          | ID token              | Refresh tokens1       | SAML assertion        |
| ------------ | --------------------- | --------------------- | --------------------- | --------------------- |
| Access token | [icon: check, set=fa] | [icon: check, set=fa] | [icon: times, set=fa] | [icon: times, set=fa] |
| ID token     | [icon: check, set=fa] | [icon: check, set=fa] | [icon: times, set=fa] | [icon: times, set=fa] |

1 You cannot exchange a token directly for a refresh token. When AM issues [refresh tokens](oauth2-refresh-tokens.html) (default), it also issues them on token exchange.

|   |                                                                                                                                                                                                                                                                       |
| - | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | Clients can exchange tokens only at the OAuth 2.0 provider that issued them.This restriction applies to AM domains and to realms. For example, a token issued by `https://am.example.com:8443/am/oauth2` cannot be exchanged at `https://am.myexample.com/am/oauth2`. |

Differences with normal token issuance:

* AM copies claims and values that must not change, such as subject and issuer claims, from the *subject token* to the new token.

  AM ignores irrelevant claims, such as those missing from the resulting token type, and claims that cannot be inferred from the subject token, such as those present in the resulting token, but not in the subject token.

* AM doesn't copy scopes, but derives them from the scope implementation.

  Learn more in [OAuth 2.0 scopes](oauth2-scopes.html).

* AM adds the `act` and `may_act` claims when relevant.

* Optionally, AM validates the audience parameter (`aud` claim) values against a predefined list of allowed values.

  This lets you restrict the downstream resource server or servers against which the exchanged token can be used.

  Learn more in [The `aud` claim](#aud-claim).

* 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](token-exchange-impersonation.html). |

#### 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 an access 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:

![OAuth 2.0 token exchange with impersonation based on an access token](_images/oauth2-token-exchange-1.svg)

#### 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:

![OAuth 2.0 token exchange with impersonation based on an ID token](_images/oauth2-token-exchange-2.svg)

### 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](token-exchange-delegation.html). |

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](oauth2-introspect-endpoint.html), 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:

```none
"act": {
  "sub": "(age!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:

![OAuth 2.0 token exchange with delegation based on an actor access token](_images/oauth2-token-exchange-3.svg)

#### Example with an actor ID token

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

![OAuth 2.0 token exchange with delegation based on an actor ID token](_images/oauth2-token-exchange-4.svg)

## 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](#token-exchange-authorization).

* Restricted token

  An access token with narrower scopes or claims than those of the subject token.

  Instead of gathering consent for different sets of scopes and claims, clients gather consent for a broad range initially and then restrict scope during token exchange.

* Subject token

  The access or ID token representing the identity on behalf of whom the request is made.

  The client can obtain the subject token with any supported OAuth 2.0 or OpenID Connect flow.

## Configuration

Token exchange configuration requires:

* A script to authorize exchange.

* Settings in the OAuth 2.0 provider or the OAuth 2.0 client application configuration.

### Authorize exchange

A claim on the original token authorizes specified clients and actors to perform the exchange.

You write a script AM runs when issuing tokens to set the claim.

#### The `may_act` claim

The `may_act` claim on a token identifies the authorized actor who can exchange the token. AM sets this claim when issuing the original token.

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

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

AM rejects token exchange requests from clients or actors who are not authorized by the `may_act` claim.

The following example claim allows:

* An `impersonationClient` to exchange the token and impersonate the user.

* A `delegateClient` to exchange the token to act on the user's behalf using the original token and an actor token issued directly to the client with the client credentials grant.

```none
"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, create an `OAuth2 May Act` script for AM to run when issuing a token.

The following example JavaScript produces the previous example claim without the comments:

* Legacy

* Next-generation

```javascript
(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)
}());
```

```javascript
(function () {
    var mayAct = {
        'client_id': ['impersonationClient', 'delegateClient'],
        'sub': '(age!delegateClient)'
    };
    token.setMayAct(mayAct);
}());
```

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

|   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | Learn about how to write a may act script from the following resources:Resource	Description&#xA;&#xA;Sample script&#xA;&#xA;&#x9;&#xA;&#xA;A fully commented example of a may act script.&#xA;&#xA;&#xA;&#xA;&#xA;Common bindings&#xA;&#xA;&#x9;&#xA;&#xA;Documentation for script variables available across all contexts, such as logger and httpClient.&#xA;&#xA;&#xA;&#xA;&#xA;May act scripting API&#xA;&#xA;&#x9;&#xA;&#xA;Details on the specific bindings and objects unique to the may act script context. |

#### The `aud` claim

The `aud` claim lists the target service or services where the client intends to use the exchanged token. By default, AM doesn't validate the `aud` claim.

To configure AM to validate audience parameter values, set the following properties:

* On the client, list the target resource server or servers in the Allowed Resource Server Audience Values property.

* On the OAuth 2.0 provider, enable the Accept Audience Parameters in Token Exchange Requests property.

If Accept Audience Parameters in Token Exchange Requests is enabled:

* AM validates audience parameter values in token exchange requests against the values defined in Allowed Resource Server Audience Values on the client.

  If validation fails, the token exchange request is rejected.

* If the requested values are included in the Allowed Resource Server Audience Values property, AM stores the audience values in the resulting access or ID token.

* For client-side access tokens, if you've enabled [Include Client ID Claim In Stateless Access & Refresh Tokens](../setup/services-configuration.html#include-client-ID-claim-in-tokens), the client ID is included as the *first* audience value.

* For client-side ID tokens, the client ID is *always* included as the first audience value.

* If you use an [Access token modification](modifying-access-tokens-scripts.html) script to override the audience values, AM stores the modified values in the resulting access token.

If Accept Audience Parameters in Token Exchange Requests is not enabled (the default):

* AM ignores audience parameter values in token exchange requests.

* For client-side tokens, if you've enabled [Include Client ID Claim In Stateless Access & Refresh Tokens](../setup/services-configuration.html#include-client-ID-claim-in-tokens), a single audience value is included that contains the client ID.

* If you use an [Access token modification](modifying-access-tokens-scripts.html) script to override the audience value, AM stores the modified values in the resulting access token.

  For client-side tokens, the audience value is available when examining the contents of the JWT.

  For server-side tokens, you can introspect the JWT to obtain the audience value.

##### The `aud` claim and token introspection

The contents of the `aud` claim in a token introspection response depend on the token type and the requested response type:

* `/oauth2/introspect endpoint`:

  If you ask the server to check a token, the `aud` value depends on the format of the answer you requested:

  * If you request a JWT response (signed or signed and encrypted), the `aud` claim will always be the Client ID of the application performing the introspection.

  * If you request a JSON response, the `aud` claim is only included if the token is server-side and already had an audience inside it.

  * For client-side macaroon tokens, the response always includes an `aud` claim, but it might not perfectly match the original value.

* `userinfo` endpoint:

  This endpoint is specifically for getting user profile details. The `aud` behavior here is slightly different:

  * If the token *already* has an `aud`, it is returned regardless of whether you choose JSON or JWT.

  * If the token doesn't have an `aud`:

    * JWT Responses: The server adds an `aud` containing the Client ID.

    * JSON Responses: No `aud` is added. It remains missing.

* `tokeninfo` endpoint:

  If the token has an `aud` claim, the JSON response will show it. If it doesn't have one, it won't.

These differences are summarized in the following table:

| Request Method       | Response Format        | What is in the `aud` claim?                              |
| -------------------- | ---------------------- | -------------------------------------------------------- |
| `/oauth2/introspect` | JWT (Signed/Encrypted) | The client ID (The "receiver" of the response)           |
| `/oauth2/introspect` | JSON                   | The original audience from the token (server-side only). |
| `userinfo`           | JWT                    | The token's audience (or client ID if empty).            |
| `userinfo`           | JSON                   | The token's audience (or nothing if empty).              |
| `tokeninfo`          | JSON                   | The token's audience (if it exists).                     |

### 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](../am-authentication/auth-nodes-and-journeys.html#authentication-levels-trees) 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.

## 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](../sts/preface.html) lets AM establish cross-domain trust federation relationships. To do this, AM provides an STS framework loosely based on the SOAP WS-Trust specification.

  You must build, deploy, and maintain the STS yourself.

  The STS supports username/password, SSO tokens, X.509 certificates, and ID tokens as input tokens, and SAML 2.0 assertions and ID tokens as output tokens.

  Due to its transformation capabilities, the STS 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.
