RFC 8693 OAuth 2.0 Token Exchange

Introduction

RFC 8693 OAuth 2.0 Token Exchange (hereinafter “Token Exchange”) is a technical standard that defines a way to get a new token by presenting an existing token and optionally one more existing token at the token endpoint.

The specification is very flexible. To put it the other way around, the specification does not define details that are necessary for secure token exchange. Therefore, you have to consider further details in the undefined part to implement the specification in an authorization server.

This article describes some key details to implement the Token Exchange specification and Authlete’s support of this specification.

Specification

The diagram below illustrates the token exchange flow.

The following sections explain token types and token exchange request/response.

Tokens

There are two kinds of input tokens; a subject token and an actor token.

Subject Token

“Subject Token” is a mandatory input token. It “represents the identity of the party on behalf of whom the request is being made.” (excerpt from Section 2.1. Request of RFC 8693)

The specification expects that the subject identified by the subject token is used as the subject of the newly issued token.

Actor Token

“Actor Token” is an optional input token. It “represents the identity of the acting party.” (excerpt from Section 2.1. Request of RFC 8693)

If there is a need to distinguish the subject of the newly issued token from the acting party that uses the token, authorization server implementations may utilize the actor token and embed information about the acting party in the token to issue. Section 4.1 and Section 4.4 of RFC 8693 define JWT claims related to the acting party.

Token Types

As possible types of the tokens above, the specification lists the following token types and assigns token type identifiers to them. The identifiers of token types are registered at OAuth URI of OAuth Parameters of IANA (Internet Assigned Numbers Authority).

Token Type Token Type Identifier
JWT urn:ietf:params:oauth:token-type:jwt
Access Token urn:ietf:params:oauth:token-type:access_token
Refresh Token urn:ietf:params:oauth:token-type:refresh_token
ID Token urn:ietf:params:oauth:token-type:id_token
SAML 1.1 Assertion urn:ietf:params:oauth:token-type:saml1
SAML 2.0 Assertion urn:ietf:params:oauth:token-type:saml2

Token Exchange Request

A token exchange request is a kind of token requests.

Grant Type

To distinguish token exchange requests from other token requests, a new grant type urn:ietf:params:oauth:grant-type:token-exchange is defined in the specification. The value is used as the value of the grant_type request parameter of a token request.

Client Identification and Authentication

The specification does not require client authentication and even client identification at the token endpoint. Section 2.1. Request of RFC 8693 states it as follows.

The supported methods of client authentication and whether or not to allow unauthenticated or unidentified clients are deployment decisions that are at the discretion of the authorization server.

Technically speaking, “unauthenticated clients” means public clients (cf. RFC 6749 Section 2.1. Client Types) and “unidentified clients” means that a token request does not contain information whereby to identify the client making the request.

Although Appendix 1.1 of RFC 8693 shows an example of token exchange request from an unidentified client, such cases are appropriate only in limited conditions, such as a closed network within a service. In other circumstances, you have to define further details, which are out of the scope of RFC 8693, for secure token exchange.

Request Parameters

The following table shows parameters related to token exchange requests.

Request Parameter Necessity Description
grant_type REQUIRED The value urn:ietf:params:oauth:grant-type:token-exchange indicates that the token request is a token exchange request.
resource OPTIONAL Resources to be tied to the newly issued token. This request parameter may be specified multiple times. See RFC 8707 Resource Indicators for OAuth 2.0 for details.
audience OPTIONAL Audience of the newly issued token. This request parameter also may be specified multiple times.
scope OPTIONAL A list of space-delimited names of scopes that are to be tied to the newly issued token.
requested_token_type OPTIONAL The token type of the newly issued token that the client wishes. One of the registered token type identifiers.
subject_token REQUIRED The value of the subject token.
subject_token_type REQUIRED The token type of the subject token. One of the registered token type identifiers.
actor_token OPTIONAL The value of the actor token.
actor_token_type OPTIONAL The token type of the actor token. One of the registered token type identifiers. When the actor_token request parameter is given, this request parameter is REQUIRED. On the contrary, when the actor_token request parameter is not given, this request parameter must not be present.

Token Exchange Response

A token exchange response is a kind of token responses.

Response Parameters

The following table shows parameters related to token exchange responses.

