Logo

Ena OAuth 2.0 Token Exchange Profile for Chaining Identity and Authorization

Version: 1.0 - draft 01 - 2025-10-17

Abstract

The OAuth 2.0 framework defines mechanisms that allow users (resource owners) to delegate access rights to protected resources for the applications they use.

This document specifies solutions for chaining OAuth 2.0 identity and authorization in scenarios where calls to protected resources trigger additional calls, or where calls cross domain boundaries.

Table of Contents

  1. Introduction

    1.1. Requirements Notation and Conventions

  2. Protected Resource Acting as an Client

    2.1. Problem Statement

    2.2. Solution Overview

    2.3. Token Exchange Request

    2.3.1. Processing Requirements

    2.4. Token Exchange Response

    2.4.1. The Actor Claim

    2.5. Examples

  3. Accessing Protected Resources in Other Domains

    3.1. Problem Statement

    3.2. Solution Overview

    3.2.1. Domain Trust Relationships and Prerequisites

    3.3. Token Exchange

    3.3.1. Token Exchange Request

    3.3.2. Inbound Token Requirements

    3.3.3. Processing Requirements

    3.3.4. Token Exchange Response and JWT Contents

    3.4. Authorization Grant Requirements

    3.4.1. Access Token Request According to RFC7523

    3.4.2. Processing of JWT Authorization Grant

    3.4.3. Token Response

    3.5. Additional Features and Advanced Topics

    3.5.1. Scope Mapping Across Domains

    3.5.2. Transcription of User Identity Claims

    3.6. Examples

  4. General Token Exchange Requirements and Considerations

    4.1. The Resource and Audience Parameters

    4.2. Subject Token Requirements and Considerations

    4.2.1. Issuing a Token Usable for Token Exchange

    4.2.2. Processing Requirements for a Subject Token

    4.3. Token Exchange and the User and Resource Owner Distinction

  5. References

    5.1. Normative References

    5.2. Informational References


1. Introduction

The "OAuth 2.0 Token Exchange" specification, [RFC8693], defines a generic extension to OAuth 2.0 that allows an entity to call an OAuth 2.0 authorization server acting as a Security Token Service (STS) in order to exchange a token in its possession for another token. While token exchange is a powerful tool for addressing many OAuth 2.0-related challenges, a generic specification such as [RFC8693] requires profiling to achieve interoperability and to avoid introducing security risks.

This specification profiles the use of OAuth 2.0 Token Exchange for two common use cases where a structured and secure method of applying OAuth 2.0 has not previously been defined.

Common to both use cases is that each API, or protected resource, requires the presentation of a valid access token that conveys some or all of the user's delegated access rights to the protected resource. To enable this delegation, the user's identity must be established and chained across subsequent calls.

The problem statements therefore do not include the use of the client credentials grant, where one service calls another without the involvement of a user or resource owner. Such usage is not affected by the chaining challenges described in this document and is therefore out of scope for this specification.

Note: Section 1.5 of [Ena.OAuth2.Profile] describes the distinction between a user and a resource owner, and in some OAuth 2.0 deployments, the user is not the actual resource owner. This profile covers the following cases:

The requirements for the use of OAuth 2.0 token exchange may differ depending on whether the user is the actual resource owner. Where this is relevant, this profile explicitly specifies under which circumstances a given requirement applies. See Section 4.3, Token Exchange and the User and Resource Owner Distinction.

1.1. Requirements Notation and Conventions

The keywords “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” are to be interpreted as described in [RFC2119].

These keywords are capitalized when used to unambiguously specify requirements over protocol features and behavior that affect the interoperability and security of implementations. When these words are not capitalized, they are meant in their natural-language sense.

2. Protected Resource Acting as an Client

2.1. Problem Statement

The simple illustration below shows a typical use of the OAuth 2.0 authorization code grant, where an application (OAuth 2.0 client) obtains an access token from the authorization server to access an API (protected resource) on behalf of a user interacting with the application.

But what happens if the implementation of the API needs to make a backend call to a second API in order to construct a response to the API request?

Pic

In this scenario, the first API will act as an OAuth 2.0 client against the second API, but how will it acquire the access token to pass along in the call?

Firstly, let's determine why the access token it received in the call from the application cannot simply be forwarded:

Some deployments that do not use DPoP forward access tokens between services in a call chain. In such cases, the access token either contains multiple audience values or all invoked services are treated as the same entity. Furthermore, the initial client identifier is passed along the chain, which breaks traceability. Entities conformant with this profile MUST NOT rely on such shortcuts.

The following sub-sections specify how OAuth 2.0 Token Exchange, as defined in [RFC8693], can be used by a protected resource to obtain a new access token based on a previously received one before acting as an OAuth 2.0 client to call another service.

2.2. Solution Overview

