Delegated access in the agentic era
Agents need to log in to things.
Not with your API key. Not with a copy of your password. With an identity of their own, permission you actually granted, and a trail you can read afterwards.
It's OAuth, and almost all of it already exists. What's been missing is a picture of how the pieces fit together for software that decides at runtime what it will touch. Seven scenarios, each adding one piece.
First, who's in the room
Four parties, and one of them is new.
One of the parties is new, and it changes where the credentials must not go.
-
User or System→Agent
Optional. A person, a batch job, or another agent hands the agent a task. It may also simply run on a schedule with no instruction at all.
-
Agent→Model
The agent gives the model the context it has: the request, its system prompt, the available tools, and whatever earlier tool output it accumulated.
-
Model→Agent
The model returns output determining which tool, service or resource gets called next. This is where a task becomes a decision about what to touch.
-
Agent→Tools · Services · Resources
The agent calls one or more external endpoints, any of which may itself be another agent. This is the arrow the rest of this site is about.
-
Tools · Services · Resources→Agent
Results come back, become more context, and steps 2 to 5 run again until the agent decides it's finished.
-
Agent→User or System
Optional. It answers, or asks for more input, or reports intermediate progress.
The model is a protected resource too. Step 2 is an authenticated API call needing what any other does: an identity for the caller, a scoped token, an audit trail. There's no useful difference between an API, an MCP server, and another agent wearing a tool's clothes.
The model must never be able to reach a credential. Steps 2 and 3 loop through a component that reads untrusted input and can be talked into printing things, so a credential in that context window is a credential you have published. The one rule here with no exceptions, and the argument for credentials the agent never holds on disk.
The same six flows
Six flows. Four parties. All of it OAuth.
The four parties sit in the same place in every diagram, and the flows get longer as you move right. Solid arrows are requests, dashed are responses. The fourth party stays idle until the last tab: crossing a company boundary is the only flow that needs a second authorization server.
An API key replaced with a key the agent holds. The token it earns is bound to that key, so a copy is worth nothing.
Delegation without a browser. The token names the person and the agent, so the API's log has both.
No registration step, and no human to go do one. The agent's client ID is a URL the server fetches.
Consent about the act, not the category. The request carries the payee and the amount; the token carries what was granted.
One invocation, challenged. A person approves those exact parameters, and the retry is checked against them.
Two companies, two authorization servers. Each keeps issuing its own tokens, and the user's identity survives.
- client assertion
- a JWT the agent signs with its own key, replacing a client secret
- DPoP proof
- signed per request, over this method and URL, so a stolen token is useless
- resource
- names the API the token is for, so it can't be replayed at a different one
- client_id
- a URL the authorization server fetches to find out who is asking
- request_uri
- a handle for a request already pushed to the authorization server
- authorization_details
- the operation and its parameters, not a category
- challenge
- signed by the resource, naming the one call it wants approved
- ID-JAG
- a short-lived, audience-bound grant that crosses a company boundary
One flow is missing. When a call arrives and fans out into eleven internal service calls, the question stops being how the agent gets in and becomes how the call context travels inward. That's transaction tokens.
The honest version
Software changed. Five assumptions broke.
OAuth was designed around integrations decided by people, in advance, and written down. Agents don't work that way, and the friction everyone is feeling is real.
The old shape
A developer registers their app, gets a client_id, picks scopes, and ships. A user clicks
"Connect," sees a consent screen in a browser, and approves. The app holds a token for months.
The new shape
An agent works out which services it needs while it is running. It meets a server nobody registered with, acts at 3am while its user sleeps, calls another agent that calls an API at a different company. None of it was written down in advance.
Nobody registered the client
Registration assumes a human filled out a form and got an identifier back. An agent that discovers a server mid-task has no identifier, and neither side wants a manual step mid-conversation.
Closed by Client ID Metadata Documents. The client publishes its own metadata at a URL, and that URL is the client ID.
There's no browser, and no one is watching
Consent was designed as a redirect: a person in front of a screen, reading a page. Agents run in terminals, in CI, at night, and the human may be hours away when a decision is needed.
Closed by the device grant, CIBA, and the transaction authorization challenge. Asynchronous approval, with polling, as a first-class flow.
"Read your email" is not a permission
Scopes name categories. Agents take specific actions: move this $4,000, delete that repository, email these forty people. A scope can't say which, so the consent is far broader than the act the user would approve.
Closed by Rich Authorization Requests. Structured authorization details describing the actual operation, not the category.
A bearer token is a bearer token
The whole security model of a bearer token is "don't let it leak," and agents copy credentials into prompts, logs, sandboxes and third-party runtimes. A leak is good for the token's entire lifetime, on any machine on earth.
Closed by DPoP and mTLS. The token is bound to a key the agent holds, so a stolen copy is inert.
By hop four, nobody knows who asked
A request passes through an agent, an MCP server, a partner's API and three internal services. Somewhere the original identity turns into "trust me, I'm the backend," and the log says a service did it.
Closed by Token Exchange, Identity Chaining and Transaction Tokens. The actor chain travels with the request across every hop.
Notice what isn't on this list
None is a flaw in OAuth's core idea: a resource owner granting software narrow, revocable, auditable access without handing over a credential. That's exactly what agents need. What broke are the assumptions layered on top, and each has a spec-shaped answer.
The ladder
Seven scenarios, each one piece bigger than the last.
Start with an agent that has no user and just needs to call an API. Add a person, a service nobody registered with, precision, absence, a company boundary, your own internals. Every rung reuses everything below it and adds one idea.
The agent acts as itself
A nightly job summarizes yesterday's support tickets. No user in the loop, and today it authenticates with a long-lived API key in an environment variable.
Adds: an identity that isn't a shared secret. A key the agent holds, and a short-lived token that's useless if it leaks.
Replace the API key
The agent acts for a person
Now the agent reads your calendar, so the API has to know two things at once: which software is asking, and whose data it may touch.
Adds: delegation. A token naming the user and the agent acting for them.
Add the human
The agent meets a service nobody registered with
Mid-conversation, the agent is pointed at an MCP server it has never seen, run by a company that has never heard of it. No portal step, no human free to go do one.
Adds: runtime discovery and registration-free clients. Protected resource metadata, and a client ID you can fetch.
Bootstrap from a URL
The agent says exactly what it's about to do
"This agent may send email on your behalf" is a promise with no edges. What the user wants to approve is "send this draft to these recipients."
Adds: structured intent. Authorization details describing the operation, so consent and the audit record are about the act.
Get specific
Nobody's watching and it needs permission
Forty minutes in, the agent hits the one step that needs a person: a refund above the limit, a production deploy. Its user is asleep, and guessing is worse than failing.
Adds: asynchronous authorization. The resource issues a challenge, a human approves it out-of-band, and the agent waits.
Wait for the human
The work crosses a company boundary
An agent inside your SaaS vendor's product needs a document in your company's storage. The storage API shouldn't have to learn a new token issuer for every vendor you buy.
Adds: identity chaining. A short-lived, audience-bound grant, so each domain keeps issuing its own tokens and the user's identity survives.
Cross the boundary
The request fans out inside your own walls
One agent call becomes eleven internal service calls. The outermost token stops at the edge, but everything downstream still needs to know who it's acting for and under what authorization.
Adds: transaction tokens. A per-request, internally-scoped credential carrying immutable call context through the fan-out.
Follow it inward
Before the first request
Something has to decide what to ask for.
A user says "chase up our overdue invoices." Between that sentence and an authorization request containing an amount and an account number, a decomposition happens. That's the agent's mission, and naming it lets you draw a line around it.
A mission arrives in natural language, broader than any single API call. Turning it into concrete access requests is a planning problem, not a protocol one, and no specification will tell you how.
Which is why the boundary matters. Mission decomposition is performed by the least trustworthy component in the system, the one reading untrusted invoices and web pages. Its output is a plan, a plan is a request, and a request is not an authorization.
Don't decompose the whole thing up front
A mission isn't fully knowable at the start, which is what makes it a mission rather than a script. The temptation is to ask for everything it might need, producing the broadest consent request at the moment the user understands least.
Ask late and ask narrowly. Per-resource authorization is cheap when discovery is a 401 and two well-known documents away.
Let the resource tell the agent what's askable
Decomposition doesn't have to be a guess. Protected resource metadata publishes the scopes that exist, and a server can publish which authorization details types it accepts, so the agent finds out what a legitimate request looks like instead of inferring it.
Planning becomes a negotiation with the resource rather than an educated guess, which is why RAR metadata and error remediation matters more for agents than anyone else.
The plan must not decide when a human is asked
If the agent's own decomposition determines which steps need approval, then whoever controls the agent's input does. That's the whole game, lost in one line of application logic.
The resource sets the bar and issues the challenge; the authorization server enforces it. The agent is a courier, not a judge. See rung 04.
Tie the whole mission together
One mission becomes many grants, tokens and calls across several services. If nothing connects them, your audit trail is a pile of unrelated authorizations and "what did this task do" is an afternoon of log archaeology.
A correlation identifier carried through every hop, which is what a transaction token's txn claim is for. See rung 06.
The honest part
Decomposition is out of scope for every specification here, and should be: it's application logic, different for every agent. Naming the mission on the wire isn't, and isn't solved. It's on the list below.
The other direction
Sometimes the agent is the one being called.
Every rung above puts the agent on the left of the arrow, asking for access. Flip it: another company's agent invokes yours. Now your agent is the protected resource, making the decisions the APIs above were making.
This needs nothing new. An agent that accepts calls is an OAuth resource server: it publishes protected resource metadata, validates audience-restricted tokens, checks proof of possession, and decides what the caller may ask for. There is one mistake that gets made almost every time.
Your agent receives an access token, needs to call three services, and the token is right there. Sending it onward hands every downstream service a credential minted for you, replayable against anything in that token's audience.
Exchange it instead: Token Exchange inside your own
domain, identity chaining for a different authorization
server, transaction tokens for the internal fan-out. The
act chain nests, so "this agent, for that agent, for this person" survives while each hop gets
a credential that only works there.
Agent-to-agent isn't a sixth rung. It's the ladder read in both directions: your agent climbing it as a client, standing at the top of it as a resource.
The parts bin
None of this is speculative.
Everything in the seven scenarios is a published RFC or an active IETF draft. These six do the most work; the full reference has the rest.
DPoP RFC 9449
Binds an access token to a key the client holds, so a copied token is worthless. That's what makes a token safe to hand to a runtime you don't fully control.
Protected Resource Metadata RFC 9728
Lets an API declare which authorization server protects it. The discovery step that makes "meet a server you've never seen" possible at all.
Client ID Metadata Document WG draft
A client's ID is an HTTPS URL serving its own metadata. No registration call, no portal, no shared secret, and the identifier means the same thing at every server that fetches it.
Rich Authorization Requests RFC 9396
Replaces a scope string with a structured description of the operation. The difference between "can send mail" and "send this message to these people."
Token Exchange RFC 8693
Trades one token for another, carrying an act claim that names the actor operating on the subject's behalf. Where "the agent, for the user" becomes something a token can say.
Transaction Tokens WG draft
A short-lived token scoped to one call chain inside a trust domain, carrying immutable context so every internal hop decides for itself without re-deriving who asked.
Not a sales pitch
What's actually missing.
A page claiming everything is solved is a page you shouldn't trust. Some things genuinely aren't standardized yet, and the size of the remaining gap is the whole question of whether this needs a new ecosystem or a few more drafts.
-
Naming the individual agent instance
A
client_idnames software, not the copy currently running. There's no standard way to put "this is instanceabc-123, spawned at 14:02, by this parent" into a token so a resource can act on it or revoke just that one. Naming instances is well-trodden ground outside OAuth; composing it with OAuth is the open work, and AI Agent Authentication and Authorization is where that's happening.Closest thing today: DPoP's key thumbprint as a de-facto instance handle, plus a private claim. Interoperable, no. Workable, yes.
-
How deep delegation is allowed to go
Token Exchange's
may_actsays who may act for whom. It can't express "this agent may sub-delegate once more and no further," or "this delegation dies with the parent task." Agents calling agents makes that live.Closest thing today: nested
actchains plus local policy at each authorization server. -
Showing a person what they're approving
Rich Authorization Requests express an operation exactly. Nothing standardizes how a server should render an unfamiliar authorization details type, or what to do with one it doesn't understand. Precision the user can't read isn't consent.
Closest thing today: the RAR metadata and error remediation draft, which is exactly this problem being worked on.
-
Revocation that actually propagates
"Kill this agent's access everywhere, now" spans an IdP, three authorization servers and a partner. The machinery exists: the Shared Signals Framework, with CAEP and RISC as its profiles. What's missing is deployment. Until subscribing is ordinary, access dies at the speed of the longest token lifetime in the chain.
Closest thing today: short token lifetimes and the refresh token expiration draft. Blunt, but it works.
-
Naming the mission on the wire
One objective becomes a dozen authorizations across several services. Nothing standard lets a token say "this was obtained in service of that mission," so you can't revoke a mission, audit one across companies, or ask a server to refuse anything outside one. The planning step is rightly out of scope; the identifier shouldn't be.
Closest thing today: a transaction token's
txnclaim inside one trust domain, and a shared request identifier by convention outside it. Works if everyone involved agreed in advance. -
Vouching for what an agent is, to a stranger
Inside a platform this works, and it has a name: posture assessment at the moment a credential is issued. The gap is portability. A client ID metadata document tells you what a client claims to be, and posture assessment only convinces the platform that did the assessing. Neither gives an API across the internet anything it can check.
Closest thing today: attestation-based client authentication and SPIFFE client authentication where the authorization server sits inside the same trust domain, plus reputation on the client ID URL itself.
A claim here, a metadata field there, a rendering convention. Draft-sized problems, landing in an ecosystem that already has authorization servers, libraries, audit pipelines and security review. Not that OAuth is perfect for agents, but that the distance from here to what agents need is short, and the distance from zero is not.
Start at the bottom.
The first rung is the one almost everybody is standing on: an agent with an API key in an environment variable. It's also the easiest to fix.