OAuth 2.0 Token Exchange
The Token Exchange extension specifies a process by which a client can acquire its own tokens using a different set of tokens. This has several applications, including:
- Single-sign-on between multiple mobile apps without launching a web browser
- A resource server exchanging a client's tokens for its own tokens
In alignment with the specification outlined in RFC 8693, Identify supports this feature, underscoring our commitment to providing robust authentication and authorization mechanisms for our users and clients.
What is Token Exchange?
OAuth 2.0 Token Exchange extends the capabilities of the OAuth 2.0 protocol by allowing client applications to seamlessly request and acquire security tokens, such as access tokens, from an authorization server functioning as a Security Token Service (STS).
Put simply, a client application can request access to resources using an access token obtained from a third-party authorization server. It can then exchange this token for an access token issued by the target authorization server. The client then uses this exchanged token to authenticate its request for target resources.
Security tokens obtained from the Identify can allow the bearer to either impersonate or delegate the original service.
OpenId Connect Discovery endpoint
The OpenID Connect Discovery endpoint now contains a new supported grant type: urn:ietf:params:oauth:grant-type:token-exchange in the grant_types_supported
property:
"grant_types_supported": [
...
"urn:ietf:params:oauth:grant-type:token-exchange"
],
Configuration
To use the Token exchange grant type in Identify, follow these steps to configure the OAuth/OIDC applcation:
- Open the existing OAuth/OIDC application in the application list.
- Go to its Security tab and enable the Allow Token Exchange setting.
- Validate tokens from trusted issuers: The Token Exchange grant type supports security tokens signed by RSA or HMAC keys. To validate tokens from trusted issuers, depending on the signing algorithm, you can add them to the trusted issuers in the Bootstrap token trusted issuers section or the Issuer symmetric signing keys section in its Connection tab.
You can also enable additional validation option:
- Signing certificate revocation check: When the selected value is not None, Identify performs a revocation check for the signing certificate used to sign the security token in the subject_token parameter and the actor_token parameter (if present).
As a side note, if the security token provided in either the subject_token parameter or the actor_token parameter is also issued by your Safewhere Identify instance and is signed using its primary signing certificate, you do not need to add its issuer information to the trusted issuer list in the Bootstrap token trusted issuers section.
Token exchange request
Perform a POST operation to the token endpoint:
https://#identifydomain/runtime/oauth2/token.idp
With the following parameters:
Parameter | Requirement type | Description |
---|---|---|
grant_type | REQUIRED | This must be "urn:ietf:params:oauth:grant-type:token-exchange" |
subject_token | REQUIRED | Indicates the security token that represents the identity of the party on behalf of whom the request is being made |
subject_token_type | REQUIRED | Indicates the type of the security token in the "subject_token" parameter: - urn:ietf:params:oauth:token-type:access_token - urn:ietf:params:oauth:token-type:refresh_token - urn:ietf:params:oauth:token-type:id_token - urn:ietf:params:oauth:token-type:jwt |
actor_token | OPTIONAL | Indicates the security token that represents the identity of the acting party |
actor_token_type | REQUIRED* | Indicates the type of the security token in the "actor_token" parameter: - urn:ietf:params:oauth:token-type:access_token - urn:ietf:params:oauth:token-type:refresh_token - urn:ietf:params:oauth:token-type:id_token - urn:ietf:params:oauth:token-type:jwt (*) When the "actor_token" request parameter is given, this parameter is REQUIRED |
requested_token_type | OPTIONAL | Indicates the type of the requested security token: - urn:ietf:params:oauth:token-type:access_token - urn:ietf:params:oauth:token-type:refresh_token - urn:ietf:params:oauth:token-type:id_token - urn:ietf:params:oauth:token-type:jwt If omitted, the requested security token type is "urn:ietf:params:oauth:token-type:access_token" |
resource | OPTIONAL | Indicates the target service or resource where the client intends to use the requested security token. This parameter may be specified multi times in the token request |
scope | OPTIONAL | A list of space-delimited registered scopes |
client_id | REQUIRED | Your application's client ID |
client_secret | REQUIRED* | Your application's client secret. (*) When the client authentication method is either client_secret_basic or client_secret_post, this parameter is REQUIRED |
Impersonation token exchange request sample
In the following token exchange request, a client is requesting a token and providing only a subject_token.
POST /runtime/oauth2/token.idp //Line breaks for clarity
Host: identify01.identify.safewhere.com
Content-Type: application/x-www-form-urlencoded
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atoken-exchange
&subject_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Aaccess_token
&subject_token=eyJhbGciOiJSUzI1NiIsImtpZCI6Il94STJIMGxvaDRVZGlGN184a1dmUTRoWC1tNCIsIng1dCI6Il94STJIMGxvaDRVZGlGN184a1dmUTRoWC1tNCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsInVpSWQiOi....3uGhac6lbfjZ7vg67LHQ
&client_id=rfc8693-test
&client_secret=rfc8693-secret
Delegation token exchange request sample
In the following token exchange request, a client is requesting a token and providing both a subject_token and an actor_token.
POST /runtime/oauth2/token.idp //Line breaks for clarity
Host: identify01.identify.safewhere.com
Content-Type: application/x-www-form-urlencoded
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atoken-exchange
&scope=openid
&subject_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Aaccess_token
&subject_token=eyJhbGciOiJSUzI1NiIsI....iKQxxsDFf3-8Z4
&client_id=oidc-rfc8693-test
&client_secret=rfc8693-secret
&actor_token=eyJhbGciOiJSUzI1NiIsIm....B7HTx6RSvHkenmtP0QjjfYvw
&actor_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Aaccess_token
"may_act" claim validation
The may_act
claim in the security token provided provided in the subject_token is used to ascertain if the client (or party identified in the actor_token) is authorized to engage in the requested delegation or impersonation. Its claim value is a JSON object, and members in the JSON object are claims that identify the party that is asserted as being eligible to act for the party identified by the JWT containing the claim.
Example:
"may_act": {
"sub": "test_identify01",
"client_id": "identify01_subjectClientID"
}
Identify will validate this may_act
claim according to the ActAs authorization claim rules
configured in the OAuth/OIDC application
Here are the validation rules:
- If the
ActAs authorization claim rules
are not set (the list is empty), any request containing amay_act
claim will be rejected. - If there are configured values in the
ActAs authorization claim rules
but themay_act
claim is missing, the request will also be rejected. - If both the
may_act
claim andActAs authorization claim rules
are present, Identify will verify that all claims withinmay_act
match at least one of the rules. A request is deemed valid only if every claim inmay_act
is fulfilled. Note that the values inActAs authorization claim rules
can include regular expressions.
When a valid may_act
claim is present, it will be applied to the generating act
claim in the issued access token.
Token Exchange response
Successful response
If the token request is valid and meets all policies and criteria, Identify generates a fresh security token with the following capabilities:
- It allows the requester to assume the identity of another entity if no actor token was provided in the request.
- If an actor token was provided and the requester's identity is confirmed, it enables the requester to delegate third-party privileges.
The following table shows parameters related to the token exchange response:
Parameter | Description |
---|---|
token_type | Its value is "Bearer" |
access_token | Indicates the issued security token in response to the token exchange request |
expires_in | Indicates the validity lifetime of the issued security token, in seconds |
issued_token_type | Indicates the token type of the issued security token in response to the requested_token_type parameter in the token exchange request |
An example:
Dependent on the requested_token_type, the response may contain an additional id_token
or refresh_token
.
Access token parameter content
The access token contains an act
claim, which includes the identity information of the subject token:
"act": {
"sub": "usersubject",
"client_id": "webmvc_codeflow_id_oidc01"
}
If the token request contains a valid actor_token that includes the act
claim, the issued act
claim in the response access token will be nested.
"act": {
"sub": "useractor",
"client_id": "webmvc_codeflow_id_oidc02",
"act": {
"sub": "fromactortoken",
"client_id": "fromactortoken__ClientID"
}
}
You can learn more about impersonation token requests or delegation token requests here
Actor claim for Token Introspection
When invoking the Introspection endpoint to inspect the access token mentioned above, the Introspection response contains the act (actor) claim. Its value has the same semantics and format as the claim of the same name in the access token.
Example:
{
...
"act": {
"sub": "useractor",
"client_id": "webmvc_codeflow_id_oidc02",
"act": {
"sub": "fromactortoken",
"client_id": "fromactortoken__ClientID"
}
},
...
}
Error response
If the token request itself is not valid, or if either the subject_token or the actor_token is invalid for any reason, Identify will return an error response with the error parameter value set to invalid_request
{
"error": "invalid_request",
"error_description": "..."
}