← Articles
August 21, 2026 · 10 min read #AI#Agents#Identity#Governance#Security

Your Agent Issued the Refund. Who Authorized It?

A support agent hands back $4,000 at 2am. You open the ledger to find out who approved it and the row says svc-agent-prod, which is the name of a process, not a person and not a decision. The uncomfortable part is not that the audit trail broke somewhere in the middle. Read the source of the popular agent frameworks and you find there was never a chain to break.

At 2:14am your support agent issues a refund. Four thousand dollars, back to a customer, with nobody awake. In the morning someone asks the ordinary question: who approved that?

You open the ledger. The row says:

principal  = svc-agent-prod
operation  = refund
amount     = 4000.00
customer   = 78122
at         = 02:14:07

svc-agent-prod is a service account: one set of long-lived credentials that the whole agent deployment uses for every action it takes, for every customer, on behalf of everyone. It is the name of a running process, not the name of a decision.

So the row establishes one fact. The production agent infrastructure caused this. It cannot tell you the thing you actually want to know.

Three different stories fit that row

At least three very different sequences produce that row, and it looks identical for all of them. A customer asked for a refund and the agent processed it. A customer asked about their bill and the agent decided a refund was the helpful answer. Or nobody asked, and an instruction buried in a support ticket told the agent to issue it.

That is the difference between a customer causing an action, a customer authorizing one, and an agent deciding alone. Your ledger cannot tell them apart, and neither can your on-call engineer at 8am.

Given a few hours you can usually still work it out from the chat transcript, the application logs and a trace. So be precise: the chain has not vanished, it has turned into archaeology. You reconstruct it afterwards across systems that were never designed to agree, and nothing you reconstruct is bound to the authorization decision itself. A trace proves two events belong to one request. It does not prove anyone was allowed to act.

The ledger row names the process that acted, not the authority it acted under A ledger row records the principal as svc-agent-prod, the operation as a four thousand dollar refund, and the time. Three questions cannot be answered from it: whether the customer asked for the refund, whether any human approved it, and whether the agent decided on its own. One row. Three stories that fit it equally well. WHAT THE LEDGER HAS principal = svc-agent-prod operation = refund amount = 4000.00 at = 02:14:07 the name of a process, not a decision WHAT IT CANNOT TELL YOU ✗ The customer asked for a refund, and the agent did it. ✗ The customer asked a billing question, and the agent decided a refund was the helpful answer. ✗ Nobody asked. An instruction inside a support ticket told the agent to issue it. IN PRACTICE: caused, authorized, and decided alone are three different things, and the log spells all three the same way.
The row names the actor, not the authority. Every refund this deployment ever issues carries the same principal, so the field that should answer "on whose say-so" is the one field that never varies.

This is not a rare configuration. In a January 2026 survey of 418 IT and security professionals by the Cloud Security Alliance, commissioned by Token Security, 68% said they had strong visibility into the agents in their environment and 82% had found at least one agent nobody had registered. Self-reported surveys measure belief, not systems, which is why the gap between those two numbers is the interesting part.

The chain was never there at hop one

The natural assumption is that identity gets lost somewhere deep in the call stack. Trace one tool call through the popular frameworks and you find something plainer.

In the OpenAI Agents SDK the client that talks to the model is built once from a key in a process-level global, not per request, and a tool call is your own Python function plus JSON arguments with no credential injected into it. Whatever that function uses to reach the outside world, it brought itself. LangGraph is the same shape: its tool node injects state, a store and a runtime object, and no authorization header. Off LangGraph’s hosted server the runtime’s user field is documented as None.

Now look at what crosses when one agent hands off to another: conversation items and an opaque application context. No field for the person who started this, none for what they authorized, none for how far that authority reaches. You can put a user ID in your own context object and nothing downstream will turn it into a credential.

So the frameworks do not lose the chain at hop three. They pass conversation, not authority, starting at hop one.

What actually crosses each hop from the customer to the ledger A request passes from the customer to an orchestrator agent, to a refund agent, to a tool, to the payments API, to the ledger. Between the agents, only conversation items and an opaque context cross. At the tool, only a name and JSON arguments cross. At the API, a service account credential is used. The customer's authority is dropped at the first hop and never travels with the request. Conversation travels. Authority does not. customer asks a question orchestrator plans the work refund agent picks the tool tool your function payments API, then ledger writes the row conversation items + opaque context conversation items + opaque context tool name + JSON arguments svc-agent-prod the agent's own key the customer's authority stops here, at the first hop, and never travels with the request IN PRACTICE: no field in the handoff carries who started this, what they allowed, or how far that permission reaches.
Nothing drops the chain, because nothing was carrying it. Each hop faithfully forwards what it was given. What it was given is a conversation.

