Flow · multi-hop
Multi-hop on-behalf-of (Token Exchange + chaining)
The user authorizes Agent A. A calls Service B. B must call API C in another domain without pretending to be the user or widening scope.
Use the hop list beside the stage, or the phase labels, to jump. Every hop has Now, Why, the RFC, and chips — none are skipped.
Actors
User · Agent A · AS A · AS B · API C
Sequence
Animated sequence · multi-hop
RFC 8693 — How does an actor get a new pass without becoming the user?
Multi-hop on-behalf-of (Token Exchange + chaining)
The user authorizes Agent A. A calls Service B. B must call API C in another domain without pretending to be the user or widening scope.
Now · 1/8· Discover· OAuth 2.1You are here
User→AS A·Authenticates at AS A (ordinary user-delegated grant)
The user authenticates at AS A. Agent A is the client, not the user.
Why Do not start at the exchange. The authorization-code + PKCE hops are the OAuth 2.1 sequence; we show login and consent so subject_token has a pedigree.
Alice shows ID. The messenger is not Alice.
- resource owner from the spec
- authentication from the spec
Solid = from the spec
Never expand scopes at a hop. Inside one domain, transaction tokens carry immutable purpose. Across domains, identity chaining is in the RFC Editor queue — still cite the draft until an RFC number exists.
Transcript
- 1
DiscoverUser→AS AOAuth 2.1
Authenticates at AS A (ordinary user-delegated grant)
The user authenticates at AS A. Agent A is the client, not the user.
Why Do not start at the exchange. The authorization-code + PKCE hops are the OAuth 2.1 sequence; we show login and consent so subject_token has a pedigree.
Alice shows ID. The messenger is not Alice.
- resource owner
- authentication
- 2
GrantUser→AS AOAuth 2.1
Consents to Agent A calling APIs on her behalf
Alice approves Agent A for a scope. That scope is the ceiling for every later act hop.
Why Consent is the original grant. Token exchange later must not widen what she approved.
Alice signs the first permission slip.
- consent
- scope
- 3
GrantAS A→Agent AOAuth 2.1
Issues Alice's access token. sub is Alice. No act yet
Ordinary delegated grant. subject_token later will be this access token. sub is the user; no act yet.
Why This string is the subject_token the exchange will present.
Alice's pass is issued. The name on it is still Alice.
- access token
- sub
- subject_token
- 4
GrantAgent A→AS ARFC 8693
Presents subject_token at the token endpoint (token exchange)
grant_type=urn:ietf:params:oauth:grant-type:token-exchange. subject_token = user token, actor_token = agent, attenuated scope, aud toward B.
Why Mint a new pass for a new audience or tighter scope, and record who is acting. Do not reuse Alice's original token at API C.
Ask the desk for a new pass: same owner, this messenger, a smaller door.
RFC 8693 act claim records the agent
- subject_token
- actor_token
- act
- 5
GrantAS A→Agent ARFC 8693
Returns a new token with act appended. sub is still Alice
The issued token keeps sub=user and adds act naming Agent A.
Why act records the actor. sub must not flip to the agent. The new token is a different string.
The pass still says Alice. A footnote names the hand holding it.
- sub
- act
- 6
GrantAgent A→AS ARFC 7523
If crossing domains: exchange for a JWT grant aud=AS B (identity chaining)
AS A mints a JWT authorization grant whose audience is AS B. Still do not widen scope.
Why Optional inside one domain. RFC 8693 alone does not define cross-domain trust. Identity chaining profiles 8693 with a JWT bearer grant. Shown so a beginner does not think 8693 hops the ocean unaided.
A letter of introduction to the next desk — not a photocopy of Alice.
- JWT bearer grant
- aud=AS B
- 7
GrantAgent A→AS BRFC 7523
Presents the JWT bearer grant at AS B's token endpoint
grant_type=jwt-bearer. Get an access token whose aud is API C.
Why AS B issues a pass for its resource, not a copy of AS A's token.
The foreign desk prints its own pass. Do not widen what it unlocks.
- grant_type=jwt-bearer
- access_token
- aud=API C
- 8
CallAgent A→API CRFC 6750
Presents audience-restricted, preferably PoP-bound token
Call API C with the new pass. Inside one domain, Txn-Tokens carry immutable purpose instead.
Why Authorization header, not query. Prefer DPoP/mTLS so the chain cannot be photocopied. Nested act (if present) is a chain of hands, not a new user sub.
Show the pass at door C. Glue it to a key if you can.
- Authorization
- aud
- DPoP
Caveats
Never expand scopes at a hop. Inside one domain, transaction tokens carry immutable purpose. Across domains, identity chaining is in the RFC Editor queue — still cite the draft until an RFC number exists.