The sequence diagram below illustrates the role of OAuth 2.0 Token Exchange during chained API-calls.

sequenceDiagram
autonumber
    
    actor User as User
    participant Service as Application<br/>(Client)
    participant AsA as Authorization Server A
    participant ApiA as Protected Resource<br/>API A
    participant ApiB as Protected Resource<br/>API B

    User-->>Service: Action ...

    Service-->>+User: Redirect
    User->>-AsA: Authorization Request

    User-->AsA: Authenticate (and possibly consent)

    AsA-->>+User: Redirect
    User->>-Service: Authorization Response w. code

    Service->>+AsA: Token Request w. code
    AsA->>-Service: Token Response w. Access Token

    Service->>+ApiA: Make API call<br/>Include Access Token

    Note over ApiA: API A will have to invoke API B<br/>in order to process API-call

    ApiA->>+AsA: Token Exchange Request
    AsA->>-ApiA: Token Exchange Response<br/>with Access Token

    ApiA->>+ApiB: Make API call<br/>Include new Access Token
    ApiB->>-ApiA: API response

    ApiA->>-Service: API response

    Service-->>User: Response ...

Steps 1 through 9 represent a standard OAuth 2.0 authorization code flow, where the application (client) obtains an access token by directing the user to the authorization server, where the user authenticates and the application’s access rights are authorized. The application then uses the issued access token to access the protected resource, API A. The protected resource validates the supplied access token before starting to process the request.

However, in order for API A to process the API-call and to put together a response, it needs to make a call to an underlying resource, API B.

In order to obtain a valid access token for API B, API A acts as an OAuth 2.0 client towards the authorization server. Instead of prompting the user again or forwarding the original token, API A uses OAuth 2.0 Token Exchange [RFC8693] to present the inbound access token it received from the application and requests a new access token intended for API B (steps 10 and 11).

This mechanism ensures that:

By using token exchange, API A does not need to manage or impersonate the original client. Instead, it formally assumes the role of an OAuth 2.0 client, bound by the same rules as any other client when requesting access tokens. This maintains a clear separation of concerns: the application acts as a client in relation to API A, and API A acts as a client in relation to API B.

This solution also strengthens traceability, since the resulting access token clearly reflects both the identity of the user (as chained from the inbound token) and the identity of API A as the requesting client. Downstream services can therefore distinguish whether a request originates directly from the user’s application or from another protected resource acting on behalf of the user.

In the following sections, the exact requirements for the token exchange request, processing rules, and response are defined.

2.3. Token Exchange Request

A protected resource that needs to act as a client in order to call another protected resource MUST perform an OAuth 2.0 token exchange request in accordance with [RFC8693]. The inbound access token received from the original client MUST be supplied as the subject_token.

The token exchange request MUST include:

Clients SHOULD include:

Clients MAY include:

Multiple resource or audience parameters MAY be included to indicate the intended use of the resulting access token at multiple protected resources, or as stated in Section 6.1.1 of [Ena.OAuth2.Profile], to support alternative representations of a protected resource as audience values.

Client authentication at the token endpoint MUST follow the requirements given in [Ena.OAuth2.Profile].

2.3.1. Processing Requirements

When processing a token exchange request, the authorization server MUST:

Servers supporting multiple profiles: An authorization server deployment may support token exchange both within its own domain (as described in this section) and in other scenarios that involve different domains (described in Section 3). In such cases, the requested_token_type parameter MUST be used to distinguish which type of token exchange the client is requesting. When requested_token_type is urn:ietf:params:oauth:token-type:access_token, the server MUST process the request according to this section and issue an access token intended for the indicated protected resource(s). When requested_token_type is urn:ietf:params:oauth:token-type:jwt, the server MUST process the request according to the rules specified in Section 3 and issue a JWT authorization grant for use at another authorization server. If the parameter is omitted and the server cannot unambiguously determine the intended profile from context, it MUST reject the request with invalid_request.

2.4. Token Exchange Response

Upon successful validation, the authorization server MUST issue a new access token in response to the token exchange request. The issued access token MUST follow the requirements stated in Section 6.1 of [Ena.OAuth2.Profile] with the following extensions and clarifications:

The response MUST be encoded as JSON according to Section 2.2.1 of [RFC8693] and include at least the following elements:

Furthermore, the scope parameter is optional according to [RFC8693] if the scope(s) issued were the same as the requested scope(s). However, for simplicity and to improve interoperability, for entities compliant with this profile its use is RECOMMENDED in all cases.

Unless overridden by local policy, authorization servers compliant with this profile MUST NOT issue refresh tokens for token exchange in the context of identity and authorization chaining.

2.4.1. The Actor Claim

The act (actor) claim provides accountability and auditability by recording which entity performed the token exchange. This claim enables downstream protected resources to distinguish between the end-user identity (sub) and the chain of actors that acted on behalf of the user.

