SSOGEN / Learn / OAuth Token Exchange: Delegation and Impersonation Under RFC 8693
Learn
OAuth Token Exchange: Delegation and Impersonation Under RFC 8693
OAuth token exchange lets a client present one token and receive another with a different audience, and RFC 8693 covers both impersonation and delegation.
Updated

OAuth token exchange lets a client present one token to an authorization server and receive a different one in return. RFC 8693 defines it as a protocol for a security token service built on OAuth 2.0, and it covers both impersonation and delegation.
The issued token can differ from the input token in several ways:
- a different audience
- narrower scopes
- a different token format
- a record of who is acting for whom
The last point matters most for AI agents. A token can state “this agent, acting for Maria” instead of letting the agent pass as Maria.
What a token exchange request contains
The client sends an HTTP POST to the token endpoint with grant_type set to urn:ietf:params:oauth:grant-type:token-exchange. Section 2.1 defines the other parameters.
| Parameter | Required | Meaning |
|---|---|---|
grant_type |
Yes | The token-exchange URN above |
subject_token |
Yes | A token for the party on whose behalf the request is made |
subject_token_type |
Yes | What kind of token the subject token is |
actor_token |
No | A token for the party that will act |
actor_token_type |
Yes, if actor_token is sent |
What kind of token the actor token is |
resource |
No | The URI of the service where the new token will be used |
audience |
No | The logical name of that service |
scope |
No | The scopes you want on the new token |
requested_token_type |
No | The kind of token you want back |
Token types are identified by URNs, listed in section 3: urn:ietf:params:oauth:token-type:access_token, ...:refresh_token, ...:id_token, ...:jwt and two SAML forms.
A client can send several resource or audience values and request one token that is valid at all of them. The RFC advises requesting no more breadth than the client needs.
Delegation versus impersonation
Section 1.1 separates the two.
- Impersonation. A becomes indistinguishable from B within some context. The resource server sees B. Nothing in the token says A was involved.
- Delegation. A keeps its own identity. B has handed A some rights, and actions are understood to be taken by A representing B. The resource server can see both.
The audit log shows the difference. Under impersonation the log records Maria, even though a program performed the action. Under delegation the log can record Maria, through the invoice agent.
In the request, the actor token decides which one you get:
- Only a
subject_token: the client requests impersonation semantics. - A
subject_tokenfor the person plus anactor_tokenfor the agent: the client requests delegation.
Appendix A of the RFC shows both: A.1 impersonation, A.2 delegation.
A sample request with fictional values
An agent called agt_inv01 holds an access token for the person maria.lopez and a token of its own. It requests a token for the Acme invoices API with one scope. Token values are shortened.
POST /oauth2/token HTTP/1.1Host: login.acme.exampleContent-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:token-exchange&subject_token=<token that represents maria.lopez>&subject_token_type=urn:ietf:params:oauth:token-type:access_token&actor_token=<token that represents agt_inv01>&actor_token_type=urn:ietf:params:oauth:token-type:access_token&resource=https://invoices.acme.example/api&scope=invoices.readA successful response (section 2.2.1) contains access_token, issued_token_type and token_type, and normally expires_in. It includes scope when the issued scope differs from the requested one.
{ "access_token": "<new token>", "issued_token_type": "urn:ietf:params:oauth:token-type:access_token", "token_type": "DPoP", "expires_in": 240, "scope": "invoices.read"}token_type tells the client how to present the issued token; the RFC gives Bearer and N_A as examples. A deployment that binds tokens to a key, as in DPoP, can return DPoP. When the issued token is a JWT, the delegation appears in its act claim (section 4.1):
{ "iss": "https://login.acme.example", "sub": "maria.lopez", "act": { "sub": "agt_inv01" }, "aud": "https://invoices.acme.example/api", "scope": "invoices.read", "exp": 1791297720}subremains the person.actnames the party that is acting.- Nested
actclaims record a chain: the outermost entry is the current actor and inner entries are earlier actors.
A separate claim, may_act (section 4.4), states in advance that one party may become the actor for another.
Why it matters for AI agents
Without token exchange, an agent that calls tools for a person has three poor options, and each one breaks the audit trail or grants too much:
- use the person’s own token
- use a shared key
- act as itself, with no link to the person
Delegation is a fourth option: a token for this person, naming this agent, for one audience and scope set, with a short lifetime. It works only when the issuer enforces three rules:
- The issuer decides whether the agent may act for the person. An exchange is a request, not an entitlement; the issuer checks consent and policy first.
- The new token should be narrower, not wider. Scope and audience should only shrink.
- The resource server must read
act. If it only looks atsub, delegation looks like impersonation again.
An auditor needs more than the chain in the token: the AI agent delegation audit guide explains the record each action should leave.
Errors and what to check
Section 2.2.2 defines two error codes for token exchange:
invalid_request: the request is malformed, or the subject or actor token is invalid for any reason.invalid_target: the server can’t or won’t issue a token for the statedresourceoraudience.
| Symptom | Likely cause |
|---|---|
invalid_request |
Expired subject token, wrong subject_token_type, or actor_token without actor_token_type |
invalid_target |
The audience is not one the server will issue for, or this caller may not target it |
| Token works but logs show only the person | The resource server ignores act |
| Token works for a wider set than expected | scope or audience was not narrowed at issue time |
How SSOGEN records an agent acting for a person
SSOGEN records delegation in the credential it issues to an AI agent. When an agent acts for a person, the person is the subject and the agent is the actor.
The credential covers one application and its scopes, and lives 240 seconds by default and never more than 270.
- The person approves the agent first, on a consent screen that lists the scopes and the duration, and can withdraw that approval later in My Account.
- DPoP binds the credential to the agent’s key.
- The decision goes to the audit log with the actor chain. SSOGEN doesn’t use AI to make that decision.
See AI agent identity, how the MCP Gateway checks each tool call, and the guide to access control for agents.
Questions people ask
What is the difference between OAuth token exchange and a refresh token?
A refresh token obtains a new access token for the same client and grant. Token exchange trades a token for one with a different audience, scope, type or actor, and it can take two tokens as input.
Is token exchange the same as the on-behalf-of flow?
They solve a similar problem. RFC 8693 is the standard form; a vendor’s on-behalf-of flow is its own variant, so check the vendor’s documentation for the exact parameters.
Do I need an actor token?
Only for delegation. Without an actor token the client requests impersonation semantics, and the resource server won’t see the agent.
Can token exchange give an agent more access than the person has?
It shouldn’t. The issuer should limit the new token to what the person allowed and still has; whether a given server does so depends on its configuration.
Where to go next
- Related guides. The confused deputy problem and SPIFFE and SPIRE.
- Key binding. DPoP binds the resulting token to a key.
- Framework. OAuth 2.0 shows how the pieces fit.
- Governance. AI agent governance covers consent and review.
- Specification. RFC 8693.
Sources, all read 2026-10-09: RFC 8693.