The protocols underneath do not rescue this. In the Model Context Protocol, which is how agents reach tools, authorization is explicitly optional, and over a standard input and output connection the spec says to take credentials from the environment instead; a tool call carries a name and arguments. The Agent2Agent protocol, which is how agents reach each other, is blunter: identity is handled at the protocol layer, not within its semantics, and credentials are obtained out of band. Both are defensible protocol design. Neither gives the payments API the sentence it needs.

Four things can cross a hop

There are exactly four options at each step, and the choice decides what an auditor can rebuild later.

You can forward the customer’s own token, which is honest about the human, silent about the agent, and hands over every permission the customer has rather than the one the agent needs. You can swap to the agent’s service account, which is what most stacks do, and lose the human entirely. You can exchange the credential for a short-lived one naming both parties and only the scope required. Or you can carry a workload credential plus a separately signed record of who delegated what, which works only if the receiving service checks that record instead of trusting whoever handed it over.

The third option has a specification, and it is not new. RFC 8693, OAuth 2.0 Token Exchange, has been published since 2020. It defines a subject_token for the party on whose behalf a request is made, an actor_token for the party doing the acting, and an act claim naming the delegate. It even says that a chain of delegation can be expressed by nesting one act claim inside another, which is precisely the refund problem written down years before anyone deployed a support agent.

The mental model that keeps this safe is authority reduction. An exchanged token should carry the intersection of what the customer may do, what the agent may do, and what the target service accepts. It is never an upgrade.

Four options at each hop and what each one leaves for an auditor Forwarding the user token shows the human but hides the agent and over-grants permission. Swapping to a service account shows the workload and loses the human. Exchanging for a scoped token names both parties and the scope, and is fully reconstructable. Workload identity plus signed provenance is reconstructable only if the receiving service verifies the provenance. Four ways to cross one hop. Only one carries both parties. FORWARD USER TOKEN downstream sees the customer the log says sub = customer agent inherits every permission they hold, and is itself invisible SERVICE ACCOUNT downstream sees the deployment the log says svc-agent-prod the human disappears; every agent and every customer share one name TOKEN EXCHANGE downstream sees both, and the scope the log says sub=cust act=agent subject, actor, scope and expiry all reconstructable RFC 8693, since 2020 WORKLOAD + PROOF downstream sees attested workload plus a signed record of who delegated it strongest evidence, but worthless unless the receiver verifies it IN PRACTICE: a claim saying the customer approved this proves nothing if the service trusts whoever supplied the claim.
The choice at each hop is the audit trail. You are not deciding how to authenticate. You are deciding, months in advance, what a regulator or an incident reviewer will be able to reconstruct.

Rossoctl, an open source platform whose stated purpose is platform primitives for trustworthy AI agents, does implement token exchange. Immediately above the call that performs it:

// RFC 8693 Section 4.1 actor-token "act" claim chaining is not yet
// wired by any plugin; the wire-format support stays in
// exchange.ExchangeRequest.ActorToken for when a plugin needs it.

The field for the acting party is on the request structure. Nothing fills it in. That is not a knock on a project that is further along than most of its peers, and it is a fair picture of the state of the art: the delegation slot exists, and it is empty.

Four questions, four different mechanisms

The reason this stays unsolved is that “who authorized that?” is not one question. Workload identity answers what this running process is. Token exchange answers under whose authority it may act. An authorization policy answers whether this action is permitted. An audit record answers what happened. Teams buy a tool for one of those and expect the whole answer: cryptographic workload identity is excellent and will never tell you a customer approved a refund, and distributed tracing is excellent and is correlation, not authorization.

There is a fifth thing that no amount of identity plumbing replaces. Above some threshold, the action itself needs approving, with the amount and the account and the policy version written into the authorization record. You do not solve a $4,000 refund by adding another claim to a token.