As defined in Section 4.1 of [RFC8693], the act claim may be a nested structure to represent multiple actors. Under this profile:

Example

Below is a simplified JWT payload of an access token issued by https://as.example.com to be used at https://api2.example.com.

{
  "iss": "https://as.example.com",
  "aud": "https://api2.example.com",
  "sub": "user-1234",
  "acr": "http://id.elegnamnden.se/loa/1.0/loa3",
  "client_id": "https://api1.example.com",
  "act": {
    "sub": "https://api1.example.com",
    "act": {
      "sub": "https://app.example.com"
    }
  },
  "scope": "api-read",
  "jti": "987ui87665456",
  "nbf": 1695379200,
  "iat": 1695379200,
  "exp": 1695382800
}

In this example:

This chaining ensures that all involved actors are visible to the downstream service, while authorization decisions remain based only on the standard claims (sub, aud, scope, etc.).

2.5. Examples

This section provides a non-normative, end-to-end illustration of token exchange, aligned with the "Ena OAuth 2.0 Interoperability Profile", [Ena.OAuth2.Profile].

The example illustrates:

For readability, long values are folded and signatures are abbreviated. All examples use the scope api-read.

Inbound Access Token (JWT):

Access token presented by the application (https://app.example.com) to the first protected resource (https://api1.example.com):

{
  "iss": "https://as.example.com",
  "aud": ["https://api1.example.com", "https://as.example.com"],
  "sub": "user-1234",
  "acr": "http://id.elegnamnden.se/loa/1.0/loa3",
  "client_id": "https://app.example.com",
  "scope": "api-read",
  "jti": "inbound-1234-unique-jwt-id",
  "nbf": 1695375550,
  "iat": 1695375600,
  "exp": 1695379200
}

Note that the authorization server has issued the access token with its own issuer identifier among the aud values. See Section 4.2.1, Issuing a Token Usable for Token Exchange.

Token Exchange Request:

The protected resource https://api1.example.com acts as an OAuth 2.0 client and calls the AS token endpoint for a token exchange request, authenticating with private_key_jwt. The inbound access token above is supplied as the subject_token and a new access token is requested for the audience https://api2.example.com.

HTTP request:

POST /token HTTP/1.1
Host: as.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atoken-exchange&
subject_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2FzLmV4YW1wbGUu \
  Y29tIiwiYXVkIjoiaHR0cHM6Ly9hcGkxLmV4YW1wbGUuY29tIiwic3ViIjoidXNlci0xMjM0IiwiY2xpZW50X \
  2lkIjoiaHR0cHM6Ly9hcHAuZXhhbXBsZS5jb20iLCJzY29wZSI6ImFwaS1yZWFkIiwianRpIjoiaW5ib3VuZC \
  0xMjM0LXVuaXF1ZS1qd3QtaWQiLCJuYmYiOjE2OTUzNzU1NTAsImlhdCI6MTY5NTM3NTYwMCwiZXhwIjoxNjk \
  1Mzc5MjAwfQ.MEUCIQDt...&
subject_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Aaccess_token&
audience=https%3A%2F%2Fapi2.example.com&
scope=api-read&
client_id=https%3A%2F%2Fapi1.example.com&
client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&
client_assertion=eyJhbGciOiJSUzI1NiIsImtpZCI6ImtpZC0wMDEiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJ \
  odHRwczovL2FwaTEuZXhhbXBsZS5jb20iLCJzdWIiOiJodHRwczovL2FwaTEuZXhhbXBsZS5jb20iLCJhdWQi \
  OiJodHRwczovL2FzLmV4YW1wbGUuY29tL3Rva2VuIiwianRpIjoiYTMtMTIzNC11bmlxdWUtand0LWlkIiwib \
  mJmIjoxNjk1Mzc1NTUwLCJpYXQiOjE2OTUzNzU2MDAsImV4cCI6MTY5NTM3NTkwMH0.MIIB...

For reference, the decoded client_assertion (private_key_jwt) components:

JOSE header:

{
  "alg": "RS256",
  "kid": "kid-001",
  "typ": "client-authentication+jwt"
}

JWT claims:

{
  "iss": "https://api1.example.com",
  "sub": "https://api1.example.com",
  "aud": "https://as.example.com",
  "jti": "a3-1234-unique-jwt-id",
  "nbf": 1695375550,
  "iat": 1695375600,
  "exp": 1695375900
}

Token Exchange Response:

HTTP response:

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
  "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImtpZC0wMDEiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodH \
  RwczovL2FzLmV4YW1wbGUuY29tIiwiYXVkIjoiaHR0cHM6Ly9hcGkyLmV4YW1wbGUuY29tIiwic3ViIjoidXNlci0x \
  MjM0IiwiYWN0Ijp7InN1YiI6Imh0dHBzOi8vYXBpMS5leGFtcGxlLmNvbSIsImFjdCI6eyJzdWIiOiJodHRwczovL2 \
  FwcC5leGFtcGxlLmNvbSJ9fSwic2NvcGUiOiJhcGktcmVhZCIsImp0aSI6Im5ldy0xMjM0LXVuaXF1ZS1qd3QtaWQi \
  LCJuYmYiOjE2OTUzNzkyMDAsImlhdCI6MTY5NTM3OTIwMCwiZXhwIjoxNjk1MzgyODAwfQ.Fh0B...",
  "issued_token_type": "urn:ietf:params:oauth:token-type:access_token",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "api-read"
}

