Custom Token Exchange Beta
Overview
The Custom Token Exchange feature allows clients to exchange their existing tokens for Auth0 tokens by calling the /oauth/token
endpoint with specific parameters. You can use Actions to write custom code to decode subject_tokens
passed to the /oauth/token
endpoint, set the user in the transaction, and issue tokens for that user.
Custom Token Exchange allows customers to address advanced integration use cases. In particular, it is useful for integrating legacy systems or third-party services by converting their tokens into Auth0 tokens, thus enabling seamless authentication and authorization within the Auth0 ecosystem. It is also useful for exchanging Auth0 tokens for other Auth0 tokens, making it possible to get Auth0 tokens for a different audience or for a different client_id
.
Setup
Application
To use Custom Token Exchange, you must create a new application. To learn how to set up the new application with the proper settings, read Application Settings. Make sure to enable the Database Connection you intend to use with Custom Token Exchange for this application.
Once you've created the application, note the client_id
and client_secret
for later use when calling the /oauth/token
endpoint.
Actions
To configure Custom Token Exchange in your Auth0 tenant using Actions, follow these steps in the Auth0 Dashboard:
Navigate to Actions > Library.
Click Create Action > Build from Scratch.
3. In the Create Action dialog, enter a name and select the Custom Token Exchange Beta trigger from the drop-down.
4. Click Create.
Next, add the newly created Action to the Custom Token Exchange flow.
Navigate to Actions > Flows.
Click Custom Token Exchange Beta.
Under Add Action, click Custom. Then drag and drop your newly-created Action into the flow under Start. You will see Drop Here appear as you drag it.
4. Click Apply.
Now that you have an Action assigned to the Custom Token Exchange Beta flow, you can use the new Actions API methods available in the Custom Token Exchange Beta to set the user in the transaction.
Actions API
Custom Token Exchange vs Post Login Actions
The new Token Exchange Action available as a part of the Custom Token Exchange Beta is designed for use with the new API methods we have listed below.
For other use cases, such as adding custom claims to Access Tokens, your Post Login Actions will execute after the Token Exchange Action for the user that you set, thus giving you all the same functionality you have today for other login flows. You can identify the Token Exchange flow in your Post Login Action by searching for an “event.transaction.protocol”
value equal to “oauth2-token-exchange”
.
Use the Actions API
We have provided a number of APIs to use with your Token Exchange Action. You should implement an Action which decodes and validates the subject_token
based on the subject_token_type
. You can then indicate in your Action which user the subject token corresponds to. Auth0 will then issue access, ID, and refresh tokens for this user.
api.authentication.setUserByProfile
The setUserByProfile
command sets user profile attributes in a specified database connection. If the user does not exist, it is created on the fly with the specified attributes. If the user already exists, this command ensures that user profiles are updated with the provided attributes in a structured and controlled manner.
The setUserByProfile
command accepts the following parameters:
Parameter | Description |
---|---|
connection_name |
The name of the database connection where the user profile will be set. Limited to 512 characters. |
user_profile |
An object containing the user profile attributes to be set. Limited to 24 properties. |
Supported user_profile Properties
You can set the following profile properties for new users. These are the same properties supported by the Management API Update a user endpoint.
user_id
(required): note this is the external user's id provided by the external identity provideremail
(required)app_metadata
user_metadata
blocked
email_verified
given_name
family_name
name
nickname
picture
username
Example Usage
exports.onExecuteCustomTokenExchange = async (event, api) => {
// validate and decode your token, and extract user details
const user = validateToken(event.transaction.subject_token);
api.authentication.setUserByProfile('Username-Password-Authentication', {
user_id: user.id,
name: user.name,
email: user.email,
phone: user.phone_number,
user_metdata: {
department: user.department
}
});
Was this helpful?
api.authentication.setUserById
The setUserById
command sets user attributes based on a specified user ID. This allows you to specify an existing user without updating the profile. This will fail if the user does not yet exist.
The setUserById
accepts the following parameter:
Parameter | Description |
---|---|
user_id |
The user ID, such as auth0|55562040asf0aef . |
Example Usage
exports.onExecuteCustomTokenExchange = async (event, api) => {
// validate and decode your token, and extract user details
const user = validateToken(event.transaction.subject_token);
api.authentication.setUserById(user.id);
return;
};
Was this helpful?
api.access.deny
The deny command denies the login transaction and returns an error to the caller.
The deny command accepts the following parameters:
Parameter | Description |
---|---|
code |
A string which is returned in the error property in the response. Two “standard” error codes can be used:
If you use your own error code, it will return a |
reason |
A string which is returned in the error_description property in the response. |
Example Usage
exports.onExecuteCustomTokenExchange = async (event, api) => {
if (event.client.client_id !== 'HOVc2PDFTH7eahimN4yNCo8mOtjfNjLV') {
api.access.deny('invalid_request', 'Unable to process token exchange.');
}
// ...
};
Was this helpful?
Actions Event
In addition to new Actions API methods, you can use data in the Actions Event to learn about the context of the Token Exchange request, such as the subject token, IP address, client, and more.
Client parameters
Property | Type | Example |
---|---|---|
client_id |
string | HOVc2PDFTH7eahimN4yNCo8mOtjfNjLV |
name |
string | My Web App |
metadata |
object | { “foo”: “bar” } |
Tenant parameters
Property | Type | Example |
---|---|---|
id |
string | dev_1234 |
Request parameters
Parameter | Type | Example |
---|---|---|
geoip |
object | { … geoip object } |
hostname |
string | dev_1234.us.auth0.com |
ip |
string | 123.42.42.34 |
userAgent |
string | Mozilla/5.0 |
language |
string | en |
body |
object | { // raw req.body } |
method |
string | POST |
Transaction parameters
Property | Type | Example |
---|---|---|
subject_token_type |
string | urn://cic-migration-token |
subject_token |
string | 41598922a1745f7af70 |
requested_scopes |
string[] | [“openid”, “email”] |
requested_token_type |
string|null | urn:ietf:params:oauth:token-type:access_token |
Resource server parameters
Parameter | Type | Example |
---|---|---|
id |
string | http://acme-api/v1/profile |
Deploy the Action
After you create your Token Exchange Action using the API and Event object, you must deploy the changes by clicking the Deploy button at the top of the page in the Auth0 Dashboard.
Call Token Exchange
To use Custom Token Exchange, you need to call the POST /oauth/token
endpoint using the client_id
and client_secret
from the application you configured earlier. Note the new parameters used with Custom Token Exchange:
Parameter | Description |
---|---|
grant_type |
For Custom Token Exchange, use urn:ietf:params:oauth:grant-type:token-exchange . |
subject_token_type |
The type of the subject token. For Custom Token Exchange, this can be any url which is scoped under your own ownership, such as http://acme.com/legacy-token . ⚠️ Token types using Auth0 or IETF spec namespaces are not permitted. |
subject_token |
The subject token. |
client_id |
The client ID of the application you are using for the Token Exchange. As for other grant types, this can be conveyed in the Authorization header using HTTP Basic Auth. |
client_secret |
The client secret of the application you are using for the Token Exchange. As for other grant types, this can be conveyed in the Authorization header using HTTP Basic Auth. |
audience |
The API identifier defined in Auth0. |
scope |
The OAuth2 scope parameter. |
event.request.body
in the corresponding Action.Sample Request
curl --location –-request POST 'https://{domain}/oauth/token' \ --data '{ "grant_type":"urn:ietf:params:oauth:grant-type:token-exchange", "subject_token_type":"http://acme.com/migration", "subject_token":"fha9f3fadf0asffdfjsd", "client_id":"{clientId}", "client_secret":"clientSecret}", "audience":"urn:acme.com/v1/profile", "scope":"openid email profile" }'
Was this helpful?
Limitations
This is a beta feature, and thus comes with some limitations and incompatibility with other Auth0 features.
The following features are not supported (or will not work properly) with Custom Token Exchange Beta:
Organizations
MFA
Attack Detection
Non-DB Connections
Flexible Identifiers other than email
Impersonation Use Cases
Third-Party and Non-OIDC Conformant Clients
Rate Limits
The Custom Token Exchange Beta feature is configured with a fixed one request per second (RPS) rate limit. If you exceed 1 RPS, you will see a too_many_requests
error with the following message: Custom Token Exchange Beta rate limit exceeded
.
Troubleshooting
"Consent required” Response
In certain cases, you may see a consent_required
response when calling the token endpoint (error invalid_request
with error description Consent required
. In this case, you need to enable the Allow Skipping User Consent option for your API in the Auth0 Dashboard.