
AUTHORIZATION
Agent Authorization Explained
Authorization is several checks in sequence, not one. The intersection rule, where OAuth scopes stop being enough, how RFC 8693 carries two identities, and the failures that look identical.
TL;DR
Authorization is not one decision. It's several, checked in sequence, and most agent incidents trace back to only one of them ever being checked. A team wires up a login, confirms the agent is who it says it is, and calls that "authorized", but identity only answers who is acting, not what they're allowed to do.
The standards already assume the gap. OAuth 2.1 says plainly that "access tokens are intended to be issued to clients with less privileges than the user granting the access has." AWS builds the same idea into IAM, where a session's permissions are "the intersection of the identity-based policies for the IAM entity" and the session policy.
The common shortcut treats authentication as a stand-in for authorization: verify the agent, assume the rest is fine. A perfectly identified agent with no limit on its reach is exactly as dangerous as an anonymous one, because identity tells you who broke something, not whether they were allowed to.
None of this means locking agents down until they're useless. The opposite failure is just as common and harder to notice: an agent that quietly inherits everything the person it serves can do, looking fine right up until the day it uses that inherited reach.
What holds up is layered. A request clears identity, then who it's acting for, then which tool, then which action, then which data, before it runs at all. Design the layers before you design the login screen.
Overview
An agent that only answers questions is limited by what it can say. An agent that can act, retrieving records, calling tools, updating systems, sending messages, is limited by what it's allowed to do, and that limit is what authorization defines.
Most teams building their first agent get identity right and stop there. The agent has a service account, it authenticates cleanly, the logs show which agent connected to which system. That feels like the hard part is done. We don't think it is: knowing precisely which agent reached the data warehouse doesn't help if it was free to export every table once it got there.
Which specific permissions an agent should hold is a policy question, covered in agent permissions best practices. This post is about mechanism.
A system that can only say who acted, and not how far they were allowed to reach, is only half built.
Two Questions, Not One
Authentication and authorization get treated as one step because they usually happen in the same login flow. They aren't the same question, and they don't fail the same way.
Authentication answers who or what is this agent. Authorization answers what is this agent allowed to do. A system can nail the first and skip the second, and from the outside it looks fine right up until the agent does something nobody meant to allow.
OAuth's own vocabulary keeps them apart. RFC 6749 defines a resource owner as "an entity capable of granting access to a protected resource" and a client as "an application making protected resource requests on behalf of the resource owner and with its authorization." The agent is the client in that picture, never the owner, and the grant is the thing that has to be bounded.
Why It's Hard for Agents
Authorization for people is a settled discipline: roles, groups, access reviews. Agents complicate it because they sit between a person and a system, acting continuously, at machine speed, on someone else's behalf.
The trap is inheritance. An agent acting for a user is not the user, and shouldn't quietly absorb everything that user is allowed to do. A finance analyst can post journal entries; their reconciliation agent might read balances and propose an adjustment, never post one. A data engineer can query production directly; their analytics agent gets a read replica with sensitive fields stripped out. In both cases the human has more authority than the agent working in their name, on purpose.
That asymmetry is what OAuth was built for. The OAuth 2.1 draft states it outright: "Access tokens are intended to be issued to clients with less privileges than the user granting the access has." An agent handed the user's full authority has thrown away the one property the token was supposed to have.
NIST SP 800-207, published August 2020, makes the same point from the network side. Its third zero-trust tenet grants access "on a per-session basis" and adds that "authentication and authorization to one resource will not automatically grant access to a different resource." An agent that chains four tools together is four sessions, not one.
The Intersection Rule
An action is allowed only when the user and the agent are separately permitted to take it. Not one or the other. Both. The taxonomy calls this aact:authorization-model/intersection-of-agent-and-user.
allow(action) = permitted_for(user) AND permitted_for(agent)
# Procurement example
user (buyer): can create POs, can approve POs up to $250k
agent: can create POs, cannot approve any PO
create_po($40k) -> user: yes, agent: yes -> ALLOWED
approve_po($40k) -> user: yes, agent: no -> BLOCKED, needs a personThis is not a novel idea, and that is the best argument for it. AWS IAM has shipped it for years under two names. Session policies, passed when a role is assumed, produce a session whose permissions are "the intersection of the identity-based policies for the IAM entity (user or role) used to create the session and the session policies," and the docs add that they "limit permissions for a created session, but do not grant permissions." A permissions boundary does the same thing structurally: with one attached, "the entity can perform only the actions that are allowed by both its identity-based policies and its permissions boundaries." Read the agent as the session and the user as the entity, and the mapping is exact.
Two properties come with the pattern. It fails closed: a marketer may personally hold publish rights, but if their campaign agent's own grant stops at drafting, the campaign waits for a person regardless. And denial wins over grant. AWS is explicit that "an explicit deny in any of these policies overrides the allow," and Google Cloud puts the ordering in the evaluation path: "IAM always checks relevant deny policies before checking relevant allow policies."
An intersection you cannot state as code is not an intersection. If the agent's ceiling lives in a prompt, a config comment, or somebody's memory of the design review, the effective permission set is whatever the user has.
The Layers
A single allow-or-deny flag is too coarse for something that chains tools together. A request clears several checks, each narrower than the last.
Figure 1 — A request has to clear every layer before it runs. One denial anywhere in the chain stops it.
In order: agent identity confirms this is a recognized agent rather than a borrowed credential. User context establishes who it's acting for right now, since the same agent serving a junior rep and a team lead may resolve to different limits. Tool access decides which systems it can reach at all. Action permissions narrow that further: reaching the ticketing system is not the same as being allowed to close, reassign or delete a ticket in it. Data boundaries scope which records it can see. Conditions restrict a permission to a time window, a transaction size, an active incident.
We think the layer people skip most often is conditions, because it requires thinking about when a permission should hold rather than what it covers. NIST's fourth zero-trust tenet is exactly this: "access to resources is determined by dynamic policy," with inputs including client identity, the requesting asset's state, and behavioural attributes. A grant that ignores time, volume and context will eventually be used at a moment nobody would have approved.
Where Scopes Run Out
OAuth scope is the layer most teams reach for, and it carries less than people assume. On its own it is aact:authorization-model/scope-at-grant: fixed when the credential is issued, never rechecked per action. RFC 6749 section 3.3 leaves it loose: "the authorization server MAY fully or partially ignore the scope requested by the client," and when the granted scope differs from the request the server "MUST include the 'scope' response parameter to inform the client of the actual scope granted." The client does not get what it asked for. It gets what it was given, and it has to read the response to find out which.
The deeper limit is expressiveness. RFC 9396, Rich Authorization Requests, published in May 2023, opens by saying the scope parameter "is not sufficient to specify fine-grained authorization requirements, such as 'please let me transfer an amount of 45 Euros to Merchant A' or 'please give me read access to directory A and write access to file X.'" That is the agent problem stated four years early. mail.send is a scope. "May send to addresses inside the company, up to twenty recipients, excluding the all-staff list" is not, and no amount of naming discipline turns one into the other.
RAR's answer is a structured authorization_details array, where each entry carries a type plus fields the RFC defines for reuse: actions, "the kinds of actions to be taken at the resource"; locations, "typically URIs identifying the location of the RS"; and datatypes, "the kinds of data being requested from the resource."
{
"authorization_details": [
{
"type": "ticketing_api",
"actions": ["read", "comment", "close"],
"locations": ["https://tickets.example.com/queues/tier1"],
"datatypes": ["ticket", "attachment"]
}
]
}Whether you adopt RAR or model the same shape in your own gateway matters less than accepting it: an agent permission is a verb plus a place plus a data class, and one flat string cannot hold three.
Carrying Two Identities
If both parties have to be checked, both have to arrive at the check. RFC 8693, OAuth 2.0 Token Exchange, gives that a wire format, and its most useful contribution is a distinction people blur constantly.
Under impersonation, "principal A is given all the rights that B has within some defined rights context and is indistinguishable from B in that context." Under delegation, "principal A still has its own identity separate from B, and it is explicitly understood that while B may have delegated some of its rights to A, any actions taken are being taken by A representing B." An agent running as the user is impersonation, and it destroys the intersection rule by construction. No second identity is left to check. The other shape is aact:delegation-model/on-behalf-of-user.
Section 4.1 describes the act claim as a way "to express that delegation has occurred and identify the acting party to whom authority has been delegated," with nested claims recording a chain and the outermost one representing the current actor. Section 4.4 adds may_act, which "makes a statement that one party is authorized to become the actor and act on behalf of another party."
{
"iss": "https://idp.example.com",
"sub": "user:a.chen",
"aud": "https://tickets.example.com",
"scope": "tickets:read tickets:close",
"act": { "sub": "agent:tier1-triage" }
}Gateway Gateway intersects user scopes with agent scopes Gateway checks conditions and data boundary Gateway --audience-bound request--> Ticketing API API may answer 403 insufficient_scope Gateway returns the result, or a denial with a reason, to the agent The agent never holds a credential and never sees a token it could reuse elsewhere. -->
Figure 2 — Two identities on one request. The agent's own grant is what makes the gateway's check meaningful.
The Model Context Protocol specification, revision 2026-07-28, closes the matching hole on the server side. An MCP server acts as an OAuth 2.1 resource server and "MUST validate that access tokens were issued specifically for them as the intended audience," and servers "MUST NOT accept or transit any other tokens." That is the confused-deputy defence: without it, a token minted for one tool can be replayed against another by anything that can reach both.
The same spec is worth copying for its denial semantics. A server short of permission answers 403 with error="insufficient_scope" and a scope parameter naming the minimum scopes needed, and it "SHOULD include all scopes required for the current operation in a single challenge" rather than dribbling them out one retry at a time. A denial that names what was missing is the difference between a client that can recover and one that loops.
Choosing a Model
Underneath the layers sits a modelling choice. The three candidates fail in different places.
| Model | Decides on | Good at | Where it breaks for agents |
|---|---|---|---|
| RBAC | A role assigned to the principal | Coarse tool access, easy to review | Conditions and per-record scope. NIST's ABAC guide notes that ad hoc, thinly populated roles lead to "role explosion" |
| ABAC | Attributes of subject, object, environment | Time windows, amount limits, data class, region | Attributes must be populated and fresh; a stale one is a silent grant |
| ReBAC | A relationship graph | "May act on tickets in queues its user owns", per-object checks | Graph freshness, and a check on every object in a list |
Table 1 — Three authorization models against the agent workload. Most production systems end up with RBAC for tool access and one of the other two for records.
NIST SP 800-162, published January 2014, defines ABAC as access "granted or denied based on assigned attributes of the subject, assigned attributes of the object, environment conditions, and a set of policies that are specified in terms of those attributes and conditions." That is the vocabulary the conditions layer needs, and it is why we think most teams land on a hybrid.
Before writing any of it yourself, price the alternative. Cedar, OpenFGA and Open Policy Agent are mature, permissively licensed, and have already solved decision caching, evaluation ordering and a test harness for rules. Build in-house only the agent-specific piece, the intersection and the two identities, because none of them models that for you.
How It Fails
These look alike from a distance and have opposite fixes.
| Failure | What you see | How to tell it apart |
|---|---|---|
| Inherited authority | Agent succeeds at something nobody granted it, with no denial in the logs | The call carries one identity, the user's. The agent's own grant was never evaluated |
| Confused deputy | Agent reaches a system it was never connected to | A token minted for tool A accepted by tool B. Audience validation is missing, or the gateway forwards tokens verbatim |
| Scope creep | Permission list grows monotonically, nothing removed | Compare granted scopes against scopes exercised in the last 30 days. The gap is the blast radius |
| Stale attribute | A condition that should deny keeps allowing | The attribute has not updated since a reorg. ABAC's characteristic failure |
| Coarse denial | Agent retries forever, or gives up entirely | A 401 or a bare 403 with no scope hint. Nothing told the caller what was missing |
| Ignored partial grant | Agent acts as though it holds scopes it was refused | Nobody read the scope in the token response. RFC 6749 lets a server grant less than was asked |
Table 2 — Six authorization failures, and the signal that separates each from its neighbours.
Two of those rows are worth instrumenting rather than investigating. Log the identity count on every call: a request carrying one identity where two were expected is the inherited-authority failure before it becomes an incident. And log granted-but-unused scope per agent per month, because that number only moves in one direction unless somebody looks at it.
Least Privilege Is the Default
Give an agent only the minimum it needs, nothing held "just in case." Broad access is a quiet temptation during development, because full admin removes friction while you iterate. An over-permissioned agent doesn't just have capability sitting unused; it has a wider blast radius the moment a prompt gets manipulated or the model reasons its way into something nobody intended.
The MCP authorization spec builds the incremental version into its flow: clients "SHOULD follow the principle of least privilege by requesting only the scopes necessary for their intended operations," with scopes_supported representing "the minimal set of scopes necessary for basic functionality" and anything further requested through step-up authorization when an operation needs it. That beats requesting everything at install time in case it comes up.
Authorization Without a Record Is Half a Control
Knowing what an agent was allowed to do is half of it. You also need to know what it did, and whether the two matched.
Every decision the authorization layer makes belongs in the record next to the action: what was requested, which permission applied, whether it was allowed or blocked, and which identity each half of the intersection resolved to. NIST's zero-trust model separates the component that decides from the component that carries the decision out, and notes that the deciding one "makes and logs the decision (as approved, or denied)." The log is part of the control, not a report about it.
Without that link, authorization is a claim about how the system is supposed to work. With it, you can answer the question that comes up in an incident: what was allowed, and did anything happen outside the lines. OWASP's Agentic AI: Threats and Mitigations, published 17 February 2025 as the first guide from its Agentic Security Initiative, is a reasonable starting point on the threats this record has to reconstruct. Log design is covered in audit logging best practices.
Where Fabriq Fits
Agentic Fabriq implements the intersection rule as a default rather than a configuration option. An agent's effective tool list is the intersection of the user's scopes and the agent's own, permissions are default-deny across org, team and member with per-user overrides, and action-level permissions are enforced in the backend rather than advertised in a tool description. Every call carries two identities into an audit record. Credentials sit in a vault and are attached server-side at the moment of the call, so the agent never handles the secret and has nothing to replay elsewhere.
What it does not do is reach into the provider for you. Clearing a vault copy is not the same act as invalidating a grant upstream, so revoking at the identity provider or the SaaS application is still yours to do.
Frequently Asked Questions
What is agent authorization? The set of checks that decide whether a specific action an agent is attempting, right now, on behalf of a specific person, is permitted. It is distinct from authentication, which only establishes which agent is calling.
What is the difference between agent authentication and authorization? Authentication answers who is acting. Authorization answers what they may do. A system with perfect authentication and no authorization can tell you exactly which agent exported the customer table and nothing about whether it should have been able to.
Should an AI agent have the same permissions as the user it serves? No, and OAuth assumed as much from the start. The OAuth 2.1 draft says access tokens "are intended to be issued to clients with less privileges than the user granting the access has." An agent is faster, less context-aware and unattended, so its grant should be a subset of the user's.
Is OAuth scope enough to authorize an agent? Rarely. RFC 9396 states that scope "is not sufficient to specify fine-grained authorization requirements", and gives per-amount and per-directory examples. Scope handles which tool. Verb, record and condition need structure underneath it.
RBAC or ABAC for agents? Both, usually. Roles are the cheapest way to answer which tools an agent may reach. Attributes are the only practical way to answer time, amount, region and data class. NIST's ABAC guide warns that pushing the second kind of question into roles produces "role explosion."
Where should the authorization check run? Server-side, at a point the agent cannot bypass, and on every call. A check inside the agent's own prompt or client code is a suggestion, not a control.
The Boundary That Makes Autonomy Usable
Good authorization makes agents safer and easier to scale at once. It gives builders a line to work within and gives security teams a real answer, not a hope, for whether an agent can act outside its limits.
Three things carry most of the weight. State the intersection in code, so a user's authority cannot leak into the agent. Give a permission enough structure to name a verb, a place and a data class. And make every denial say what was missing, so narrowing a grant is a decision rather than an outage.
Authorization is the line between useful automation and autonomy nobody actually decided to grant. Skip it and the question isn't whether an agent oversteps. It's when.
Sources
All URLs read 2026-09-29.
- RFC 6749: The OAuth 2.0 Authorization Framework — section 1.1 on resource owner and client roles, section 3.3 on scope and partially granted scope.
- The OAuth 2.1 Authorization Framework, draft-ietf-oauth-v2-1-13 — access tokens issued with fewer privileges than the granting user, and refresh tokens bound to consented scope.
- RFC 8693: OAuth 2.0 Token Exchange — section 1.1 on delegation versus impersonation, section 4.1 on the
actclaim, section 4.4 onmay_act. - RFC 9396: OAuth 2.0 Rich Authorization Requests — why scope is insufficient for fine-grained authorization, and the
actions,locationsanddatatypesfields. - Model Context Protocol, Authorization, revision 2026-07-28 — MCP servers as OAuth 2.1 resource servers, audience validation, the prohibition on transiting other tokens, and
insufficient_scopechallenges. - Policies and permissions in AWS IAM — session policies as an intersection, permissions boundaries as a ceiling, and explicit deny overriding allow.
- Deny policies, Google Cloud IAM — deny policies evaluated before allow policies, and the effect of a matching deny rule.
- NIST SP 800-207: Zero Trust Architecture — August 2020; tenets 3, 4 and 6 on per-session access, dynamic policy inputs, and the separation of the deciding component from the enforcing one.
- NIST SP 800-162: Guide to Attribute Based Access Control — January 2014; the ABAC definition and the "role explosion" problem in RBAC.
- Agent Access Control Taxonomy — the authorization model and delegation model dimensions;
intersection-of-agent-and-userfor the rule above,scope-at-grantfor what a bare scope gives you,on-behalf-of-userfor the two-identity case. - OWASP Agentic AI: Threats and Mitigations — 17 February 2025, the first guide from the OWASP Agentic Security Initiative. </content>