feat(oauth-provider): Implement RFC 8693 Token Exchange #2887

Open
opened 2026-03-13 10:25:46 -05:00 by GiteaMirror · 0 comments
Owner

Originally created by @AndreaJ-Vasquez on GitHub (Feb 17, 2026).

Is this suited for github?

  • Yes, this is suited for github

When building an application with a BFF that communicates with multiple protected resources using oauth-provider, there's no standard way to maintain user context across service-to-service calls.

With the authorization_code grant, the BFF receives an access token tied to a single audience. But in practice, the BFF often needs to call several downstream APIs each expecting its own audience, while some of those APIs still need to know who the original user is.

Beyond multi-audience scenarios, there's currently no way to support impersonation (a trusted service acting as the user) or delegation (one user acting on behalf of another). These patterns are common in systems and require audit trails to track who did what on whose behalf.

Describe the solution you'd like

Implement the Token Exchange grant type as defined in RFC 8693. https://datatracker.ietf.org/doc/html/rfc8693

Core Implementation
Add support for grant_type=urn:ietf:params:oauth:grant-type:token-exchange at the token endpoint with the following parameters:

Additonal request parameters in /token:

  • subject_token (required): The token representing the user/entity on whose behalf the request is made
  • subject_token_type (required): Token type identifier (e.g., urn:ietf:params:oauth:token-type:access_token)
  • actor_token (optional): Token representing the acting party (for delegation)
  • actor_token_type (required if actor_token present)
  • requested_token_type (optional): Type of token to issue

Two modes of operation
Impersonation: When only subject_token is provided, the issued token represents the subject directly. The client acts as if it were the subject, downstream services see the original user's identity.

Delegation: When both subject_token and actor_token are provided, the issued token contains an act claim indicating who is acting on behalf of the subject. This preserves auditability and allows policies based on the actor's identity.

Security considerations

  • Confidential clients only: Token exchange must be restricted to clients that can authenticate securely (with client_secret). Public clients cannot use this grant.
  • Opt-in per client: Clients must have allowedTokenExchange: true to use this grant. Disabled by default.
  • Scope validation: The client can only request scopes it's authorized for. Optionally, enforce that requested scopes don't exceed those in the original subject_token (downscoping).
  • may_act claim: If present in the subject_token, the authorization server validates that the requesting client/actor is authorized to act on behalf of the subject.

Describe alternatives you've considered

  1. Forwarding the original token → Downstream services may reject it due to audience mismatch, and it violates the principle of least privilege.
  2. Using Client Credentials grant → The user context (sub claim) is completely lost. The downstream service only knows which client is calling, not which user the request is for. This breaks user-specific authorization, audit trails, and per-user rate limiting.
  3. Requesting broad scopes upfront with an opaque token → Violates minimal authorization. Also, opaque tokens require introspection, which can only be introspected by the client that originally requested the token, impractical for multi-service architectures where JWTs with audience validation are preferred.

RFC 8693 Token Exchange is the standardized solution adopted by other identity providers.

Additional context

No response

Originally created by @AndreaJ-Vasquez on GitHub (Feb 17, 2026). ### Is this suited for github? - [x] Yes, this is suited for github ### Is your feature request related to a problem? Please describe. When building an application with a BFF that communicates with multiple protected resources using oauth-provider, there's no standard way to maintain user context across service-to-service calls. With the authorization_code grant, the BFF receives an access token tied to a single audience. But in practice, the BFF often needs to call several downstream APIs each expecting its own audience, while some of those APIs still need to know who the original user is. Beyond multi-audience scenarios, there's currently no way to support impersonation (a trusted service acting as the user) or delegation (one user acting on behalf of another). These patterns are common in systems and require audit trails to track who did what on whose behalf. ### Describe the solution you'd like Implement the Token Exchange grant type as defined in RFC 8693. https://datatracker.ietf.org/doc/html/rfc8693 **Core Implementation** Add support for `grant_type=urn:ietf:params:oauth:grant-type:token-exchange` at the token endpoint with the following parameters: Additonal request parameters in `/token`: - **subject_token (required):** The token representing the user/entity on whose behalf the request is made - **subject_token_type (required):** Token type identifier (e.g., urn:ietf:params:oauth:token-type:access_token) - **actor_token (optional):** Token representing the acting party (for delegation) - **actor_token_type** (required if actor_token present) - **requested_token_type** (optional): Type of token to issue Two modes of operation **Impersonation:** When only `subject_token` is provided, the issued token represents the subject directly. The client acts as if it were the subject, downstream services see the original user's identity. **Delegation:** When both `subject_token` and `actor_token` are provided, the issued token contains an act claim indicating who is acting on behalf of the subject. This preserves auditability and allows policies based on the actor's identity. **Security considerations** - **Confidential clients only:** Token exchange must be restricted to clients that can authenticate securely (with client_secret). Public clients cannot use this grant. - Opt-in per client: Clients must have `allowedTokenExchange: true` to use this grant. Disabled by default. - Scope validation: The client can only request scopes it's authorized for. Optionally, enforce that requested scopes don't exceed those in the original `subject_token` (downscoping). - may_act claim: If present in the `subject_token`, the authorization server validates that the requesting client/actor is authorized to act on behalf of the subject. ### Describe alternatives you've considered 1. **Forwarding the original token** → Downstream services may reject it due to audience mismatch, and it violates the principle of least privilege. 2. **Using Client Credentials grant** → The user context (sub claim) is completely lost. The downstream service only knows which client is calling, not which user the request is for. This breaks user-specific authorization, audit trails, and per-user rate limiting. 3. **Requesting broad scopes upfront with an opaque token** → Violates minimal authorization. Also, opaque tokens require introspection, which can only be introspected by the client that originally requested the token, impractical for multi-service architectures where JWTs with audience validation are preferred. RFC 8693 Token Exchange is the standardized solution adopted by other identity providers. ### Additional context _No response_
GiteaMirror added the enhancement label 2026-03-13 10:25:46 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#2887