Newly Issued Access Token (JWT):

Decoded claims of the issued access token intended for https://api2.example.com:

{
  "iss": "https://as.example.com",
  "aud": "https://api2.example.com",
  "sub": "user-1234",
  "acr": "http://id.elegnamnden.se/loa/1.0/loa3",
  "client_id": "https://api1.example.com",
  "act": {
    "sub": "https://api1.example.com",
    "act": {
      "sub": "https://app.example.com"
    }
  },
  "scope": "api-read",
  "jti": "new-1234-unique-jwt-id",
  "nbf": 1695379200,
  "iat": 1695379200,
  "exp": 1695382800
}

3. Accessing Protected Resources in Other Domains

3.1. Problem Statement

The previous section described the challenge of identity and authorization chaining for services within the same domain, i.e., where the same trust model and authorization server are used. However, applications may also need to access resources outside their own domain, where a different authorization server and trust model apply, and in many cases, a different user authentication model.

Pic

Given this problem statement, the main challenges are:

The solution to the above challenges requires establishing a trust relationship between the authorization servers in the respective domains. This trust enables the authorization server in the first domain to issue a statement intended for the authorization server in the second domain, allowing clients in the first domain to obtain access tokens that can be used in the second domain.

3.2. Solution Overview

Note: The draft "OAuth Identity and Authorization Chaining Across Domains", [Draft.ID-Chaining], focuses on solving the problem described above. Future versions of this profile will reference this specification if and when it reaches RFC status. Until then, the draft is informational and no references will be made to it.

The solution for identity and authorization chaining within the same trust domain involves exchanging an access token for another access token containing the correct audience and scope values. However, when a call is made to another trust domain, the output from the token exchange cannot be an access token usable at the intended protected resource. This is because:

Therefore, token exchange in these cases must use an intermediate proof issued by the authorization server in the originating domain and trusted by the authorization server in the target domain. This proof is represented as a signed JWT in which the authorization server in the originating domain asserts relevant claims about the sending client and authenticated user.

For this to function, a trust relationship must be configured between the authorization servers in the two domains; see Section 3.2.1 below.

sequenceDiagram
autonumber
    
    box Domain A
        actor User as User
        participant Service as Application<br/>(Client)
        participant AsA as Authorization Server A
        participant ApiA as Protected Resource<br/>API A
    end

    box Domain B
        participant AsB as Authorization Server B
        participant ApiB as Protected Resource<br/>API B
    end

    User-->Service: Logged in
    User-->AsA: Has session at Authorization Server

    User-->>Service: Action ...

    Service->>+AsA: Token Exchange Request (RFC8693)
    AsA->>-Service: Authorization Grant JWT (RFC7523)

    Service->>+AsB: Access Token Request<br />Pass Authorization Grant JWT (RFC7523)
    AsB->>-Service: Access Token Response

    Service->>+ApiB: Make API call<br />Include Access Token
    ApiB->>-Service: API response

    Service-->>User: Response ...

The sequence diagram above describes a token exchange operation that enables an application in domain A to invoke a protected resource in domain B.

  1. The user is assumed to be logged in to the application in domain A. How this login was performed is out of scope for this profile.

  2. For this illustration, it is assumed that the end-user has a relationship with the authorization server; that is, at some point the user was directed to the authorization server, where the user was authenticated and access rights to a protected resource were authorized.

  3. The user performs an action in the application that requires the application to access a resource in domain B.

  4. To obtain a signed attestation from the authorization server in domain A, which can then be used to request an access token for domain B, the application makes an OAuth 2.0 token exchange request to the authorization server. Included in this request is a previously acquired access or refresh token. See Section 3.3.1 and Section 3.3.2.

  5. Based on its configuration and established trust relationships, the authorization server in domain A returns a signed JWT. This JWT contains claims attesting to the information needed by the authorization server in domain B to issue an access token. See Section 3.3.4.

  6. The application (client) in domain A then uses the received JWT authorization grant in a token request to the authorization server in domain B. This is done according to the authorization grant processing requirements defined in [RFC7523]. See Section 3.4.1.

  7. The authorization server in domain B processes the request according to Section 3.4.2 and issues an access token that can be used to access the protected resource in domain B. See Section 3.4.3.

