← agents
8 min read~2.6k tokens

The Agent Authorization Standard We Already Had

Using OAuth Token Exchange (RFC 8693) and actor claims to control and audit agent delegation.

Agents may be a new thing, but the way they authenticate with each other and with external services does not have to be.

This year has been all about agents, as I am sure you are aware. They are everywhere, and we are trying to use them for everything, from Outlook schedulers to incident response. As we go down this road, the conversation about tightening our controls on them becomes even more relevant. It seems every week we get another announcement about how AI will take over the world tomorrow. Predictably, this day has not yet come, and I am skeptical it ever will. But regardless, it might make sense to scope down what agents can do.

So, as agents change the way we work, the permissions we give them have to change too. The evolution is already familiar. First came the local agent with shell access and a bunch of API keys. God-level permissions on your laptop. Rudimentary, but extremely effective, which probably explains why I still see it more often than anybody would like to admit. ;)

The next step is isolation. Dump the agent in a container. Restrict the network. Give it a narrowly scoped GitHub token. Let one container pull the repository, persist only the required files, and let a second container with a headless coding harness go wild inside a smaller box. Again: rudimentary, but effective.

Eventually you arrive at OAuth 2.0, a convention that is as old as time by AI standards. This is normally where people start drawing complicated architecture diagrams and inventing new vocabulary. What these "experts" seem to miss is that a lot of the authorization model we need already exists.

For the sake of this article, let's define a case most of us high-minded tech people will understand. Meet Nadia. She uses a personal assistant agent to coordinate her development work. It can read requests from a chat Model Context Protocol (MCP) server (Slack) and delegate coding tasks to a coding agent (headless Claude). That coding agent can eventually call a deployment MCP server to get our beautiful code into the only real testing environment: PRODUCTION.

It Starts With 401 Unauthorized

Need a JWT refresher? A JWT Is Not Authorization covers the claims and signatures used below. Otherwise, the 401 awaits.

Nadia asks her personal assistant to handle a development request that arrived in Slack. Before it can decide what work to delegate, the assistant needs to read the conversation through the chat MCP server.

The assistant calls the endpoint without a usable token and receives this pretty rude response:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://chat.example.com/.well-known/oauth-protected-resource"

It is not the server saying, "I will never love you, please stop texting me." It is saying: you need a token, and here is where you can go to try and get one.

RFC 9728 defines this protected-resource metadata pattern. Bear with me here. The client fetches the metadata, confirms that the returned resource exactly matches the resource it tried to access, discovers an authorization server it is willing to trust, completes the appropriate OAuth flow, and retries with a token created for that resource.1

There is one important caveat: a 401 response does not magically create trust. An agent cannot blindly follow any authorization-server URL placed in a response. It still validates Transport Layer Security (TLS), resource metadata, issuer metadata, and its local trust policy. Discovery tells the client where to look. It does not tell the client who to believe. The client has to decide that for itself.

The endpoint now accepts a token, but that token has to say more than "Nadia is allowed."

Three Identities Are Hiding in the Request

The authorization model becomes easier to reason about if we stop saying "the agent's token" and ask three separate questions:

Subject:  Who owns the authority?
Actor:    Who is currently exercising that authority?
Audience: Where may that authority be used?

The personal assistant can act as itself:

{
  "sub": "personal-assistant",
  "aud": "chat-mcp",
  "scope": "messages.read"
}

That is fine when the work genuinely belongs to the machine. A bot posting its own health status does not need to pretend a human clicked the button.

The assistant can instead impersonate Nadia:

{
  "sub": "nadia",
  "aud": "chat-mcp",
  "scope": "messages.read"
}

This can still be tightly scoped. Impersonation does not automatically mean every permission Nadia has. The problem is that the chat MCP server sees Nadia and only Nadia. It cannot tell whether Nadia read the thread directly, whether her assistant did it, or whether somebody copied the token into a curl command at 02:00.

Or the assistant can act for Nadia through explicit delegation:

{
  "sub": "nadia",
  "act": {
    "sub": "personal-assistant"
  },
  "aud": "chat-mcp",
  "scope": "messages.read"
}

Now the token says two things at once: Nadia owns the authority, and the personal assistant is exercising it. The resource can preserve Nadia as the subject while applying different policy to the agent acting for her.

For delegation to work, the assistant needs its own identity and a way to prove it, the same way a human would. A client_id identifies a client registration, but it does not authenticate the agent by itself. The agent still needs a credential or another authentication mechanism before an authorization server can trustfully name it as an actor.

