Scenario 06 · adds internal call context
The request fans out inside your own walls
One agent request arrives at your edge and becomes eleven internal service calls, three queue messages and a batch job an hour later. The access token was audience-bound to the edge. Everything downstream still needs to know who it's acting for, under what authorization, in which request.
The two things people do instead
- Forward the access token everywhere. It preserves the user's identity, and gives every internal service a credential that works against your external API. A compromised log shipper becomes an authenticated caller with the user's full authority. The audience said "the edge" for a reason.
-
Drop the user and trust the network. Services authenticate with their own credentials and
pass a
user_idin a header. Every service now trusts every other's claim about who asked, with no cryptographic backing, and the audit trail says the orders service did it.
The first has a second form, one hop out: a tool forwarding the token it was handed, making the service downstream a replay target for a credential minted for you. Exchange it instead: token exchange or a transaction token inside your domain, identity chaining for a different authorization server. True whether the tool is a plain API or an agent someone else is calling.
This was always uncomfortable and mostly survivable, because the fan-out was deterministic: you could read the code and know what a request would touch. Which services an agent-initiated task reaches depends on what the agent decided, which depends on input you didn't write.
The mechanism
A credential scoped to one call chain
Transaction Tokens put a boundary at the edge of your trust domain. The external token stops there, and the edge calls a Transaction Token Service, a Token Exchange endpoint, for a short-lived token valid only inside and only for this request. Part of it is frozen:
- Immutable context. Who the user is, which agent is acting, what was authorized. Set once at the edge, carried through every hop, unchangeable by anything downstream.
- A transaction identifier. One value tying all eleven calls, three messages and the batch job together, so your traces and your audit log describe the same thing.
- Per-hop requester context. Each service records what it's asking for without touching the frozen part.
- A very short life. Minutes. It's scoped to one request, and requests end.
// a transaction token, decoded
{
"iss": "https://txn-token-service.internal",
"aud": "https://internal.example", // inside only. useless outside.
"txn": "txn_01KAB93QF7X2", // ties the whole fan-out together
"sub": "user:9f3c21",
"purp": "process_return",
"exp": 1787894700,
"tctx": { // immutable: set at the edge, frozen
"actor": { "sub": "agent:support-agent/inst-7741" },
"client_id": "https://agent.example.com/clients/support-agent",
"approved_by": "user:31f0aa", // from scenario 04's challenge
"challenge_id": "chal_01K9M2X7"
},
"azd": { // what was actually authorized
"type": "refund",
"order_id": "ORD-88213",
"amount": { "currency": "GBP", "amount": "900.00" }
},
"rctx": { "req_ip": "203.0.113.44", "authn": "mfa" }
}
Notice what came through from four rungs down: the agent instance from scenario 00's key, the user from 01, the authorization details from 03, the approval from 04. The payments service has the whole story in a token it verifies locally. That's service nine, which has never heard of an agent.
The flow
Edge to service nine
-
Agent→Edge / API gateway
Arrives with a DPoP-bound access token, audience-restricted to the edge. The edge validates it and does not pass it on.
-
Edge→Txn Token Service
Token exchange: hands over the external token and the request context, receives a transaction token whose immutable context is now fixed for the life of this request.
-
Edge→Orders service
Calls inward, presenting the transaction token. Orders validates the signature locally, with no callback to an authorization server on the hot path.
-
Orders→Txn Token Service
Needs to call two more services. Requests a token for the next hop; the service can add its own requester context but cannot alter
tctx,suborazd. -
Orders→Payments service
Service nine sees the user, the agent instance, the approved refund and the approver, and enforces its own policy on all four.
-
Payments→Partner API
Leaving the domain again: the transaction token becomes the input to another exchange, producing an outbound grant with internal detail stripped out. Scenario 05, in reverse.
The transaction token chaining profile covers that last step, including claims minimization. The internal token's structure, service names and request context never cross back over the boundary. Your internal topology stays internal.
And then turning it off
Short lifetimes are why this degrades gracefully: a transaction token expires in minutes, so a compromised service has a small window and no external reach. But "revoke this agent everywhere, now" spans the IdP, several authorization servers and possibly a partner, and no token lifetime answers that during an incident.
The machinery is the Shared Signals Framework, with CAEP and RISC as its profiles: a standard way to tell another party, in near real time, that a session ended or a grant was revoked. What participants owe in return is enforcement. A service that honours a cached decision until it expires has turned a five-second problem into a five-minute one.
The biggest operational gap on the site, and not a design problem: the specs exist, but not enough parties have implemented their half. Until then, short tokens, rotated refresh tokens, and the refresh token and authorization expiration draft so an agent knows when its grant ends rather than discovering it.
The whole ladder, in one token
The transaction token at service nine contains the agent's identity, the user's, the specific operation, the human approval and the request that occasioned it. Each came from a different spec, most published years before anyone said "agentic," and none had to be redesigned.
That's the argument. Not that this is finished, because it isn't, but that the remaining work is a handful of drafts landing in an ecosystem that already has the hard parts built.