Response Parameter Necessity Description
access_token REQUIRED Regardless of the token type, the value of the newly issued token is set to this response parameter.
issued_token_type REQUIRED The token type of the newly issued token. One of the registered token type identifier.
token_type REQUIRED When the token type of the newly issued token is urn:ietf:params:oauth:token-type:access_token, this response parameter has the same meaning as defined in RFC 6749 The OAuth 2.0 Authorization Framework. In other cases, "N_A" is set.
expires_in OPTIONAL The lifetime of the newly issued token in seconds.
scope OPTIONAL Scopes tied to the newly issued token. When the actual set of scopes tied to the newly issued token is different from the set requested by the token exchange request, this response parameter is REQUIRED.
refresh_token OPTIONAL A refresh token (cf. RFC 6749 Section 6. Refreshing an Access Token).

Support in Authlete

This section describes Authlete’s support for Token Exchange.

RFC 8693 is supported by Authlete 2.3 onwards.

Token Exchange Request

"action" value of /auth/token API response

On receiving a token request from a client, an authorization server will send the request content to Authlete’s /auth/token API as one of request parameters. This API will make a response that includes TOKEN_EXCHANGE as a value of action parameter if the following conditions are met:

  • The value of the grant_type request parameter of the token request is urn:ietf:params:oauth:grant-type:token-exchange
  • The request passes basic validation steps which are performed on Authlete server side

The following table lists response parameters related to Token Exchange in a response from the /auth/token API.

Response Parameter Type Description
resources string array The values of the resource request parameters.
audiences string array The values of the audience request parameters.
scopes string array The scopes listed in the scope request parameter.
requestedTokenType string A string representing the requested_token_type request parameter such as "ACCESS_TOKEN". (cf. TokenType.java)
subjectToken string The value of the subject_token request parameter.
subjectTokenType string A string representing the value of the subject_token_type request parameter such as "ACCESS_TOKEN". (cf. TokenType.java)
subjectTokenInfo object Information about the subject token. Available only when the token type is either access token or refresh token.
actorToken string The value of the actor_token request parameter.
actorTokenType string A string representing the value of the actor_token_type request parameter such as "ACCESS_TOKEN". (cf. TokenType.java)
actorTokenInfo object Information about the actor token. Available only when the token type is either access token or refresh token.

Token Validation

Regarding validation on input tokens, the specification states as follows.

In processing the request, the authorization server MUST perform the appropriate validation procedures for the indicated token type and, if the actor token is present, also perform the appropriate validation procedures for its indicated token type. The validity criteria and details of any particular token are beyond the scope of this document and are specific to the respective type of token and its content.

It means that an authorization server MUST perform an appropriate validation, but the RFC 8693 doesn’t define any details about token validation and leaves them to authorization server implementations. To reduce the burden of authorization servers, Authlete’s /auth/token API performs the following validation.

No. Validation
1 Confirm that the value of the requested_token_type request parameter is one of the registered token type identifiers if the request parameter is given and its value is not empty.
2 Confirm that the subject_token request parameter is given and its value is not empty.
3 Confirm that the subject_token_type request parameter is given and its value is one of the registered token type identifiers.
4 Confirm that the actor_token_type request parameter is given and its value is one of the registered token type identifiers if the actor_token request parameter is given and its value is not empty.
5 Confirm that the actor_token_type request parameter is not given or its value is empty when the actor_token request parameter is not given or its value is empty.

Furthermore, Authlete performs additional validation on the tokens specified by the subject_token request parameter and the actor_token request parameter according to their respective token types as shown below.

Token type: JWT

No. Validation
1 Confirm that the format conforms to the JWT specification (RFC 7519 JSON Web Token (JWT)).
2 Check if the JWT is encrypted and if it is encrypted, then (a) reject the token exchange request when the tokenExchangeEncryptedJwtRejected flag of the service is true or (b) skip remaining validation steps when the flag is false.
3 Confirm that the current time has not reached the time indicated by the exp claim if the JWT contains the claim.
4 Confirm that the current time is equal to or after the time indicated by the iat claim if the JWT contains the claim.
5 Confirm that the current time is equal to or after the time indicated by the nbf claim if the JWT contains the claim.
6 Check if the JWT is signed and if it is not signed, then (a) reject the token exchange request when the tokenExchangeUnsignedJwtRejected flag of the service is true or (b) finish validation on the input token.
7 (The signature of the JWT is not verified.)

