OAuth 2.0 Token Exchange (RFC 8693) is indeed designed for this kind of scenario. It allows you to exchange an existing token (the user's web-audience token) for a new token with a different audience (e.g. mcp) while maintaining the user's identity and authorization context.
Important Note: FusionAuth does not currently implement RFC 8693 (OAuth 2.0 Token Exchange) natively. There is an open GitHub issue tracking this feature request. However, FusionAuth provides alternative approaches to achieve similar outcomes.
How Token Exchange Works (RFC 8693 Concept) User authenticates and receives a token with audience: web. AI agent receives a request from the user via the chat interface. Agent exchanges the token: The agent (or a backend service acting on its behalf) calls the token exchange endpoint, providing: The original web-audience token as the subject_token The desired new audience (mcp) in the audience parameter Optionally, a narrower set of scopes if the downstream service requires fewer permissions New token issued: The authorization server returns a new token with audience: mcp, tied to the same user identity. Agent calls downstream service using the new token. Example Token Exchange Request POST /oauth2/token Content-Type: application/x-www-form-urlencoded grant_type=urn:ietf:params:oauth:grant-type:token-exchange &subject_token=<user-web-token> &subject_token_type=urn:ietf:params:oauth:token-type:access_token &audience=mcp &scope=mcp:read mcp:write Current Alternatives in FusionAuthSince RFC 8693 isn't supported yet, here are the recommended approaches:
1. Issue a JWT APIUse the Issue a JWT endpoint to exchange a token from one application for a token for another application. This is FusionAuth's implementation of SSO for access tokens:
GET /api/jwt/issue?applicationId={targetApplicationId} Authorization: Bearer <existing_access_token>This returns a new JWT with the target application's audience, preserving the user's identity. The user must be registered in both applications.
2. JWT Populate LambdaUse a JWT Populate Lambda to customize the aud claim directly. You can add multiple audiences to avoid token swapping:
function populate(jwt, user, registration) { // Add multiple audiences jwt.aud = ['web', 'mcp', 'https://api.example.com']; } 3. Vend a JWT APIFor more complex delegation scenarios, use the Vend a JWT endpoint to create a custom JWT with free-form claims (except reserved claims like iat, exp, amr, and cnf).
Key Considerations Authorization: The agent should be a registered OAuth client with permission to perform token exchanges. You may want to restrict which clients can exchange tokens and for which audiences. Scope narrowing: The new token can have a subset of the original token's scopes, ensuring least-privilege access to the downstream service. User consent: Depending on your security requirements, you may want to prompt the user to authorize the agent's access to the downstream service the first time this exchange happens. Application registration: When using the Issue JWT approach, ensure the user is registered in both the source and target applications.This approach avoids re-authentication and cleanly separates concerns: the user holds their web token, and the agent dynamically obtains the correct token for each downstream service it needs to call.
Related Documentation OAuth 2.0 Grant Types - Token Exchange Grant - Overview of RFC 8693 token exchange Issue a JWT API - Exchange tokens between applications (FusionAuth's current solution) Vend a JWT API - Create custom JWTs for complex scenarios JWT Populate Lambda - Customize JWT claims including audience GitHub Issue #1471 - Track RFC 8693 implementation progress