Four questions, four mechanisms, and none of them answers alone Workload identity answers what process this is. Token exchange answers under whose authority it acts. Authorization policy answers whether the action is allowed. The audit record answers what happened. Answering who authorized an action requires all four together. Four questions. Buying one tool answers one quarter of it. What process is this? workload identity, attested at startup names the runner Under whose authority? token exchange, the act claim names the delegation Is this action allowed? authorization policy, evaluated per call makes the decision What happened? the audit record, written to survive keeps the evidence "who authorized that?" is answered by all four together, or by none of them IN PRACTICE: tracing joins the events into one story; it never establishes that anyone was permitted to act.
Four separate problems wearing one name. Most teams buy workload identity, get a real improvement in blast radius, and are surprised that the refund question is still unanswerable.

The honest cost, and when a service account is right

Doing this properly is not free, and the frameworks that demand accountability are conspicuously silent on the bill. There is no published figure for what a token exchange costs you per hop, so do not believe one.

What you can say concretely is what you are signing up to run. The service that issues tokens is now in the path of live requests, so it is an availability dependency, and when it is down the exchange fails. Short-lived credentials shrink your revocation window and raise your issuance traffic. Every agent identity acquires a lifecycle, which means somebody has to answer who owns agent-8f7d when it needs rotating. The policy engine that decides whether the refund is allowed can now take the refund path down with it, so you must decide per resource whether a policy outage fails open or closed. A $4,000 refund fails closed. Fetching product documentation can degrade.

And the most realistic failure is not dramatic. The first two hops carry the delegation faithfully and the third one drops it, so the chain looks healthy in testing and is broken exactly where the money moves.

The cost scales with the number of trust boundaries you cross, not with the number of agents you run. which is what makes this defensible rather than lazy: a shared service account is fine when no individual person’s authority is being represented. A metrics collector, a nightly job clearing cache, a read-only summarizer inside one system with a small blast radius. Those do not need any of this, and wiring them up because a vendor said machine identities are the future is cargo cult work. Give an agent its own identity when you need to revoke it separately during an incident. Reach for token exchange when the authorization genuinely depends on which person caused the action.

Gartner’s Shiva Varma put the failure mode well in May 2026: enterprises treat agent governance as binary, either locked down or fully trusted, and that is the root cause of failure.

When a shared service account is fine and when you need the delegation chain A shared service account is fine when no person's authority is represented, the work is read-only or trivial, and the blast radius is small. The delegation chain is needed when the action represents a specific person's authority, writes something consequential, and crosses a trust boundary. The bill includes a token issuer in the request path, a credential lifecycle per agent, a policy engine that becomes an availability dependency, and delegation that silently truncates. Pay for the chain where the authority is real. A SHARED SERVICE ACCOUNT IS FINE • no individual person's authority is represented • read-only, or the write is trivial and reversible • small blast radius, one trust boundary a nightly cache sweep does not need any of this YOU NEED THE CHAIN • the action carries a specific person's authority • it writes something consequential • it crosses a trust boundary, and money moves the 2am refund is every one of these at once THE BILL a token issuer in the live request path · a lifecycle per agent identity · a policy engine that can now take you down · and a chain that truncates at hop three while the first two look fine
The threshold is authority, not agent count. Cost grows with the number of trust boundaries you cross, which is why "identity for every agent" is the wrong budget line and "the chain where the money moves" is the right one.

Not a standards vacuum. An integration vacuum.

It would be comforting to conclude that the industry is waiting on a standard. It is not. Token exchange with a delegation claim was specified in 2020. Workload attestation is mature. Policy engines are commodity. Audit pipelines are a solved problem in every other regulated system your company runs.

What is missing is the wiring between them, and you can watch that gap in a code comment where the delegation field sits on a request struct with nothing to fill it. Meanwhile the incidents keep arriving in a shape that makes the point better than any framework does. When researchers demonstrated the RovoBlast flaw in Atlassian’s AI assistant this July, the most instructive detail was not that a crafted link could make the assistant exfiltrate data using the victim’s own privileges. It was that chaining the steps inside a single agent run left behind an audit trail that looked like ordinary research activity. That is the failure: not an agent doing something it should not, but an agent doing something consequential and leaving a record that cannot be told apart from routine work.

So when you review your own stack, skip the question of whether your agents have identities. Ask the harder one: for the most consequential thing an agent in your company can do, what evidence reaches the other end, and would it survive somebody asking, nine months later, who said yes? Building that answer into the retrieval, authorization, and audit layers of production systems is the work we do at Gracient. Let’s talk.