Custom Token Exchange allows you to exchange tokens from external identity providers or legacy authentication systems for Auth0 tokens without browser redirects. This implements OAuth 2.0 Token Exchange (RFC 8693).
NOTE: For complete documentation on Custom Token Exchange, configuration requirements, and detailed use cases, see the official Auth0 documentation.
Exchange a custom token for Auth0 tokens without creating a user session.
from auth0_server_python.auth_server.server_client import ServerClient
from auth0_server_python.auth_types import CustomTokenExchangeOptions
# Initialize the client
auth0 = ServerClient(
domain="<AUTH0_DOMAIN>",
client_id="<AUTH0_CLIENT_ID>",
client_secret="<AUTH0_CLIENT_SECRET>",
secret="<AUTH0_SECRET>"
)
# Exchange a custom token
response = await auth0.custom_token_exchange(
CustomTokenExchangeOptions(
subject_token="custom-token-from-external-system",
subject_token_type="urn:acme:mcp-token",
audience="https://api.example.com",
scope="read:data write:data"
)
)
# Access the exchanged tokens
print(f"Access Token: {response.access_token}")
print(f"Expires In: {response.expires_in} seconds")
if response.id_token:
print(f"ID Token: {response.id_token}")Exchange a custom token AND establish a user session.
from auth0_server_python.auth_types import LoginWithCustomTokenExchangeOptions
from fastapi import Request, Response
# Exchange token and create session
result = await auth0.login_with_custom_token_exchange(
LoginWithCustomTokenExchangeOptions(
subject_token="custom-token-from-external-system",
subject_token_type="urn:acme:mcp-token",
audience="https://api.example.com"
),
store_options={"request": request, "response": response}
)
# User is now logged in
user = result.state_data["user"]
print(f"User logged in: {user['sub']}")TIP: Use
login_with_custom_token_exchange()when you need both token exchange and session management (e.g., user migration flows). Usecustom_token_exchange()for pure token exchange scenarios (e.g., service-to-service authentication).
Enable delegation scenarios where one service acts on behalf of a user.
# Service acting on behalf of a user
response = await auth0.custom_token_exchange(
CustomTokenExchangeOptions(
subject_token="user-access-token",
subject_token_type="urn:ietf:params:oauth:token-type:access_token",
actor_token="service-access-token",
actor_token_type="urn:ietf:params:oauth:token-type:access_token",
audience="https://api.example.com"
)
)Pass additional parameters to the token endpoint.
response = await auth0.custom_token_exchange(
CustomTokenExchangeOptions(
subject_token="custom-token",
subject_token_type="urn:acme:mcp-token",
audience="https://api.example.com",
authorization_params={
"custom_field": "custom_value"
}
)
)NOTE: Critical parameters (
grant_type,client_id,subject_token,subject_token_type) cannot be overridden viaauthorization_paramsfor security reasons.
Specify an organization when exchanging tokens.
response = await auth0.custom_token_exchange(
CustomTokenExchangeOptions(
subject_token="custom-token",
subject_token_type="urn:acme:mcp-token",
audience="https://api.example.com",
organization="org_abc1234"
)
)from auth0_server_python.error import CustomTokenExchangeError
try:
response = await auth0.custom_token_exchange(
CustomTokenExchangeOptions(
subject_token="token",
subject_token_type="urn:acme:mcp-token"
)
)
except CustomTokenExchangeError as e:
print(f"Exchange failed: {e.code} - {e.message}")INVALID_TOKEN_FORMAT: Token is empty, whitespace-only, or has "Bearer " prefixMISSING_ACTOR_TOKEN_TYPE:actor_tokenprovided withoutactor_token_typeTOKEN_EXCHANGE_FAILED: General token exchange failureINVALID_RESPONSE: Auth0 returned a non-JSON response
Use standard URNs when possible:
# Standard token types
"urn:ietf:params:oauth:token-type:jwt" # JWT tokens
"urn:ietf:params:oauth:token-type:access_token" # OAuth access tokens
"urn:ietf:params:oauth:token-type:id_token" # OpenID Connect ID tokens
"urn:ietf:params:oauth:token-type:refresh_token" # OAuth refresh tokens
# Custom token types (use your own namespace)
"urn:acme:mcp-token"
"urn:company:legacy-token"