Rich authorization requests for AI agents

OAuth 2.0 Rich Authorization Requests (RAR), standardized in RFC 9396, add a parameter called `authorization_details` so a client can ask for fine-grained access in JSON instead of relying only on coarse `scope` strings.

For autonomous AI agents, coarse scopes are often the wrong abstraction. A scope like `payments` or `repo` may authorize far more than the single action the agent is about to take — pay €45.00 to Merchant A, or read one repository — and the owner cannot see that specificity at consent time.

This page explains what RAR is, how an `authorization_details` object is structured, how it travels through authorize, pushed authorization requests (PAR, RFC 9126), and the token response, how resource servers enforce it, how it relates to token exchange (RFC 8693) and spend approval gates, and what to verify before you depend on it in production.

Why coarse OAuth scopes are too broad for agents

RFC 6749's `scope` parameter was designed for relatively static capability labels: read a profile, access an API family, offline access. That works when a human application reuses the same granted scope for many similar requests.

An agent on a schedule or in a tool loop may issue hundreds of distinct operations. If every operation shares one broad scope, a stolen access token inherits the worst case: every repository, every payment rail, every mailbox — not merely the one task that was running when the token was minted.

RAR does not remove the need for least privilege at runtime. It makes the requested privilege legible at authorization time so the owner can approve exactly what the agent asked for, and so the authorization server can bind that structure to the access token the resource server later enforces.

What RFC 9396 defines

RFC 9396 (May 2023) introduces the `authorization_details` request parameter: a JSON array of objects, each describing authorization requirements for a resource type identified by a required `type` field. The authorization server controls interpretation of each `type` and the fields allowed on that object.

The array MAY contain multiple entries of the same `type`. The AS may refuse unknown types or malformed objects with the error `invalid_authorization_details` at the authorization or token endpoint.

`authorization_details` and `scope` MAY appear in the same request; the AS MUST process both and present the merged requirements at consent. RFC 9396 RECOMMENDS that a given API use one form of requirement specification, not both, when incremental migration is complete.

Common data fields in an authorization_details object

Section 2.2 of RFC 9396 defines reusable fields API designers can combine; allowable values depend on the `type`:

`type` (required)

String identifier for the authorization details type, unique in the context of that authorization server. Collision-resistant URIs under the API designer's control are RECOMMENDED for open standards.

`locations`

Array of strings, typically URIs, identifying where the resource or resource server lives — useful when one AS protects multiple RSs.

`actions`

Array of strings naming operations the client wants at the resource (for example `read`, `write`, `initiate`).

`datatypes`

Array of strings naming kinds of data being requested from the resource.

`identifier`

String naming a specific resource instance (account id, repo slug, patient record).

`privileges`

