Delegation and impersonation
The photo API can ask the authorization server for a token to use at the storage service. Before looking at that request, there is a question the new token has to answer. It will be about you, user-2048, but you will not be the one presenting it. The photo API will.
Should the storage service be told that? The answer changes what the storage service can check, what its records show afterwards, and how much harm a misused token can do.
Two answers to who is acting
Token exchange recognizes two answers.
With impersonation, the new token is simply about you. The storage service sees a subject of user-2048, and the token makes no statement that anyone else is acting for you. Within the rights the token carries, whoever presents it is treated as you and cannot be told apart from you. Other parts of the system, such as the authorization server's own records, may know that an exchange took place, but the token does not tell its recipient.
With delegation, the token is still about you, and it also identifies the party acting for you. The photo API keeps its own identity. The storage service can see that the photo API is reading your files on your behalf, and can treat that differently from you reading them yourself, or from some other service trying the same thing.
Which form a new token takes is the authorization server's decision, made by its policy for the requesting client and the target. A client can supply information about the actor, but the server decides what the token says.
Recording the actor
Delegation is recorded in a JWT with the act (actor) claim. Its value is a JSON object whose members identify the party that is acting.
All domains, identifiers, and tokens in these examples are fictional. The photo service's policy is to issue delegation tokens for the photo API's calls, naming the photo API as the actor, so the storage token includes these claims, among others:
{
"sub": "user-2048",
"client_id": "photo-api",
"act": {
"sub": "photo-api"
}
}
sub is still you. Inside act, sub names the photo API, using its client ID because that is how the photo service knows it. client_id names the client that requested this token. Here the client and the actor are the same party, so both say photo-api, but they answer different questions: which registered client asked for the token, and who is acting for its subject. They differ when the actor is someone other than the client.
Claims inside act only identify the actor. They have no say in whether the token is valid: an exp or aud placed inside act would mean nothing, and the token's top-level claims alone decide where and until when it can be used. When a subject identifier is unique only within its issuer, act can carry iss alongside sub.
An act claim can also contain another act. When a service that received a delegation token exchanges it again, the authorization server can record the earlier actor inside the new one. The outermost act names the current actor, and the nested ones form a history of earlier steps. Working through an example follows a chain like that.
The support console
Impersonation is most tempting where people help other people. The printing company's support team uses an internal support console. When you write in because the cover of your photo book looks wrong, an agent wants to see your order the way you see it.
The printer runs its own authorization server, https://auth.printer.example, for its internal APIs, including an orders API at https://orders.printer.example. Your printer account is customer-881, and the agent who picks up your request is staff-17. The console could be given either of these tokens:
Impersonation:
{
"iss": "https://auth.printer.example",
"sub": "customer-881",
"aud": "https://orders.printer.example",
"client_id": "support-console",
"scope": "orders.read",
"iat": 1790845500,
"exp": 1790846100,
"jti": "demo-support-token-1"
}
Delegation:
{
"iss": "https://auth.printer.example",
"sub": "customer-881",
"aud": "https://orders.printer.example",
"client_id": "support-console",
"scope": "orders.read",
"iat": 1790845500,
"exp": 1790846100,
"jti": "demo-support-token-2",
"act": {
"sub": "staff-17"
}
}
Both tokens last ten minutes, from 09:05 to 09:15 UTC. To the orders API, the first one is you. Anything the agent does with it is recorded as yours. Its client_id reveals that the support console asked for it, but not who was sitting at the console.
The second says plainly that staff-17 is acting for customer-881. The orders API can let the agent view the order while refusing to change the delivery address, record the agent's actions under both names, and show you afterwards that support looked at your order.
Keeping impersonation narrow
The property that defines impersonation is also its danger. A party that impersonates you receives your rights within the token's context and cannot be told apart from you there. An agent holding an impersonation token for your account can do whatever the token allows you to do, and every record at the API says you did it. A compromised console, or an agent acting in bad faith, leaves no trace there of who really acted.
Sometimes impersonation is still the practical choice. An older API might understand only tokens about the customer, or a problem might appear only when a request looks exactly like the customer's own. When an authorization server issues impersonation tokens, it keeps them small:
- A narrow scope, such as viewing orders, and never payment details or account security settings.
- A short lifetime. The specification notes that impersonation can be limited in scope, in time, or even to a single use.
- Only specific clients, such as the support console, may request one, and only for agents whose current role allows it.
- A reason attached, such as an open support request, and a record at the authorization server naming both the agent and the customer, because the token itself will not.
- A notice to the customer that support accessed the account.
Delegation is the better default wherever the recipient can understand it. It costs one claim, and it keeps the actor visible to the API making the decision and to anyone reading that API's records later.