Steps 8–10 follow normal OAuth 2.0 access token usage: the client provides the access token in the request to the protected resource, which validates it before granting access and returning a response.

The cross-domain use case can also be combined with the previous use case, where a protected resource in domain A acts as an OAuth 2.0 client towards domain B. This is illustrated in the sequence diagram below. The requirements in the following sections also cover these usages of token exchange.

sequenceDiagram
    
    box Domain A
        actor User as User
        participant Service as Application<br/>(Client)
        participant AsA as Authorization Server A
        participant ApiA as Protected Resource<br/>API A
    end

    box Domain B
        participant AsB as Authorization Server B
        participant ApiB as Protected Resource<br/>API B
    end

    User-->>Service: Action ...

    Service-->>+User: Redirect
    User->>-AsA: Authorization Request

    User-->AsA: Authenticate (and possibly consent)

    AsA-->>+User: Redirect
    User->>-Service: Authorization Response w. code

    Service->>+AsA: Token Request w. code
    AsA->>-Service: Token Response w. Access Token

    Service->>+ApiA: Make API call<br/>Include Access Token

    ApiA->>+AsA: Token Exchange Request (RFC8693)
    AsA->>-ApiA: Authorization Grant JWT (RFC7523)

    ApiA->>+AsB: Access Token Request<br/>Pass Authorization Grant JWT (RFC7523)
    AsB->>-ApiA: Access Token Response

    ApiA->>+ApiB: Make API call<br/>Include Access Token
    ApiB->>-ApiA: API response

    ApiA->>-Service: API response

    Service-->>User: Response ...

3.2.1. Domain Trust Relationships and Prerequisites

For the above token exchange flows to be possible, there must be a trust relationship configured in which the authorization server in the target domain accepts authorization grant JWTs issued by the authorization server in the originating domain. In addition, all entities in the originating domain that make cross-domain calls must be registered as OAuth 2.0 clients at the authorization server in the target domain.

How these relationships are established, and the requirements for trust, are out of scope for this specification.

However, the minimum requirements for establishing the cross-domain use case are as follows:

Also, there is no guarantee that the scopes used in the target domain have any meaning in the originating domain. Therefore, the authorization servers may need to maintain mappings of scopes and other rights, and define how to apply these control mechanisms when managing authorization across domain boundaries. See Section 3.5.1 below.

3.3. Token Exchange

Token exchange across domains differs from the intra-domain case in Section 2: the output is not an access token for the target protected resource, but an authorization grant in the form of a signed JWT that the client presents to the authorization server in the target domain to obtain an access token. The authorization server in the originating domain acts as an STS as per [RFC8693] and issues a JWT authorization grant suitable for use with the JWT bearer authorization grant defined in [RFC7523].

Under this profile, the authorization server in the originating domain MUST issue a short-lived, one-time-use JWT that attests to the delegating user and the requesting client, and that is explicitly targeted at the authorization server in the target domain.

3.3.1. Token Exchange Request

A client in the originating domain (or a protected resource acting as a client) MUST call the originating authorization server’s token endpoint with a token exchange request conformant to [RFC8693] with the following profile requirements:

Client authentication at the token endpoint MUST follow [Ena.OAuth2.Profile]. If private_key_jwt is used, the iss and sub of the client assertion MUST equal the client’s identifier registered at the originating authorization server.

3.3.2. Inbound Token Requirements

This profile defines the following requirements for the subject_token used as input to the token exchange:

A requesting entity MUST NOT include a token that does not fulfil all the above requirements in a token exchange request.

3.3.3. Processing Requirements

When the originating authorization server receives a conformant token exchange request, it MUST:

  1. Validate the subject_token according to Section 4.2.2, Processing Requirements for a Subject Token.

  2. Verify that the subject_token is user-bound. If not, the request MUST be rejected with invalid_request.

  3. Authenticate the client and verify it is authorized to request cross-domain token exchange for the indicated target authorization server.

  4. Verify that the target authorization server indicated by audience/resource is configured as a trusted peer and that key material and issuer identifiers are established as per Section 3.2.1. If not, the request MUST be rejected with invalid_target or unauthorized_client.

  5. Assert that requested_token_type is urn:ietf:params:oauth:token-type:jwt, or if it is omitted, apply the logic from "Servers supporting both use cases" below.

If the request is invalid, the server MUST respond with an error per [RFC8693]. Where applicable, the following errors SHOULD be used: invalid_request, invalid_scope, unauthorized_client, invalid_target, and server_error.

Servers supporting both use cases: An authorization server that supports both the intra-domain exchange in Section 2 and the cross-domain exchange in this section MUST use the requested_token_type parameter to disambiguate the requested behaviour:

If requested_token_type is set to urn:ietf:params:oauth:token-type:access_token, the server MUST process the request under the rules of Section 2, and if requested_token_type is set to urn:ietf:params:oauth:token-type:jwt, the server MUST process the request under the rules of this section.

Clients SHOULD always supply requested_token_type. If requested_token_type is omitted, the server MAY infer intent from the target indicator, where the cross-domain case will be chosen if the target identifies an authorization server, and the intra-domain case will be chosen if the target identifies a protected resource within the same domain.

If the intent cannot be determined unambiguously, the server MUST reject the request with invalid_request.

3.3.4. Token Exchange Response and JWT Contents

The token exchange response MUST be a JSON object as defined by [RFC8693] with these profile requirements:

The JWT returned in access_token MUST comply with Section 3 of [RFC7523] and this profile.

The JWT authorization grant MUST be signed by the originating authorization server using a key that the target authorization server has associated with the originating issuer (Section 3.2.1). The JWT authorization grant MAY be encrypted if both domains have explicitly configured encryption keys and policies.

3.4. Authorization Grant Requirements

This section profiles how the client uses the JWT authorization grant at the target authorization server, and how the target authorization server processes it and issues an access token.

3.4.1. Access Token Request According to RFC7523

The HTTP request to the target authorization server’s token endpoint MUST follow Section 2.1 of [RFC7523] with the following clarifications and additions.

3.4.2. Processing of JWT Authorization Grant

When the target authorization server receives a JWT bearer grant request as described in Section 3.4.1, it MUST process the request as follows:

  1. Client authentication – The client MUST be authenticated in accordance with Section 8.3 of [Ena.OAuth2.Profile].

  2. Assertion validation – The server MUST validate the JWT assertion in accordance with [RFC7523]. This includes verifying the digital signature, issuer, subject, audience, jti (for replay protection), and the iat, nbf, and exp claims. The issuer MUST correspond to a trusted originating authorization server, and the signing key MUST be bound to that issuer as described in Section 3.2.1. The aud claim of the JWT MUST contain the issuer identifier for the target authorization server.

  3. Scope and resource determination – The server MUST determine the scopes and target resources for the token to be issued. This decision MUST take into account any resource and scope parameters in the request, values carried in the assertion, and locally configured scope or resource mappings as described in Section 3.5.1.

  4. Subject determination – The server MUST determine the end-user identifier to be carried forward from the assertion for identity chaining. If needed, user identity transcription MAY be applied as described in Section 3.5.2.

  5. Client identity determination – The server MUST determine the client identifier as registered in the target domain for the requesting entity.

  6. Actor chain handling – If the assertion contains an act claim, all actor values from the assertion MUST be preserved. The target authorization server MAY add an additional actor to reflect the registered client in the target domain. The act claim MUST NOT be used for authorization decisions.

  7. Policy enforcement – The server MUST enforce local policy, including user consent, scope minimisation, and resource restrictions. If requested scopes cannot be satisfied, the request MUST be rejected with the invalid_scope error.

  8. Issuance decision – After successful processing, the server MUST issue an access token and return a response as defined in Section 3.4.3.

If any of the above checks fail, the authorization server MUST reject the request and return an error response in accordance with [RFC7523] and [RFC6749].

3.4.3. Token Response

The access token response MUST follow [RFC6749] and [Ena.OAuth2.Profile]. The access token issued by the target authorization server MUST follow the requirements stated in Section 6.1 of [Ena.OAuth2.Profile], with the following additions and clarifications:

Furthermore, the token response MUST NOT include a refresh token unless explicitly permitted by target-domain policy. If a refresh token is issued, its use MUST remain confined to the target domain.

3.5. Additional Features and Advanced Topics

3.5.1. Scope Mapping Across Domains

Scope values used within a domain may be specific to that domain and have no meaning outside it. This must be considered in the cross-domain token exchange case, where the authorization server in the originating domain issues the JWT containing the identity of the user along with the client authorizations (scopes), for the authorization server in the target domain to consume.

This profile does not specify how such scope mapping should be performed, other than that deployments MUST define a deterministic mapping from originating-domain entitlements to target-domain scopes. Whether this mapping is maintained in the originating or target domain is deployment specific.

An alternative to domain-specific scopes with mappings handled by an authorization server is an approach where the originating domain incorporates relevant scopes from the target domain into its own security and authorization model, and clients within the originating domain request those scopes directly.

3.5.2. Transcription of User Identity Claims

Subject identifiers or other relevant user identity claims may differ between domains. For example, a user may be identified differently in the originating domain than in the target domain. In such cases, either the authorization server in the originating domain or the authorization server in the target domain may perform a transcription between identities. Which server performs this depends on which party has knowledge of the required mappings.