Array of strings for privilege levels at the resource; semantics are type-specific (one API's `admin` may subsume `read` and `write`; another may not).

Example: agent-scoped repository read (illustrative type)

RFC 9396's payment_initiation example is normative for the spec's structure; API-specific types are defined by each deployment. The object below shows how an agent might request read access to one repo using common fields — your AS must register and document the actual `type` value:

[
  {
    "type": "https://example.com/github_repo_access",
    "locations": ["https://api.github.com"],
    "identifier": "octocat/Hello-World",
    "actions": ["read"],
    "datatypes": ["contents", "metadata"]
  }
]

Example: payment initiation (from RFC 9396 Figure 2)

Open-banking-style payments are the spec's running example — amount, creditor, and actions bound to consent:

[
  {
    "type": "payment_initiation",
    "actions": ["initiate", "status", "cancel"],
    "locations": ["https://example.com/payments"],
    "instructedAmount": {
      "currency": "EUR",
      "amount": "123.50"
    },
    "creditorName": "Merchant A",
    "creditorAccount": {
      "iban": "DE02100100109307118603"
    },
    "remittanceInformationUnstructured": "Ref Number Merchant"
  }
]

Authorization request and pushed authorization requests (PAR)

RFC 9396 states that `authorization_details` can be used wherever `scope` is used for authorization requirements — including authorization requests per RFC 6749, device authorization (RFC 8628), and backchannel authentication (OpenID Connect CIBA).

For authorization requests per RFC 6749, the parameter is serialized JSON, URL-encoded in `application/x-www-form-urlencoded` form on the authorize URL (RFC 9396 Figure 8). Large payloads make long query strings; Section 11.4 RECOMMENDS pushed authorization requests (RFC 9126) so the client POSTs the request (including `authorization_details`) to the AS over HTTPS and receives a `request_uri` reference for the browser step.

Section 12 notes that `authorization_details` sent through the user agent can be tampered with. Clients concerned about integrity SHOULD use signed request objects (RFC 9101) or PAR with `request_uri` rather than putting the full JSON in the front-channel URL.

Token response and narrowing on refresh

When the resource owner approves the request, RFC 9396 requires the token response to include `authorization_details` as granted and assigned to the access token — in addition to the usual RFC 6749 fields. The AS MAY omit values when returning them to the client.

The client may also send `authorization_details` on the token request to ask for a token with a subset of a previous grant (RFC 9396 Section 6). Comparison of two authorization_details structures is type-specific; simple JSON equality is often wrong when fields interact.

The AS MAY enrich authorization details in the token response — for example adding account identifiers the user picked during consent that were placeholders in the original request (Section 7.1). Clients must know per `type` whether enrichment is possible.

How resource servers enforce authorization_details

Section 9 requires the AS to make approved authorization details available to the resource server. For JWT access tokens, the AS is RECOMMENDED to add a top-level `authorization_details` claim, filtered to the token audience. For introspection (RFC 7662), the same member MUST appear at the top level of the introspection JSON when the AS includes that information.

The RS must treat the token's authorization_details as the contract for the request: payment amount and payee, allowed repo, permitted actions. Enforcement belongs in the RS (or a policy engine in front of it), not in the agent's prompt.

If the RS only checks bearer presence and a coarse scope while the token carries richer authorization_details, you have not gained safety — you have only added documentation the API ignores.

Relation to OAuth token exchange (RFC 8693)

RFC 8693 token exchange is a separate mechanism: a client presents a subject token (or other credential) and asks the authorization server for a new token aimed at a different audience or resource. RAR does not replace token exchange; they solve different problems.

In brokered agent architectures, a common pattern is: the human consents once to fine-grained `authorization_details`; the broker stores the grant; downstream services receive tokens (sometimes via RFC 8693) whose `authorization_details` or derived claims must not exceed what was approved. Your AS must define whether exchanged tokens copy, narrow, or drop authorization_details — RFC 9396 does not standardize that mapping.

Grant-level behavior at the token endpoint (authorization code, refresh, client credentials) is covered in agent OAuth token exchange on this site. RAR sits earlier: what the owner approves before any code or refresh is issued.

Spend approval gates and RAR-shaped intent

Product-level spend gates — approve this charge, cap daily ad spend, block payouts above a threshold — are not OAuth parameters. They are application policy. RAR can still align with them when a payment or transfer authorization_details object states amount and payee explicitly, so consent UI and API enforcement read the same facts.

Runtime budget enforcement before tool calls complements OAuth: a token may authorize payments in principle while your operator still refuses a call that exceeds today's cap. See budget-gating an autonomous agent for that layer.

Limits and deployment realities

Provider support

RAR requires AS, client, and RS coordination per authorization details type. Many identity providers still expose only scope strings; verify `authorization_details_types_supported` in OAuth AS metadata (RFC 9396 Section 10) before designing around RAR.

Consent UX

Humans must understand structured objects at approve time. Complex JSON needs deliberate presentation — not a dump of raw fields. Section 11.1 lists deployment steps including how details are shown and optionally enriched during consent.

Token and URL size

Large `authorization_details` inflate authorize URLs, PAR bodies, JWTs, and introspection payloads. Section 11.4 explicitly warns about very long request URIs and points to PAR.

Type-specific semantics

Subsumption rules (`write` implying `read`, `admin` implying all actions) are defined per `type`, not by RFC 9396 globally. Agents must not guess; the RS and AS must implement the same rules.

Subset grants

The resource owner may approve less than the client requested. Agents should handle partial authorization_details in the token response without assuming the full request was granted.

Checklist: RAR for an agent integration

Use when scoping a new agent that acts on user resources:

Register or document types

Define each `type` string, required fields, and validation rules; publish `authorization_details_types_supported` if you operate the AS.

Bind each tool call

Map agent tools to concrete authorization_details objects so a run requests the minimum structure for that call, not a standing super-scope.

Prefer PAR for rich requests

When details include amounts, account ids, or repo paths, POST via RFC 9126 instead of megabyte authorize URLs.

Enforce at the RS

Reject API calls when action, location, identifier, or amount does not match the token's authorization_details (JWT claim or introspection).

Plan refresh narrowing

If the agent renews tokens, specify whether refresh may widen authorization_details or only narrow them.

Handle invalid_authorization_details

Surface AS errors to the owner; do not retry the same malformed object in a loop.

Keep broker secrets off the agent

The model runtime should not hold refresh tokens or PAR client secrets; same discipline as ordinary OAuth for agents.

How this relates to other OAuth-for-agents writing

For a buyer checklist on OAuth providers and required behaviors, read OAuth for AI agents. For the secure build sequence (consent, broker, rotation), read let an AI agent authenticate with third-party APIs securely. For why unattended software needs identity at all, read OAuth for autonomous software.

Empyre Relay and RAR

A repository search on 2026-10-09 found no `authorization_details` handling in Empyre Relay's OAuth implementation (`backend/api/routes/relay_oauth.py`) or in `@empyre/relay-sdk` (`packages/relay-sdk/src/index.ts`), which exposes `scopes` on authorize and token calls only. This article describes the IETF standard; it does not claim Empyre Relay supports RAR today.

Empyre Relay (relay.empyre.dev) remains OAuth for agents with hosted consent, PKCE, scoped tokens, refresh rotation, and introspection — feature-frozen as documented in the Relay SDK release. Fine-grained RAR would require new authorization details types, consent UI, token claims, and RS enforcement beyond scope strings.

Empyre on empyre.dev builds and runs a software company after launch — product, marketing, support, and operations — rather than selling a general-purpose RAR authorization server. Founders who need RAR will implement or buy it at the APIs their agents call; Relay addresses a different layer of the stack unless and until RAR is added explicitly.

Common questions

Is RAR the same as OAuth scopes?

No. Scopes are space-separated capability labels. RAR adds structured JSON objects per resource type. They can coexist in one request during migration, but RFC 9396 recommends one primary mechanism per API.

Where does authorization_details appear?

Per RFC 9396 IANA registration: authorization request, token request, token response, JWT access tokens (recommended top-level claim), and token introspection responses.

What error code applies to bad details?

`invalid_authorization_details` at the authorization or token endpoint when the type is unknown or fields are wrong.

Must the user approve exactly what the client asked?

No. The user may grant a subset. The token response carries what was actually approved.

Does RFC 9396 define payment_initiation for everyone?

It uses payment_initiation as an example. Real deployments define their own `type` values and publish them in AS metadata.

Does Empyre Relay support RAR?

Not as of 2026-10-09 per codebase review above. Relay uses OAuth scope strings only.

What was verified on 2026-10-09?

RFC 9396 text at rfc-editor.org/rfc/rfc9396.html (structure, PAR reference to RFC 9126, token response, RS Sections 9–10, error `invalid_authorization_details`). Empyre Relay source paths cited in this page. No third-party IdP support matrix or search rankings appear here.

Try Empyre free for 3 days

Describe a business in plain words and watch eight AI agents build and deploy it. Starter is free for the first 3 days.

Start your free trial

Related

Last updated 2026-10-09. Competitor descriptions reflect each product's publicly documented capabilities at that date; they change often, so check the source before relying on a detail.