Token type: Access Token

No. Validation
1 Confirm that the token is an access token that has been issued by the Authlete server of your service.
2 Confirm that the access token has not expired.
3 Confirm that the access token belongs to the service.

Token type: Refresh Token

No. Validation
1 Confirm that the token is a refresh token that has been issued by the Authlete server of your service.
2 Confirm that the refresh token has not expired.
3 Confirm that the refresh token belongs to the service.

Token type: ID Token

No. Validation
1 Confirm that the format conforms to the JWT specification (RFC 7519 JSON Web Token (JWT)).
2 Check if the ID Token is encrypted and if it is encrypted, then (a) reject the token exchange request when the tokenExchangeEncryptedJwtRejected flag of the service is true or (b) skip remaining validation steps when the flag is false.
3 Confirm that the ID Token contains the exp claim and the current time has not reached the time indicated by the claim.
4 Confirm that the ID Token contains the iat claim and the current time is equal to or after the time indicated by the claim.
5 Confirm that the current time is equal to or after the time indicated by the nbf claim if the ID Token contains the claim.
6 Confirm that the ID Token contains the iss claim and its value is a valid URI. In addition, confirm that the URI has the https scheme, no query component and no fragment component.
7 Confirm that the ID Token contains the aud claim and its value is a JSON string or an array of JSON strings.
8 Confirm that the value of the nonce claim is a JSON string if the ID Token contains the claim.
9 Check if the ID Token is signed and if it is not signed, then (a) reject the token exchange request when the tokenExchangeUnsignedJwtRejected flag of the service is true or (b) finish validation on the input token.
10 Confirm that the signature algorithm of the ID Token is asymmetric.
11 Verify the signature of the ID Token.

Token type: SAML 1.1 Assertion

No. Validation
1 (Authlete does not perform any validation for this token type.)

Token type: SAML 2.0 Assertion

No. Validation
1 (Authlete does not perform any validation for this token type.)

Token Exchange Response

/auth/token/create API

The authorization server performs necessary validation based on the response from the /auth/token API to determine what kind of token is issued, and make a token exchange response to the client.

The server uses Authlete’s /auth/token/create API to create the token exchange response, by specifying TOKEN_EXCHANGE as a value of grantType, which is one of request parameters to the API.

Configuring Token Exchange

To configure Token Exchange in Authlete, follow these steps:

Service Configuration

  1. Log in to the Authlete Management Console.
  2. Navigate to Service Settings.
  3. Go to Endpoints > Global Settings > Supported Grant Types and enable TOKEN_EXCHANGE grant.
  4. Go to Tokens and Claims > Advanced > Token Exchange.
  5. Review and disable any unnecessary flags to tighten the security of your Token Exchange configuration.
  6. Click Save Changes to apply the configuration.

To ensure secure token exchange, you need to define additional configurations outside the scope of RFC 8693. Authlete provides the following options for this purpose:

Configuration Option Type Description
Identifiable Clients Only boolean Rejects token exchange requests from unidentifiable clients.
Confidential Clients Only boolean Rejects token exchange requests from public clients.
Permitted Clients Only boolean Rejects token exchange requests from clients without explicit permission.
Reject Encrypted JWT boolean Rejects token exchange requests using encrypted JWTs as input tokens.
Reject Unsigned JWT boolean Rejects token exchange requests using unsigned JWTs as input tokens.

Client Configuration

  1. Navigate to Client Settings of your desired client.
  2. Go to Tokens and Claims > Advanced > Token Exchange.
  3. Enable Explicit Permission for Token Exchange to grant this client explicit permission to perform token exchange requests. This setting ensures that only authorized clients can perform token exchanges, especially when the service is configured to restrict token exchange to permitted clients.
  4. Click Save Changes to finalize the configuration.

Examples

Authorization Server Implementation

Processing the TOKEN_EXCHANGE Action

Authorization server implementations have to process the TOKEN_EXCHANGE action to support Token Exchange. The switch statement below excerpted from TokenRequestHandler.java in the authlete-java-jaxrs library is an example of processing the TOKEN_EXCHANGE action. The switch statement has a case entry for TOKEN_EXCHANGE.

