Rich Authorization Requests (RAR) in the AuthPlayground
Constraining what AI is allowed to do.
Sarah asks the company’s AI assistant to prepare her for a meeting with Apex Logistics. She has broad access across customer systems and can read opportunities, update records, access multiple accounts, and perform other actions required by her role.
The AI assistant’s task is much narrower and requires only a specific set of information. What the AI assistant needs to do isn’t the same as what Sarah can do. RAR (RFC 9396) provides a way for an OAuth client to describe a specific operation it wants to perform.
The RAR model
OAuth scopes are useful for describing general capabilities. An application can request something such as customer.read. Some authorization decisions need more context, such as:
Action: Read Customer: Apex Logistics Data: Relevant account context
RAR adds the authorization_details parameter to OAuth, allowing clients to describe authorization requirements in a structured, machine-readable form. Authorization details can include type, actions, resource information, and other constraints. These details provide more precise information than a flat scope string alone.
Authorization details structure
An authorization detail is a structured JSON object. Its fields depend on the type of authorization requested. An enterprise AI API example might look like this:
{
"type": "customer_information",
"actions": ["read"],
"identifier": "apex-logistics"
}
RAR gives the API a structured way to describe what is being requested. Instead of asking only for customer.read, the request describes which customer, which action, and any other constraints that matter to policy.
The AuthPlayground implementation
Entities involved: Client application, IdP (authorization server), resource server
The AuthPlayground demonstrates the Rich Authorization Requests flow in three steps:
-
Send the authorization request with
authorization_details. -
Exchange the authorization code.
-
Enforce authorization at the resource server.
The playground uses a payment initiation example that makes fine-grained authorization easy to see.
Step 1: Send authorization details
The client begins an OAuth authorization request. Alongside the usual OAuth and Proof Key for Code Exchange (PKCE) parameters, it sends authorization_details. The request looks like this:
GET /idp/authorize
response_type=code
client_id=playground-demo-client
scope=openid
code_challenge=<pkce_challenge>
code_challenge_method=S256
authorization_details=<structured_json>
The decoded authorization details include the specific operation requested:
[
{
"type": "payment_initiation",
"instructedAmount": {
"amount": "123.50",
"currency": "USD"
},
"creditorName": "Merchant Inc",
"creditorAccount": {
"iban": "DE75512108001245126199"
}
}
]
Compared with a broader permission such as payment, the structured request tells the authorization system much more. This is the value of RAR. The authorization request describes the specific operation that needs authorization.
The user can authorize a specific operation
Because authorization details are structured, the authorization server can evaluate the exact operation requested. Instead of just asking if the application is allowed to make payments, the request asks if the application can make a $123.50 USD payment to Merchant Inc at a specific destination account. This is a more meaningful authorization decision. The user authorizes a particular operation rather than granting an abstract capability with little context.
Step 2: Exchange the authorization code
The client exchanges the authorization code using the standard Authorization Code flow with PKCE. The playground request is:
POST /idp/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
code=<authorization_code>
redirect_uri=<callback>
client_id=playground-demo-client
code_verifier=<code_verifier>
The response contains an access token. The decoded token contains:
{
"sub": "demo-user@example.com",
"scope": "openid",
"client_id": "playground-demo-client",
"authorization_details": [
{
"type": "payment_initiation",
"instructedAmount": {
"amount": "123.50",
"currency": "USD"
},
"creditorName": "Merchant Inc",
"creditorAccount": {
"iban": "DE75512108001245126199"
}
}
]
}
Notice that the scope is openid, but the token also carries the richer authorization context. This level of detail can’t be expressed with a flat scope string.
Step 3: Enforce authorization at the resource server
The client calls the protected resource using the access token:
GET /rs/resource
Authorization: Bearer <access_token>
The resource server validates the token and the authorization information associated with it. The response shows that the same structured authorization context is available at the protected resource:
{
"message": "Access granted to protected resource",
"user": "demo-user@example.com",
"authorization_details": [
{
"type": "payment_initiation",
"instructedAmount": {
"amount": "123.50",
"currency": "USD"
},
"creditorName": "Merchant Inc",
"creditorAccount": {
"iban": "DE75512108001245126199"
}
}
]
}
The resource server isn’t working from a generic statement that the user can make payments. It has structured context describing the authorized operation. This gives downstream policy something more precise to enforce.
How RAR relates to other concepts
Giving policy better information
Fine-grained authorization becomes essential when AI can take actions rather than simply retrieve information. Consider three requests against the same Apex Logistics account:
-
Reading the opportunity is low risk
-
Updating the forecast is higher risk
-
Deleting the opportunity is high risk
These operations require different policy decisions. Structured authorization details give policy enough context to distinguish between them. A read action might be allowed automatically. An update requires additional controls. A destructive operation requires approval or is denied entirely.
RAR doesn’t define business policies or a meeting preparation authorization model. It gives the authorization system a precise description of the operation to enable policies to make better decisions. The API then defines what these authorization details mean.
RAR isn’t limited to human-initiated AI
Sarah is a useful example, but RAR isn’t inherently tied to a human user. Autonomous workloads also need fine-grained authorization. For example, an autonomous action agent might request a specific operation, sending authorization_details to the authorization server to obtain constrained authorization. The agent operates under its own machine authority and authorization details help establish what the agent is allowed to do, whether it’s acting for a person or autonomously.
RAR and scopes are complementary
RAR doesn’t mean scopes disappear. Authorization details and scopes describe different parts of the authorization model. Scopes present broad capabilities, while authorization details describe fine-grained authorization requirements.
An API might use scopes, authorization details, or both depending on how its authorization model is designed. The important distinction is that RAR provides richer structure when a flat capability string isn’t enough.
RAR and PAR work together naturally
As authorization requests become richer, they can also become larger and more sensitive. This is where Pushed Authorization Requests (PAR) complement RAR. PAR defines how the authorization request reaches the authorization server, pushing the request directly to the server before the browser redirect. RAR defines what is being requested. The two protocols solve different parts of the authorization problem.
Key takeaways
RAR doesn’t establish identity. It gives the authorization system a structured description of the requested operation. RAR authorizes the specific operation, not just the caller. The authorization server evaluates the structured request, the access token carries the resulting authorization context, and the resource server enforces what’s authorized.