| Internet-Draft | AROP | November 2026 |
| McGuinness | Expires 10 May 2027 | [Page] |
This specification defines an OAuth binding for the AuthZEN Access Request and Approval Profile in which an approved access request completes as an issued OAuth access token. When a request is evaluated as an AuthZEN Access Evaluation and the decision is denied but requestable, the denial is resolved through an access request and completes by issuing an access token that carries the approved authorization. The asynchronous wait is carried by an existing OAuth asynchronous authorization mechanism; this profile defines three transport bindings: the OAuth Deferred Token Response, Client-Initiated Backchannel Authentication (CIBA), and the OAuth Transaction Authorization Challenge. The binding adds no new OAuth grant type, endpoint, or protocol parameter of its own; it composes these mechanisms with Rich Authorization Requests and the Access Request and Approval Profile.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 10 May 2027.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
The AuthZEN Access Request and Approval Profile [ARAP] defines how a denied but requestable authorization decision is resolved out of band and re-evaluated. It defines a single completion mode, reevaluate, in which the Policy Decision Point (PDP) remains authoritative at enforcement time, and it explicitly leaves completion modes that bind approval to a specific issuance flow, such as OAuth token issuance where the issued token is itself the decision representation, to a downstream profile.¶
This specification is that downstream profile for OAuth 2.1 [I-D.ietf-oauth-v2-1]. It defines a token issuance completion mode: a request is evaluated as an AuthZEN Access Evaluation [AuthZEN], and when the decision is denied but requestable it is resolved through an [ARAP] access request and completes by issuing an access token that carries the approved authorization.¶
The completion semantics are the same regardless of how the asynchronous wait is carried: the issued access token is the decision representation, the authoritative decision is made at issuance time, and the issued credential is bounded by the recorded approval expiry. What varies is the OAuth mechanism that carries the request and the wait. This profile defines three transport bindings:¶
Deferred Token Response [I-D.ietf-oauth-deferred-token-response] (DTR): the client makes a token request, and rather than returning a token or an error the Authorization Server (AS) returns a deferral_code; the client polls the token endpoint until the token is issued or the request is denied.¶
Client-Initiated Backchannel Authentication [OIDC-CIBA] (CIBA): the client makes a backchannel authentication request, the AS returns an auth_req_id, and approval is obtained out of band from a decoupled party; the client polls the token endpoint (or is notified) until completion.¶
Transaction Authorization Challenge [I-D.rosomakho-oauth-txn-challenge] (transaction challenge): a protected resource returns a signed challenge for an operation it cannot authorize from the presented token; the client presents the challenge at the token endpoint under the transaction authorization grant, the AS obtains approval and issues a transaction-scoped token, and that token is re-presented to the resource. This binding carries its wait with DTR, so it differs from the first in where the requested authorization comes from rather than in how the client waits.¶
These bindings also differ in where the requestable denial originates. In [ARAP] the Policy Enforcement Point (PEP) and PDP roles can be deployed in more than one place, and all of the following are valid: the AS evaluates and defers its own token request (AS as PEP); a protected resource asserts the requestable denial as a signed challenge that the AS consumes (resource as PEP); or both apply policy, the resource asserting the challenge and the AS additionally evaluating before it issues. This profile accommodates all three placements.¶
The binding adds no new OAuth grant type, endpoint, or protocol parameter of its own. The deferred grant belongs to DTR, the backchannel endpoint and CIBA grant belong to CIBA, and the transaction authorization grant belongs to the transaction challenge draft; this profile only binds them to the [ARAP] lifecycle and uses Rich Authorization Requests [RFC9396] (RAR) to carry both the requested and the approved authorization.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
OAuth-native completion. In this mode the issued access token is the decision representation. Authorization is exercised by presenting the token to a resource server, not by carrying an AuthZEN decision object on the wire.¶
Compose, do not reinvent. The asynchronous transport is an existing OAuth mechanism (DTR, CIBA, or the transaction challenge, which itself defers through DTR), the fine-grained request and grant are RAR, and the approval lifecycle is [ARAP]. This profile only binds them; it defines no new endpoints, grant types, or parameters of its own.¶
Shared completion semantics, several transports. The resolution outcomes, the issuance-time decision, the least-privilege constraint, and the approval-bounded lifetime are defined once and shared by all three bindings (see Section 7). A binding section specializes only the transport surface: how the request enters, the name of the continuation handle, where the client polls or is notified, and how completion is delivered (see Section 9).¶
The decision is not carried on the wire. The request carries a RAR request (or, in the transaction challenge binding, a resource-signed challenge), the evaluating party maps it to an AuthZEN evaluation internally, and the issued token carries the approved grant. No AuthZEN request or decision object travels between the client and the AS (see Section 15).¶
Least privilege. The issued token's granted authorization (authorization_details, and scope if used) reflects the approved access and MUST NOT broaden the originating request. The token SHOULD be audience-restricted to the intended resource using resource indicators [RFC8707], so a narrowly approved token is not presentable at an unintended resource server.¶
Authority model: two completion modes, chosen per approval. Approval can complete in one of two ways, and a deployment selects per approval and MAY mix them:¶
Re-evaluation completion ([ARAP]'s reevaluate): the PDP stays authoritative at enforcement, re-evaluated on every call. Currency is per call and no long-lived credential is issued.¶
Token-issuance completion (this profile): the approved grant is carried in an issued access token that is itself the decision representation. The authoritative decision is made at issuance time and a resource server later validates the token, possibly offline, so currency is bounded by the token's lifetime.¶
This profile defines token-issuance completion; it trades per-call re-evaluation for an issuance-time decision. Deployments preserve currency with short token lifetimes, token introspection, and re-evaluation at each refresh; the issued access token's lifetime MUST NOT exceed the approval expiry the Access Request Service recorded; and the approval bounds the whole credential rather than a single token (see Section 7).¶
This profile uses the roles of [AuthZEN] and [ARAP], mapped onto OAuth:¶
The OAuth Authorization Server and the token issuer. In the DTR and CIBA bindings the AS also acts as (or fronts) the AuthZEN PDP for the request. In the transaction challenge binding the AS consumes a requestable denial asserted by a protected resource, and MAY additionally apply its own policy before issuing. Any OAuth token-issuing endpoint can play this role, so approval is gated wherever the token is requested: a single AS, the identity provider (IdP) or Resource Authorization Server (RAS) in an ID-JAG [I-D.ietf-oauth-identity-assertion-authz-grant] chain, or a resource server that issues its own tokens.¶
The [ARAP] role that runs the approval workflow. The evaluating party submits the access request to it and tracks resolution. It is internal to the deployment and not exposed to the client.¶
The [ARAP] role that detects the requestable denial. In this profile the PEP may be the AS (DTR, CIBA), a protected resource that asserts a signed challenge (transaction challenge), or both.¶
The OAuth client (an agent, or a Policy Enforcement Point acting for one) that makes the request and polls for, or is notified of, completion.¶
In the transaction challenge binding, the component that attempted the operation at the protected resource. It relays the challenge to the client without modifying it and later presents the issued token to the resource [I-D.rosomakho-oauth-txn-challenge]. Where one component does both, the agent and the client are the same party; the other two bindings have no separate agent.¶
The server that accepts the issued access token and enforces the authorization it carries. In this profile the RS is the enforcement point at the time of use: it validates the token, possibly offline, rather than re-evaluating against a PDP per call. In the transaction challenge binding the RS additionally originates the requestable denial as a signed challenge.¶
The opaque value that binds the pending access request in the issuer's state and that the client redeems to obtain the token. Two bindings name it differently: the DTR deferral_code and the CIBA auth_req_id. The transaction challenge binding defers through DTR, so its handle is the deferral_code as well.¶
This profile also uses authorization_details from [RFC9396], and the transport-specific parameters of [I-D.ietf-oauth-deferred-token-response], [OIDC-CIBA], and [I-D.rosomakho-oauth-txn-challenge] as defined in the binding sections.¶
Across all three bindings the shape is the same: an asynchronous authorization request, a pending response carrying a continuation handle, a wait resolved out of band, and completion as an issued access token. The diagram shows the common flow; the binding sections give the per-transport entry point, handle, and completion surface.¶
+--------+ +---------------------+ +------------------+
| Client | | Authorization Server| | Access Request |
| | | (issuer + PDP) | | Service (ARS) |
+---+----+ +----------+----------+ +--------+---------+
| | |
| 1. asynchronous authorization request | |
| (RAR authorization_details) | |
|---------------------------------------->| |
| | evaluate (AuthZEN); |
| | denied but requestable |
| |--------------------------->|
| | submit access request |
| 2. pending: continuation handle, | |
| expires_in, interval | |
|<----------------------------------------| |
| | ... out-of-band approval |
| 3. poll (or notification) | |
|---------------------------------------->| |
| pending | |
|<----------------------------------------| |
| | approved |
| |<---------------------------|
| | re-evaluate with approval; |
| | issue token |
| 4. access_token (+ authorization_details) |
|<----------------------------------------| |
¶
In the transaction challenge binding the requestable denial originates at a protected resource, which returns a signed challenge to the agent before step 1; the agent relays it to the client, which presents it to the AS, and after completion the agent re-presents the issued token to the resource (see Section 9.3).¶
The mechanism a client uses is the one the issuer advertises, and each transport advertises independently in authorization server metadata. This profile defines no additional discovery metadata of its own; whether a given request is evaluated as an AuthZEN Access Evaluation and may be deferred for approval is a policy decision and is not separately advertised.¶
DTR. The AS advertises deferred_token_response_supported ([I-D.ietf-oauth-deferred-token-response]). A client participates by including deferred among its completion_mode values on the token request and being prepared for a synchronous token, a deferred response, or an error; a client that can put an interaction in front of the approving party includes deferred_interactive as well.¶
CIBA. The AS advertises a backchannel_authentication_endpoint and backchannel_token_delivery_modes_supported ([OIDC-CIBA]); a client uses the delivery mode (poll, ping, or push) the AS supports.¶
Transaction challenge. The AS lists urn:ietf:params:oauth:grant-type:txn-authz-challenge in grant_types_supported and sets deferred_token_response_supported to true; the protected resource advertises the keys it signs challenges with (txn_challenge_jwks_uri) and the algorithms it signs them with (txn_challenge_signing_alg_values_supported) in its protected resource metadata, per [I-D.rosomakho-oauth-txn-challenge]. Unlike the other two bindings, this introduces a trust relationship in which the AS validates challenges signed by the resource (see Section 14).¶
In a multi-issuer topology, each token-issuing party (a single AS, the IdP and the RAS in an ID-JAG chain, or a resource server that issues its own tokens) advertises its supported mechanisms independently in its own metadata.¶
This section defines the resolution outcomes and completion semantics shared by all three bindings. The binding sections (Section 9) specialize only the transport surface. For how the request maps to an AuthZEN Access Evaluation, see Section 8.¶
A client engages exactly one binding, selected by the entry point and opt-in it used; the evaluating party never converts a request made under one binding into another. The evaluating party resolves an asynchronous authorization request as follows:¶
Allow. The transport's normal success response is returned synchronously (a token, for the request mechanisms that issue one directly).¶
Deny, not requestable. A synchronous error is returned in the transport's error form: at the token endpoint, invalid_authorization_details ([RFC9396]) when the denial concerns the requested authorization_details, invalid_scope when it concerns requested scope, and otherwise invalid_grant. The pending and terminal-denial codes (authorization_pending, interaction_required, interaction_pending, access_denied, expired_token, slow_down) are reserved for the deferred path and MUST NOT be returned here. The transaction authorization grant is the one place one of them is returned synchronously; see the no-opt-in case below.¶
Deny, requestable. The evaluating party MUST NOT issue a token. It submits an [ARAP] access request to its internal Access Request Service on the client's behalf (an internal approval submission, not an outbound OAuth request to any authorization server), binds the resulting task to this transport's continuation handle, and returns this transport's pending response (carrying the handle, expires_in, and interval).¶
Deny, requestable, but the client did not opt into asynchronous completion. A binding that guards its deferred response behind a client signal (DTR's completion_mode=deferred) MUST NOT return that deferred response when the client did not send it, because the client may be unable to handle it. Opting in is a requirement of the deferral transport, not a precondition for approval; the internal access request and re-evaluation need no client opt-in. Rather than silently deny, the evaluating party MAY surface the requestable denial to the client as remediation so the client can proceed as it sees fit: retry while opting into a deferral transport (DTR or CIBA), reuse an existing token that already satisfies the requirement, or pursue interactive end-user approval where deferral is not needed. A requestable denial therefore does not by itself imply deferral. On the transaction authorization grant the answer is already fixed: [I-D.rosomakho-oauth-txn-challenge] has the AS return access_denied when the client did not signal deferred and approval cannot be obtained synchronously, and the client repeats the request with it. Where the requestable denial originates at a protected resource, the remediation reaches the client as a challenge (a signed Transaction Authorization Challenge, which the resource returns only to an agent that signalled Accept-Txn-Challenge, or an authorization_remediation response [I-D.ietf-oauth-rar-metadata-remediation]). A deployment MAY withhold the requestable nature where revealing that the operation is obtainable through approval is itself sensitive.¶
An asynchronous authorization request is not inherently idempotent, so a client that retries an initial request (for example after a lost response or a restart) could otherwise cause the issuer to open a second access request and issue a second continuation handle for one intent. To prevent duplicate approvals, the issuer SHOULD treat a repeated requestable-denial request from the same client for the same requested authorization (the same authorization_details and scope) as the same request and return the existing handle rather than open a new access request. This deduplication is best-effort; a client that requires exactness SHOULD send a stable request identifier where its transport provides one. The transaction challenge binding needs no best-effort rule: [I-D.rosomakho-oauth-txn-challenge] identifies a resubmitted challenge by its iss and jti and has the AS continue the original transaction authorization request rather than open a second one.¶
The continuation handle is the redemption handle and binds the pending access request in the issuer's state. It is not authority: possessing a handle does not authorize anything, and a token is issued only after the issuance-time re-evaluation below. The handle is sender-constrained (see Section 12) and is redeemed at most once: once a token is issued for it, a subsequent redemption MUST fail with invalid_grant.¶
The client redeems the continuation handle at the binding's completion endpoint, no faster than interval, and backs off on a slow_down response. Under DTR, authorization_pending, interaction_required, and interaction_pending are all non-terminal and the client keeps polling through them. Where a binding offers a notification channel (the DTR client callback, CIBA ping), the client MAY rely on it in addition to polling; polling remains the authoritative completion path. A binding MAY also deliver the token directly rather than by redemption (CIBA push), in which case there is no polling to be authoritative over. On resolution the evaluating party re-evaluates the original request with the approval as an input (the [ARAP] approval object, carried at context.approval in the internal evaluation) and:¶
Approved. The issuer issues the access token. The granted authorization (authorization_details, and scope if used) carries the approved access, which MUST NOT broaden the originating request, and the access token lifetime MUST NOT exceed the recorded approval expiry.¶
The approval bounds the credential, not a single token: no access token, refresh token, or token obtained by exchange ([RFC8693]) may outlive the recorded approval expiry (approved_until) or broaden the approved access, and a refresh or exchange after that expiry MUST fail with invalid_grant and requires a new access request.¶
Within that bound, whether a refresh token applies depends on the completion mode and on what was approved. Under token-issuance completion, standing, time-bounded access (for example read access to a path, or a policy-granted set of privileges expressed as RAR) is served by a refresh token bounded by approved_until and re-evaluated at each refresh, which keeps the PDP in the loop within the approval window; a single-use approval (for example a single payment, or the single-use Transaction Authorization Challenge) SHOULD NOT yield a refresh token, and [I-D.rosomakho-oauth-txn-challenge] rules one out altogether where the challenge carries a cnf claim, since a refreshed token would be bound to a key the client proves instead. Where standing access should instead be re-evaluated on every call, that is re-evaluation completion ([ARAP]'s reevaluate), which needs no long-lived credential and is out of scope for this profile.¶
Terminal denial, cancellation, or expiry. The issuer returns access_denied (or expired_token once the handle lifetime has elapsed).¶
The issued access token is the decision representation. This is the token issuance completion mode that [ARAP] defers to a downstream profile. Because completion is the issued token, this mode is not surfaced to the client as an [ARAP] result.mode value; the OAuth token response is the result.¶
Inputs the access request needs are supplied either in the initial request (for example as authorization_details fields, or CIBA's binding_message) or out of band at the Access Request Service. Where DTR carries the wait, the AS has somewhere to send the client: an interaction_uri, returned with interaction_required or alongside a pending response, is the natural carrier for an [ARAP] form_url or request_schema_url, and deferred_interactive is how a client says it can act on one. The URI is opaque to the client, and visiting it does not by itself complete the request. CIBA has no equivalent channel, and this profile defines no in-band input mechanism of its own.¶
The requestable denial and re-evaluation are driven through the AuthZEN Access Evaluation API [AuthZEN] and the [ARAP] extensions. These AuthZEN messages are exchanged between the evaluating party and its PDP and never appear on the OAuth wire; the client sees only the OAuth request and the pending or final response. For how the [ARAP] lifecycle constructs map to the OAuth wire, see Section 11.¶
[ARAP] allows the PEP and PDP roles to be deployed in more than one place, and this profile supports three placements:¶
AS as PEP (DTR, CIBA). The AS evaluates the request against its PDP, derives the requestable denial itself, and defers.¶
Resource as PEP (transaction challenge). A protected resource detects that the presented token cannot authorize the operation, asserts the requestable denial as a signed transaction_challenge, and the AS treats the validated challenge as the requestable-denial signal rather than re-deriving the decision from scratch.¶
Both. The resource asserts the challenge and the AS additionally evaluates against its own PDP before issuing, so the decision is the conjunction of resource policy and AS policy.¶
In every placement the access request, approval, and issuance-time re-evaluation are the same; only the origin of the requestable denial differs.¶
The evaluating party builds the Access Evaluation request from the OAuth request (or the challenge):¶
| OAuth request | AuthZEN Access Evaluation |
|---|---|
The principal the token will act as (client_credentials: the client; Token Exchange: the subject_token subject; authorization code: the end user; CIBA: the party in login_hint; transaction challenge: the actor in the challenge act, when present) |
subject (with the agent in subject.properties.act) |
Each authorization_details object, and any scope values |
one or more resource and action pairs |
Client identity, sender-constraining key, resource indicator [RFC8707], and request metadata |
context members |
The structural mapping above is fixed. The semantic interpretation of a given authorization_details type (and of named scopes) into AuthZEN resource and action values is deployment- or vocabulary-defined, and interoperating parties MUST agree on it. The agent acting for the principal is conveyed in subject.properties.act and context.client_id.¶
A fine-grained read request (read access to one customer record) maps to an evaluation whose subject carries the user and the acting agent, with the record as resource and read as action; the worked trace in Section 10.1 shows the full Access Evaluation request and the PDP's response.¶
A request may carry several authorization_details (and scopes), which the evaluating party evaluates together; it MAY use the AuthZEN Evaluations (bulk) API for this. This profile treats the request as a unit: if any requested authorization is requestable-denied and the client opted into asynchronous completion, the whole request is deferred and the full requested set is issued on approval. Partial issuance (issuing the allowed subset immediately and deferring the rest) is not defined by this profile.¶
When the PDP denies but the denial is requestable, it returns decision: false with an [ARAP] context.access_request and denial-binding material (context.evaluation_id or a binding_token):¶
{
"decision": false,
"context": {
"evaluation_id": "ev_9f2c8a1b",
"reason": "approval_required",
"access_request": { "expires_at": "2026-06-13T12:00:00Z" }
}
}
¶
The example above carries context.evaluation_id, which the Access Request Service resolves against the PDP's recorded evaluation; this fits a deployment where the Access Request Service shares the PDP's state. Where the Access Request Service is a separate service from the PDP, it cannot trust the submitting party's claim that a denial occurred, so the denial instead carries a PDP-signed binding_token in context.access_request that the service verifies cryptographically; evaluation_id is then optional:¶
{
"decision": false,
"context": {
"reason": "approval_required",
"access_request": {
"expires_at": "2026-06-13T12:00:00Z",
"binding_token": "eyJhbGciOiJFUzI1NiIsImtpZCI6InBkcC0xIn0..."
}
}
}
¶
The evaluating party submits the access request using this binding material, binds the resulting [ARAP] task to a continuation handle, and returns the transport's pending response. A decision: false with no context.access_request is a non-requestable denial and maps to the synchronous error in Section 7. In the transaction challenge binding the resource has already asserted the requestable denial as a signed challenge; the AS validates the challenge and submits the access request from it (and MAY additionally evaluate against its own PDP).¶
On approval, the evaluating party re-evaluates the same request with the [ARAP] approval object at context.approval (the re-evaluation request, the task it resolves, and the resulting decision are shown in Section 10.1). A decision: true response authorizes issuance: the issuer issues the access token whose granted authorization_details reflect the approved resource and action, with a lifetime bounded by approved_until. A decision: false at re-evaluation maps to access_denied on the next poll; obtaining access then requires a new request.¶
Each binding specializes the Section 7 model onto one OAuth asynchronous mechanism. The completion semantics (issuance-time decision, least privilege, approval-bounded lifetime) are identical; the table summarizes what differs, and the subsections give the detail.¶
| Deferred Token Response | CIBA | Transaction Challenge | |
|---|---|---|---|
| Origin of requestable denial | AS (PDP) | AS (PDP) | Protected resource (signed challenge) |
| Entry point | Token endpoint | Backchannel authentication endpoint | Token endpoint, transaction authorization grant |
| Client opt-in signal |
completion_mode=deferred
|
Use of the backchannel endpoint |
Accept-Txn-Challenge to the resource, then completion_mode=deferred to the AS |
| Continuation handle |
deferral_code
|
auth_req_id
|
deferral_code, from DTR |
| Completion endpoint | Token endpoint (deferred grant) | Token endpoint, CIBA grant (poll, ping); client notification endpoint (push) |
Token endpoint (deferred grant) |
| Notification (optional) | DTR client callback | CIBA ping (push delivers the token directly) |
DTR client callback |
| Completion | Access token response | Access token response | Access token response, re-presented to the resource |
| Denial / expiry |
access_denied / expired_token
|
access_denied / expired_token
|
access_denied / expired_token
|
The client makes an ordinary token request and signals deferred completion with completion_mode=deferred ([I-D.ietf-oauth-deferred-token-response]). The requested authorization is expressed with authorization_details ([RFC9396]), with scope, or with both. The AS maps the request to an AuthZEN Access Evaluation and resolves per Section 7. On a requestable denial it binds the access request to a deferral_code and returns the DTR deferred response (authorization_pending with deferral_code, expires_in, and interval).¶
The client polls the token endpoint with the deferred grant type (urn:ietf:params:oauth:grant-type:deferred) and the deferral_code, and completes per Section 7. This binding rides on any originating grant, including Token Exchange [RFC8693], the authorization code grant, and the refresh token grant.¶
CIBA [OIDC-CIBA] is purpose-built for decoupled approval: the device that consumes the token (the agent) is separate from the device on which the user authenticates and approves. This profile uses that decoupling for the agentic case in which the principal approves their own agent's elevation out of band, on their own authentication device, while the agent waits.¶
In CIBA the user identified by login_hint, login_hint_token, or id_token_hint is the user the AS authenticates and whose identity the issued tokens represent; CIBA does not natively let one party approve a token that acts as a different principal. This binding therefore maps the hint to the principal the issued token acts as, and the approving party is that same principal. Deployments that need a different party (a data owner or manager) to approve should use the DTR or transaction challenge binding, where the approver is the [ARAP] workflow's resolver and is unrelated to OAuth authentication. Per [OIDC-CIBA] the request carries the openid scope; the requested authorization is carried in authorization_details (and any additional scope), and a binding_message MAY convey the operation to the user.¶
The AS maps the request to an AuthZEN Access Evaluation and resolves per Section 7. On a requestable denial it binds the access request to the CIBA auth_req_id and returns it with expires_in and (optionally) interval. In the poll and ping delivery modes the client redeems the auth_req_id at the token endpoint with the CIBA grant type (urn:openid:params:grant-type:ciba); in ping the AS first notifies the client's notification endpoint that the result is ready, and in push the AS instead delivers the tokens directly to that endpoint with no token-endpoint redemption. A client using ping or push MUST supply a client_notification_token on the backchannel authentication request ([OIDC-CIBA]). Where the client polls, polling remains the authoritative completion path as in Section 7. In every mode completion is an access token carrying the approved authorization_details, bounded by the approval expiry.¶
In this binding the protected resource is the PEP. When the resource determines that the token presented for an operation does not authorize it, it returns HTTP 401 with a WWW-Authenticate challenge carrying a signed transaction_challenge (a JWS whose claims include txn, authorization_details, the resource as iss, the AS as aud, iat, exp, jti, and a human-readable reason, and optionally act for the requester context and cnf for a binding key), per [I-D.rosomakho-oauth-txn-challenge]. The agent signals that it understands challenges with the Accept-Txn-Challenge header, and a resource returns one only to an agent that signalled it or that it knows out of band to support the mechanism. The challenge is the resource's assertion of a requestable denial, signed so neither the agent nor the client can forge or broaden the requested operation.¶
The client itself presents the challenge to the AS named in the challenge's aud, as a token request under the transaction authorization grant (urn:ietf:params:oauth:grant-type:txn-authz-challenge) carrying the challenge in transaction_challenge and opting into deferral with completion_mode=deferred, per [I-D.rosomakho-oauth-txn-challenge]; the originating deployment does not forward anything on the client's behalf, so no server-to-server credential is crossed even when aud names an AS the client has not used before. That AS validates the challenge against the resource's signing keys, treats it as the requestable-denial signal (and MAY additionally evaluate against its own PDP), submits the [ARAP] access request to its own Access Request Service, and resolves per Section 7. On a requestable denial it returns the DTR deferred response and the client polls the token endpoint with the deferred grant, exactly as in Section 9.1. The challenge supplies the requested authorization; DTR carries the wait.¶
On approval the AS issues an access token that carries the challenge's txn and authorization_details and is audience-restricted to the resource. The client returns it to the agent, which re-presents it to the resource; the resource validates that the token's txn matches the challenge, that the audience identifies the resource, and that the granted authorization_details authorize the operation. Because the resource originates and consumes the txn, this binding is the one case where completion is not "client holds token, done": the token is evidence re-presented to the resource that originated the challenge. Resources SHOULD treat these tokens as single-use for non-idempotent or high-impact operations.¶
These examples are non-normative. Together they cover the three PEP placements of Section 8: the AS as PEP (the DTR and CIBA examples, where the AS derives the requestable denial), the resource as PEP (the transaction challenge example, where the resource asserts it), and both (the closing variant of the transaction challenge example, where the AS also applies its own policy). The first example also shows the AS's internal AuthZEN evaluation, marked as off the OAuth wire, so the binding to [AuthZEN] and [ARAP] is visible end to end; the other examples show only the client-visible OAuth exchange.¶
An agent acting on behalf of a user requests fine-grained access to a single protected resource. The authorization_details (shown decoded for readability) scopes the request to one record:¶
[ { "type": "customer_records", "actions": ["read"], "locations": ["https://crm.example/customers/c-4815"] } ]
¶
POST /token HTTP/1.1 Host: as.example.com Content-Type: application/x-www-form-urlencoded DPoP: eyJ... grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atoken-exchange &completion_mode=deferred &authorization_details=%5B%7B%22type%22%3A%22customer_records%22%2C%22actions%22%3A%5B%22read%22%5D%2C%22locations%22%3A%5B%22https%3A%2F%2Fcrm.example%2Fcustomers%2Fc-4815%22%5D%7D%5D &subject_token=...&subject_token_type=...¶
Internally, and never on the OAuth wire, the AS maps this to an AuthZEN Access Evaluation and calls its PDP:¶
{
"subject": {
"type": "user",
"id": "alice@example.com",
"properties": { "act": { "sub": "agent-7" } }
},
"resource": { "type": "customer_records", "id": "c-4815" },
"action": { "name": "read" },
"context": { "client_id": "agent-7", "dpop_jkt": "0ZcOCORZ..." }
}
¶
The PDP returns a denied-but-requestable decision:¶
{
"decision": false,
"context": {
"evaluation_id": "ev_9f2c8a1b",
"reason": "approval_required",
"access_request": { "expires_at": "2026-06-13T12:00:00Z" }
}
}
¶
Here the Access Request Service shares the PDP's state, so the denial binds by evaluation_id; a separate-service Access Request Service would instead receive a PDP-signed binding_token (Section 8). The AS submits the [ARAP] access request on the agent's behalf, echoing the denial-binding material (authentication to the Access Request Service is omitted for brevity):¶
POST /access/v1/requests HTTP/1.1
Host: pdp.example.com
Content-Type: application/json
Idempotency-Key: 7b8d0f0d-65a1-4af1-9fd3-a684f08a5d14
{
"subject": {
"type": "user",
"id": "alice@example.com",
"properties": { "act": { "sub": "agent-7" } }
},
"resource": { "type": "customer_records", "id": "c-4815" },
"action": { "name": "read" },
"denial": {
"evaluation_id": "ev_9f2c8a1b",
"expires_at": "2026-06-13T12:00:00Z",
"reason": "approval_required"
}
}
¶
The Access Request Service accepts it and returns a pending task:¶
HTTP/1.1 202 Accepted
Content-Type: application/json
Location: https://pdp.example.com/access/v1/requests/arq_01HX4Y3AJZ
{
"task": {
"id": "arq_01HX4Y3AJZ",
"status": "pending",
"status_endpoint": "https://pdp.example.com/access/v1/requests/arq_01HX4Y3AJZ"
}
}
¶
The AS binds this task to a deferral_code and returns the deferred response to the client:¶
{
"error": "authorization_pending",
"deferral_code": "8d67dc78-7faa-4d41-aabd-67707b374255",
"expires_in": 10800,
"interval": 60
}
¶
The client polls the token endpoint until the record's data owner resolves the request out of band:¶
POST /token HTTP/1.1 Host: as.example.com Content-Type: application/x-www-form-urlencoded DPoP: eyJ... grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adeferred &deferral_code=8d67dc78-7faa-4d41-aabd-67707b374255¶
Behind the AS, the data owner approves and the task reaches a terminal state, which the AS reads from the Task Status Endpoint:¶
GET /access/v1/requests/arq_01HX4Y3AJZ HTTP/1.1 Host: pdp.example.com¶
HTTP/1.1 200 OK
Content-Type: application/json
{
"task": { "id": "arq_01HX4Y3AJZ", "status": "approved" },
"result": {
"approval": { "id": "ar_123", "approved_until": "2026-06-13T18:00:00Z" }
}
}
¶
The task completes with the approval. Under this profile the completion mode is token issuance, not [ARAP]'s reevaluate (see Section 11), so the result is the issued token rather than a client-facing result.mode; the AS re-evaluates the original request itself with the approval at context.approval:¶
{
"subject": {
"type": "user",
"id": "alice@example.com",
"properties": { "act": { "sub": "agent-7" } }
},
"resource": { "type": "customer_records", "id": "c-4815" },
"action": { "name": "read" },
"context": { "approval": { "id": "ar_123", "approved_until": "2026-06-13T18:00:00Z" } }
}
¶
The PDP now allows it:¶
{ "decision": true }
¶
The AS issues an access token carrying the approved authorization, with a lifetime bounded by the recorded approved_until:¶
{
"access_token": "eyJ...",
"token_type": "DPoP",
"expires_in": 900,
"authorization_details": [
{ "type": "customer_records", "actions": ["read"], "locations": ["https://crm.example/customers/c-4815"] }
]
}
¶
If the data owner denies the request, the task reaches denied, the AS's re-evaluation returns decision: false, the poll returns access_denied, and no token is issued.¶
The flow above is independent of the originating grant and of which party gates approval. The same DTR exchange applies when the agent redeems an authorization code (the authorization_details bound to the code drive the decision), when it uses a refresh token to reach a resource outside its current scope, and when the gate sits at a resource server that issues its own tokens (contrast Section 9.3, where the resource asserts a signed challenge rather than issuing a token). In an ID-JAG [I-D.ietf-oauth-identity-assertion-authz-grant] chain there are two issuers and approval may be gated at either: the identity provider may defer when it issues the ID-JAG, or the Resource Authorization Server may defer when the agent redeems it. In every case the deferring party returns the same authorization_pending response, and the agent polls and completes as shown.¶
An agent acting for Alice needs to export a CRM report, an action that requires Alice's explicit approval. The agent makes a backchannel authentication request naming Alice (the principal the token will act as) with login_hint, and conveying the operation to her with binding_message; CIBA prompts Alice on her own authentication device while the agent waits:¶
POST /backchannel-authn HTTP/1.1 Host: as.example.com Content-Type: application/x-www-form-urlencoded DPoP: eyJ... scope=openid &login_hint=alice%40example.com &binding_message=Export+CRM+contacts &authorization_details=%5B%7B%22type%22%3A%22crm%22%2C%22actions%22%3A%5B%22export%22%5D%2C%22locations%22%3A%5B%22https%3A%2F%2Fcrm.example%2Fcontacts%22%5D%7D%5D¶
The AS evaluates the request, gets a denied-but-requestable decision, submits an access request, and returns:¶
{
"auth_req_id": "1c266114-a1be-4252-8ad1-04986c5b9ac1",
"expires_in": 300,
"interval": 5
}
¶
The agent redeems the auth_req_id at the token endpoint once the owner approves out of band:¶
POST /token HTTP/1.1 Host: as.example.com Content-Type: application/x-www-form-urlencoded DPoP: eyJ... grant_type=urn%3Aopenid%3Aparams%3Agrant-type%3Aciba &auth_req_id=1c266114-a1be-4252-8ad1-04986c5b9ac1¶
Before approval the token endpoint returns authorization_pending; on approval it returns an access token carrying the approved authorization, bounded by the approval expiry:¶
{
"access_token": "eyJ...",
"token_type": "DPoP",
"expires_in": 900,
"id_token": "eyJ...",
"authorization_details": [
{ "type": "crm", "actions": ["export"], "locations": ["https://crm.example/contacts"] }
]
}
¶
If Alice declines, or the request expires, the poll returns access_denied or expired_token and no token is issued.¶
An agent already holds a token for a CRM but attempts a high-impact deletion the token does not authorize. The resource returns a signed challenge:¶
DELETE /customers/c-4815 HTTP/1.1 Host: crm.example Authorization: DPoP eyJ... Accept-Txn-Challenge: ?1¶
HTTP/1.1 401 Unauthorized WWW-Authenticate: DPoP error="transaction_authorization_required", transaction_challenge="eyJ0eXAiOiJ0eG4tYXV0aHotY2hhbGxlbmdlK2p3dC... (signed JWT)"¶
The agent relays the challenge to its client, which presents it at the token endpoint under the transaction authorization grant:¶
POST /token HTTP/1.1 Host: as.example.com Content-Type: application/x-www-form-urlencoded DPoP: eyJ... grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atxn-authz-challenge &client_id=agent-7 &completion_mode=deferred &transaction_challenge=eyJ0eXAiOiJ0eG4tYXV0aHotY2hhbGxlbmdlK2p3dC...¶
Here the binding to [AuthZEN] differs from the DTR example: the AS does not derive the requestable denial itself, it arrives as the resource-signed challenge. The AS validates the challenge's signature, treats its authorization_details and txn as the requestable-denial signal (mapping them to an AuthZEN evaluation only if it also applies its own policy, the "both" case below), submits the access request, and returns the DTR deferred response:¶
HTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-store
{
"error": "authorization_pending",
"deferral_code": "LRGidcSAeVs_xYpEDt5pNx0A0TBr7qPHbh_Se6pfdf4",
"expires_in": 300,
"interval": 5
}
¶
The client polls the token endpoint with the deferred grant and the deferral_code. On approval the AS issues a transaction-scoped token carrying the challenge's txn, which it hands back to the agent to re-present on the original operation:¶
{
"access_token": "eyJ...",
"token_type": "DPoP",
"expires_in": 120,
"authorization_details": [
{ "type": "customer_records", "actions": ["delete"], "locations": ["https://crm.example/customers/c-4815"] }
]
}
¶
The resource validates that the token's txn matches the challenge and that the granted authorization_details authorize the deletion before performing it.¶
In this example the resource is the sole PEP and the AS acts only on the validated challenge. A both as PEP deployment adds one step: after validating the challenge, the AS additionally evaluates the operation against its own PDP before issuing, so issuance requires both the resource's challenge and an AS allow. If the AS's own evaluation is itself a requestable denial, the same access request resolves both; if it is a non-requestable denial, the AS returns the synchronous error of Section 7 and issues nothing. The wire exchange the agent sees is unchanged.¶
The OAuth wire surface replaces several [ARAP] constructs; the rest map directly. For how the OAuth request maps to AuthZEN Access Evaluation messages, see Section 8.¶
| ARAP construct | OAuth binding in this profile |
|---|---|
Requestable denial (context.access_request) |
The trigger to defer: derived by the AS (DTR, CIBA) or asserted by a protected resource as a signed challenge (transaction challenge). Not surfaced to the client as an AuthZEN object. |
| Access request submission | Performed by the evaluating party on the client's behalf during evaluation. |
| Idempotency key | Best-effort dedup by client and requested authorization; in the transaction challenge binding, the challenge's iss and jti (see Section 7). |
| Task handle | The continuation handle: the deferral_code (DTR, and the transaction challenge binding, which defers through DTR) or the CIBA auth_req_id. |
| Task Status Endpoint and polling | Polling the token endpoint: the deferred grant (DTR, transaction challenge) or the CIBA grant. |
| Callback completion | The optional DTR client callback (deferred_client_notification_endpoint), or CIBA ping notification or push delivery (both via the client notification endpoint). |
form_url / request_schema_url
|
Where DTR carries the wait, an interaction_uri returned with interaction_required (see Section 7). |
approval object (context.approval) |
Input to the issuance-time re-evaluation. |
reevaluate completion mode |
Replaced by token issuance (this profile's completion mode). |
binding_token / evaluation_id
|
Bound to the continuation handle in issuer state; not exposed to the client. |
approved_until
|
Upper bound on the issued access token lifetime. |
Denial reason and next_action
|
OAuth error codes (access_denied, expired_token). |
The continuation handle and the issued access token are sender-constrained using DPoP [RFC9449] or mutual TLS [RFC8705]; a public client MUST present DPoP on the initial request, and every polling, redemption, and cancellation request MUST carry proof of possession for the same key. DTR specifies this for the deferral_code ([I-D.ietf-oauth-deferred-token-response]), and the transaction challenge binding inherits it with the rest of DTR; the same requirement applies to the CIBA auth_req_id in this profile. The CIBA binding does not have OAuth public clients in this sense: [OIDC-CIBA] requires the client to authenticate to the backchannel authentication endpoint with its registered method, and DPoP sender-constrains the auth_req_id and issued token on top of that.¶
The transaction challenge binding has one exception. Where the challenge carries a cnf claim, the key the issued token is bound to is the one the resource verified on the request that triggered the challenge, not one the client proves, so [I-D.rosomakho-oauth-txn-challenge] does not require a DPoP proof from the client on the transaction authorization request or on its polls. A token issued for such a challenge is bound to the key in cnf; a token issued for a challenge without one follows the rule above. That draft's editor's note records the unresolved tension with DTR's sender-constraining continuity, and this profile does not settle it.¶
To cancel a pending request:¶
DTR and transaction challenge. The client revokes the deferral_code at the revocation endpoint [RFC7009] (with token_type_hint set to urn:ietf:params:oauth:token-type:deferral-code). The AS MUST cancel the underlying access request.¶
CIBA. This transport defines no client-driven cancellation; the pending request resolves on approval, denial, or expiry of its handle. In all bindings the access request MUST be cancelled when its handle expires.¶
The requested and approved authorization_details (and, in the transaction binding, the signed challenge) can carry sensitive data (account numbers, amounts, resource identifiers). Parties MUST apply data minimization and protect them in transit and at rest.¶
The evaluating party MUST NOT expose the approver's identity, internal approval state, or [ARAP] binding material to the client; the client sees only the continuation handle and the eventual token or error. A CIBA login_hint or binding_message MUST NOT echo approver detail back to the client beyond what the client supplied.¶
error_description and any human-readable text returned with a pending or error response MUST be minimized and MUST NOT leak approver identity or internal policy detail.¶
A pending response is not a grant. A pending response carrying a continuation handle is not access. Denial remains denial: a token is issued only after the issuance-time re-evaluation, and a non-requestable or terminally denied request yields an OAuth error, never a token.¶
Issuance-time decision, bounded by lifetime. Because the authoritative decision is made at issuance and the resource server may validate the token offline, deployments MUST bound the access token lifetime by the approval expiry and SHOULD keep lifetimes short and use token introspection where current revocation matters. Refresh tokens and token exchange MUST NOT be used to extend an approval beyond its recorded expiry (see Section 7); otherwise the approval bound is defeated.¶
Least privilege and audience. The issued authorization MUST reflect the approved access and MUST NOT broaden the originating request, and the token SHOULD be audience-restricted to the intended resource using resource indicators [RFC8707] so an approved token cannot be replayed at an unintended resource server. In the transaction binding the token is audience-restricted to the challenging resource and bound to the challenge txn, which the resource validates before acting.¶
Request integrity. Because the requested authorization_details drive a fine-grained authorization decision, deployments SHOULD protect them in transit and from tampering, for example with Pushed Authorization Requests [RFC9126] or a signed request, so the request that is evaluated is the one the client intended. In the transaction binding the challenge is signed by the resource, so the client cannot forge or broaden the requested operation; the AS MUST validate the challenge signature against the resource's keys before acting on it.¶
The continuation handle is not authority. It is opaque, sender-constrained, and bound to the client it was issued to; it is usable only at the binding's completion (and, for DTR, revocation) endpoint.¶
The decision is not carried on the wire. The request carries a RAR request (or a resource-signed challenge) and the issued token carries the approved grant; neither carries an AuthZEN request or decision object, which keeps the decision engine off the client surface and avoids substitution or replay of decision payloads.¶
[ARAP]: this profile is its OAuth token issuance completion mode. [ARAP] owns the requestable denial, access request, approval, and audit lifecycle; this profile binds completion to OAuth token issuance and supports the AS, a protected resource, or both as the PEP.¶
[I-D.ietf-oauth-deferred-token-response]: an asynchronous transport for this profile and, through the transaction authorization grant, the transport under two of its three bindings. It adds no new grant type; the binding uses DTR's completion_mode, deferred grant, and polling. As a profile layered on DTR this one adds no completion modes, observable states, response parameters, or parameter-update mechanisms of its own, and it keeps DTR's substrate guarantees: the least-privilege rule in Section 7 is DTR's no-authorization-expansion guarantee, polling stays the authoritative completion path, and the handle's sender-constraining carries through to the issued token. The one place that last guarantee is in question is a challenge carrying cnf (see Section 12), which the challenge draft's own editor's note leaves open.¶
[OIDC-CIBA]: an asynchronous transport built for decoupled approval, where the approving party need not be the client; the binding uses the backchannel endpoint, the CIBA grant, and auth_req_id.¶
[I-D.rosomakho-oauth-txn-challenge]: a resource-initiated mechanism in which the protected resource asserts the requestable denial as a signed challenge; the binding uses its transaction authorization grant and the txn-bound token, and the challenge draft in turn uses DTR to carry the wait.¶
[RFC9396]: carries the requested authorization in the request and the approved authorization in the issued token.¶
[RFC8693]: Token Exchange is a natural originating grant for on-behalf-of agent flows, and DTR can defer it; this profile composes with it unchanged.¶
[I-D.brossard-oauth-rar-authzen]: that draft places an AuthZEN request and response inside authorization_details. This profile deliberately does not. The decision stays behind the evaluating party and the token carries the approved grant, not the evaluation.¶
[I-D.ietf-oauth-rar-metadata-remediation]: a resource-initiated remediation mechanism in which a protected resource returns insufficient_authorization with an authorization_remediation challenge carrying the authorization_details the client must obtain, plus an optional authorization_reference the client can use to locate a token it already holds that satisfies the requirement (avoiding a new grant). It composes with this profile as a discovery and remediation front-end: the client either reuses a matching token or takes the remediation authorization_details to the AS while opting into deferred completion (or using CIBA); the AS resolves the requestable denial through approval and issues a token carrying the granted authorization_details as the fulfillment. Three layers compose: this mechanism says what to request, a transport binding carries the approval wait, and the issued token carries the fulfillment. It is the unsigned, fresh-grant counterpart to the resource-signed Transaction Authorization Challenge; because the remediation challenge is not a signed requestable-denial assertion, the AS evaluates the request itself (AS as PEP) rather than consuming the resource's decision.¶
[RFC8628]: the Device Authorization Grant solves a related asynchronous case for the same end user; these transports (and therefore this profile) do not assume the approver is the requesting user, which is the agentic case this profile targets.¶
This profile defines no new OAuth grant types, parameters, endpoints, or error codes; it reuses [I-D.ietf-oauth-deferred-token-response], [OIDC-CIBA], [I-D.rosomakho-oauth-txn-challenge], and [RFC9396]. It requests no IANA registrations. Any authorization_details type used by a deployment is registered per [RFC9396].¶
The author thanks Yaron Zehavi for review and discussion, including how this profile composes with the remediation mechanism of [I-D.ietf-oauth-rar-metadata-remediation].¶