Exchange Authority Instead of Forwarding Tokens

Now, how do we get these delegated tokens we mentioned earlier? How does the agent get a token that retains Nadia as the subject but exists exclusively for the agent and what it is supposed to do? The answer has existed for a while.

RFC 8693 defines OAuth 2.0 Token Exchange, an HTTP and JSON protocol for asking an authorization server to validate one security context and issue a new token for another.2

The subject_token represents Nadia, whose authority is being exercised. The personal assistant authenticates as itself and can provide an explicit actor_token. The requested resource or audience says where the new token will be used, and scope says what it should permit there.

The authorization server validates Nadia's token, authenticates the assistant, and applies policy. Is this assistant allowed to act for Nadia? Is it allowed to access this resource? Is the requested scope appropriate? Only then does the authorization server mint a new token for the next boundary. Think of it like a power of attorney for humans. Your bank does a whole lot of stuff to make sure your cousin is actually your cousin when you want him to buy a house for you.

The agent does not crack open Nadia's token, change the audience, add itself as an actor, and sign it again. If an agent can mint its own trusted delegation evidence, you do not have delegation. As I said earlier, the agents are probably not going to take over, but this would be an unusually considerate way to help them if they were going to.

Assuming the authorization server is configured to issue a composite JSON Web Token (JWT) for delegation, the result can preserve Nadia as sub, identify the assistant in act, pin the token to the chat MCP server with aud, restrict it to messages.read, and give it a short lifetime with exp.

One audience. Bounded capability. Short lifetime. If that token leaks, another service checking aud should reject it, and it will be dead soon anyway.

This is usually where someone asks about the latency of all this exchanging. But a token exchange does not have to happen for every API call. If the assistant already holds a suitable, unexpired token for the same audience, it can reuse it while policy permits. The important boundary is a change in audience or authorization context. A chat token should not wander into the deployment MCP server just because both systems accept OAuth.

The Audit Record Finally Stops Lying

Without explicit delegation, the production deployment record might look like this:

principal=nadia
action=deploy_release

Technically true, in the sense that Nadia's authority was used. Operationally it is a flat-out lie, because Nadia did not perform the deployment.

With explicit delegation, the deployment system can record something closer to the truth:

principal=nadia
current_actor=coding-agent
previous_actor=personal-assistant
audience=deployment-mcp
scope=deploy.production
action=deploy_release

This is where agent identity becomes useful rather than decorative. The resource can distinguish Nadia acting directly from a coding agent acting for Nadia. It can apply different controls to different agents, block one actor without pretending Nadia herself is compromised, and reconstruct the path during the inevitable production incident.

Delegation separates ownership of authority from responsibility for exercising it. That sentence is a bit dry, but it is the entire point.

What This Standard Does Not Solve

RFC 8693 gives us delegation semantics, not a complete agent security architecture. It does not define how unrelated agent domains establish federation, a universal agent identifier, maximum delegation depth, user approval experiences, agent reputation, or a global mechanism that immediately revokes one agent's authority everywhere.

We still have to design the trust model and policy. In practice that means short-lived and audience-specific tokens, independently authenticated actors, local limits on delegation depth, complete audit records, and sender-constrained tokens when theft presents a material risk.

But compare this with where we started. A chat MCP server returned a 401 because Nadia's assistant needed a token. By the time an action reaches production, the deployment system can answer five useful questions:

Who owns the authority?       Nadia
Who is exercising it?         Coding Agent
Who acted previously?         Personal Assistant
Where can it be used?         Deployment MCP
What can it do?               deploy.production

AI agents may be new to the party, but delegation is not a new security problem. RFC 8693 already gives us a vocabulary for the subject, the actor, the permitted delegate, and the target. RFC 9728 gives an unfamiliar client a standard way to begin the authorization conversation. Agent-to-Agent (A2A) communication can carry the task, while OAuth carries bounded authority and MCP exposes capabilities behind explicit authorization boundaries.

The challenge is not inventing another token format. It is applying the authorization machinery we already have with discipline.

The feeling I get more and more these days is that the conversations we are having around agents feel increasingly familiar: boundaries, domains, responsibilities, and accountability. The safest agent systems may not be built on novel authorization technology, but on old authorization technology used precisely.

Optional Detours

This article stands on its own. The three below are detours, not homework. Pick whichever covers the part you want to poke at:

References

Footnotes

  1. RFC 9728: OAuth 2.0 Protected Resource Metadata ↩

  2. RFC 8693: OAuth 2.0 Token Exchange ↩