In cross-domain use cases, it may also be necessary to prevent the disclosure of a user’s actual identity in the target domain. In such cases, it may be sufficient for the protected resource to know only that the user originates from the originating domain. The authorization server in the originating domain is responsible for replacing the actual user identity (for example, the sub claim) with a pseudonymous value. If this feature is used, the originating authorization server MUST be able to map the pseudonym back to the actual identity value, for example for out-of-band investigations of potential attacks or fraud.

3.6. Examples

This section provides a non-normative, end-to-end illustration of the cross-domain token exchange flow as described in the first sequence diagram in Section 3.2.

The example uses the following identifiers:

For readability, long values are folded and signatures are abbreviated.

Note on scopes across domains: In this example, the originating domain uses the scope a-api-read and the target domain uses the scope b-api-read. This reflects that scopes are domain-specific and require mapping as described in Section 3.5.1.

Furthermore, for this example, the meaning of a-api-read is that the possession of it grants access to API A and API B (and possibly other API:s in B). In domain B, the scope b-api-read grants access to API B.

Inbound Access Token:

The decoded access token JWT that the application in domain A has in its possession is shown below.

{
  "iss": "https://as.domain-a.com",
  "aud": ["https://api.domain-a.com", "https://as.domain-a.com"],
  "sub": "user-1234",
  "acr": "http://id.elegnamnden.se/loa/1.0/loa3",
  "client_id": "https://app.domain-a.com",
  "scope": "a-api-read a-api-write",
  "jti": "inbound-app-123",
  "nbf": 1696500000,
  "iat": 1696500000,
  "exp": 1696503600
}

As shown in the JWT, the access token was issued for use at https://api.domain-a.com (a protected resource within domain A). The authorization server has also added itself as a valid audience (https://as.domain-a.com). See Section 4.2.1, Issuing a Token Usable for Token Exchange.

In this example, the acr claim is included to indicate the authentication context under which the subject (user) was authenticated. In a real-life scenario, the access token may contain additional claims representing the user identity and authentication.

It is worth noting that the access token contains two scopes: a-api-read and a-api-write.

Token Exchange Request:

Next, the application needs to make a cross-domain call to domain B, and therefore submits a token exchange request according to Section 3.3.1 to the authorization server in its own domain.

POST /token HTTP/1.1
Host: as.domain-a.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:token-exchange&
subject_token=eyJhbGciOi...inbound-app-123...&
subject_token_type=urn:ietf:params:oauth:token-type:access_token&
audience=https%3A%2F%2Fas.domain-b.com&
scope=a-api-read&
client_id=https%3A%2F%2Fapp.domain-a.com&
client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&
client_assertion=eyJhbGciOi...

Token Exchange Response with JWT Authorization Grant:

The authorization server in domain A processes the token exchange request according to Section 3.3.3 and, if permitted by the token exchange policy for domain B, issues a JWT authorization grant as specified in Section 3.3.4.

The response:

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
  "access_token": "eyJhbGciOi...jwt-authorization-grant...",
  "issued_token_type": "urn:ietf:params:oauth:token-type:jwt",
  "token_type": "N_A",
  "expires_in": 300,
  "scope": "a-api-read"
}

The decoded JWT authorization grant (the value of the response access_token field):

{
  "iss": "https://as.domain-a.com",
  "aud": "https://as.domain-b.com",
  "sub": "user-1234",
  "acr": "http://id.elegnamnden.se/loa/1.0/loa3",
  "client_id": "https://app.domain-a.com",
  "scope": "a-api-read",
  "jti": "grant-456",
  "nbf": 1696500000,
  "iat": 1696500000,
  "exp": 1696500300,
  "act": {
    "sub": "https://app.domain-a.com"
  }
}

Access Token Request to Authorization Server in Domain B:

Next, the application in domain A acts as an OAuth 2.0 client towards the authorization server in domain A, and sends a token request according to Section 3.4.1, including the JWT authorization grant.

POST /token HTTP/1.1
Host: as.domain-b.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&
assertion=eyJhbGciOi...grant-456...&
scope=b-api-read&
client_id=https%3A%2F%2Fapp.domain-a.com&
resource=https%3A%2F%2Fapi.domain-b.com&
client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&
client_assertion=eyJhbGciOi...

Access Token Response from Authorization Server in Domain B:

When the authorization server in domain B receives the token request, it processes it according to Section 3.4.2 before issuing a token response containing an access token, as specified in Section 3.4.3.

The token response:

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
  "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImJiLWtpZC0wMDEiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FzLmRvbWFpbi1iLmNvbSIsImF1ZCI6Imh0dHBzOi8vYXBpLmRvbWFpbi1iLmNvbSIsInN1YiI6InVzZXItMTIzNCIsImNsaWVudF9pZCI6Imh0dHBzOi8vYXBwLmRvbWFpbi1hLmNvbSIsInNjb3BlIjoiYi1hcGktcmVhZCIsImp0aSI6Im5ldy1iLTc4OSIsIm5iZiI6MTY5NjUwMDMwMCwiaWF0IjoxNjk2NTAwMzAwLCJleHAiOjE2OTY1MDM5MDB9.au3P...sig",
  "issued_token_type": "urn:ietf:params:oauth:token-type:access_token",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "b-api-read"
}