// Dispatch according to the action.
switch (action)
{
    case INVALID_CLIENT:
        // 401 Unauthorized
        return ResponseUtil.unauthorized(content, CHALLENGE);

    case INTERNAL_SERVER_ERROR:
        // 500 Internal Server Error
        return ResponseUtil.internalServerError(content);

    case BAD_REQUEST:
        // 400 Bad Request
        return ResponseUtil.badRequest(content);

    case PASSWORD:
        // Process the token request whose flow is "Resource Owner Password Credentials".
        return handlePassword(response);

    case OK:
        // 200 OK
        return ResponseUtil.ok(content);

    case TOKEN_EXCHANGE:
        // Process the token exchange request (RFC 8693)
        return handleTokenExchange(response);

    case JWT_BEARER:
        // Process the token request which uses the grant type
        // urn:ietf:params:oauth:grant-type:jwt-bearer (RFC 7523).
        return handleJwtBearer(response);

    default:
        // This never happens.
        throw getApiCaller().unknownAction("/api/auth/token", action);
}

Processing token exchange requests

TokenExchanger.java in java-oauth-server, an open-source sample implementation of authorization server written in Java, is a sample implementation of processing a token exchange request.

Note that the implementation is just an example, and not intended for production use.

Request and Response Example

1. Prepare an ID Token in some way or other.

$ ID_TOKEN=eyJraWQiOiJhdXRobGV0ZS1mYXBpZGV2LWFwaS0yMDE4MDUyNCIsImFsZyI6IlJTMjU2In0.eyJpc3MiOiJodHRwczovL2ZhcGlkZXYtYXMuYXV0aGxldGUubmV0LyIsInN1YiI6IjEwMDQiLCJhdWQiOlsiNTg5OTQ2MzYxNDQ0ODA2MyJdLCJleHAiOjE2NTg2NzExMzAsImlhdCI6MTY1ODY3MDgzMCwiYXV0aF90aW1lIjoxNjU4NjcwODMwLCJub25jZSI6IjEyMzQ1Njc4OSIsInZlcmlmaWVkX2NsYWltcyI6eyJ2ZXJpZmljYXRpb24iOnsidHJ1c3RfZnJhbWV3b3JrIjoibmlzdF84MDBfNjNBIn0sImNsYWltcyI6eyJnaXZlbl9uYW1lIjoiSW5nYSIsImZhbWlseV9uYW1lIjoiU2lsdmVyc3RvbmUiLCJiaXJ0aGRhdGUiOiIxOTkxLTExLTA2IiwiOmFnZV8xOF9vcl9vdmVyIjpudWxsfX19.mxE8FQaDb0edY_rWasSQ7pEMXbFon7oWr-Ccv1dB15q8eh2MaKRGrgvwPw_XjAdXlMNzkcV6iEUjRUvLGTvzm7_45cdoOxRX1xWzQw-vwvRbM46xd3Yht3EVjyRUUBJ_92J1yBmu7Nn93rygcnCE-fC_bSTSIJWgEnoC7dpxHYnoJ2QHrIOYFMBAA_3ZYCLGpgiWbIZnB2D1ib2eqwJ9zoJqeFNEBhXo9ThYkASHYaG-ZWofy7364lgeV4Rqy1r4XqzchFRW4yzWs_IM72bTtXTUkstlNOxZU12KEz50uVhtcOXv06iI71I9vceRP-ZVICpq7Knt0vEKWTM41E3ziw

2. Make a token exchange request.

$ curl http://localhost:8080/api/token -d grant_type=urn:ietf:params:oauth:grant-type:token-exchange -d subject_token=$ID_TOKEN -d subject_token_type=urn:ietf:params:oauth:token-type:id_token -d client_id=5908895171 -d scope=email

3. Receive a token exchange response.

{
  "access_token":"NEdL-q9EfOI4S5XzaMeimXAXVqS139Jm9DTYeLUAd5o",
  "issued_token_type":"urn:ietf:params:oauth:token-type:access_token",
  "token_type":"Bearer",
  "expires_in":86400,
  "scope":"email",
  "refresh_token":"pK9f5OWIrx58_XWrE_SpCLLN-BM673ljliTSffjqwao"
}