The decoded access token:

{
  "iss": "https://as.domain-b.com",
  "aud": "https://api.domain-b.com",
  "sub": "user-1234",
  "client_id": "https://app.domain-a.com",
  "https://claim.domainb.com/custom": "foobar",
  "scope": "b-api-read",
  "act": {
    "sub": "https://app.domain-a.com"
  },
  "jti": "new-b-789",
  "nbf": 1696500300,
  "iat": 1696500300,
  "exp": 1696503900
}

Given this access token, the application in domain A can now call the protected resource https://api.domain-b.com in domain B.

4. General Token Exchange Requirements and Considerations

This section defines requirements and considerations that are common to both use cases profiled in this specification.

4.1. The Resource and Audience Parameters

The resource parameter, as defined in [RFC8707], and the audience parameter, as defined in [RFC8693], are two separate but related ways of indicating the target service for a token exchange operation.

[RFC8693] states that the resource parameter should be used when the client does not know the logical name of the target service, and that the audience parameter should be used when such a logical name is known to the client.

To promote interoperability, this profile specifies the following requirements:

4.2. Subject Token Requirements and Considerations

The token supplied as a subject_token in a token exchange request, for the use cases profiled in this specification, is either an access token or a refresh token.

This section defines the requirements for issuing access tokens and refresh tokens that may later be used in a token exchange request, as well as the requirements that an authorization server functioning as a Security Token Service MUST apply when processing such a request.

4.2.1. Issuing a Token Usable for Token Exchange

This section specifies requirements and considerations for authorization servers that issue tokens which may later be used as input in a token exchange request to the same authorization server.

Example:

{
  "aud": ["https://api.example.com", "https://as.example.com"],
  "iss": "https://as.example.com",
  "sub": "user-1234",
  "client_id": "https://client.example.com",
  "may_act": {
    "sub": "https://client.example.com"
  },
  "scope": "api-read",
  "jti": "8ujkdsna7",
  "nbf": 1696500000,
  "iat": 1696500000,
  "exp": 1696503600
}

4.2.2. Processing Requirements for a Subject Token

This section specifies the requirements for how an authorization server processing a token exchange request MUST verify the subject token (subject_token) provided in the request.

Note: When a refresh token is supplied as a subject_token, its underlying representation, based on the original authorization, is verified against the requirements above.

4.3. Token Exchange and the User and Resource Owner Distinction

Section 1.5 of [Ena.OAuth2.Profile] describes the distinction between the typical OAuth 2.0 usage, where the user is the resource owner and delegates access to a client for a protected resource, and cases where the OAuth authorization code flow is used even though the user is not the owner of the protected resource.

The major difference between these two OAuth usages lies in what happens at the authorization server when a client sends an authorization request:

Given these distinctions, this profile defines the following requirements for token exchange requests:

[*]: User consent may be either explicit, meaning that the user gives consent through a dialogue at the authorization server, or implicit, meaning that the consent is based on a previously accepted user agreement or similar.

5. References

5.1. Normative References


[RFC2119]

Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", March 1997.


[RFC6749]

Hardt, D., "The OAuth 2.0 Authorization Framework", RFC 6749, DOI 10.17487/RFC6749, October 2012.


[RFC7523]

Jones, M., Campbell, B., and C. Mortimore, "JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants", RFC 7523, DOI 10.17487/RFC7523, May 2015.


[RFC8693]

Jones, M., Campbell, B., and D. Waite, "OAuth 2.0 Token Exchange", RFC 8693, DOI 10.17487/RFC8693, January 2020.


[RFC8707]

Campbell, B., Bradley, J., and H. Tschofenig, "Resource Indicators for OAuth 2.0", RFC 8707, DOI 10.17487/RFC8707, February 2020.


[RFC9449]

Fett, D., Campbell, B., Bradley, J., Lodderstedt, T., Jones, M., and D. Waite, "OAuth 2.0 Demonstrating Proof of Possession (DPoP)", RFC 9449, DOI 10.17487/RFC9449, September 2023.


[Ena.OAuth2.Profile]

Ena OAuth 2.0 Interoperability Profile

5.2. Informational References


[Draft.ID-Chaining]

Schwenkschuster, A., Kasselmann, P., Burgin, K., Jenkins, M., and B. Campbell, "OAuth Identity and Authorization Chaining Across Domains", draft-ietf-oauth-identity-chaining-06, September 2025.