| Internet-Draft | AuthZEN Token Issuance | August 2026 |
| Gazitt | Expires 6 February 2027 | [Page] |
Numerous OAuth 2.0 specifications define a moment at which an authorization server decides whether to issue a security token, and each of them declares the decision itself to be a matter of local policy that is out of scope. The result is that a decision common to every OAuth deployment has no interoperable expression.¶
This document defines a profile for using the OpenID AuthZEN Authorization API to externalize that decision to a Policy Decision Point. It specifies how the inputs to a token issuance request map onto AuthZEN's mandatory five-tuple, how a Policy Decision Point response may shape the issued token, and how the two parties discover each other's capabilities.¶
The mapping is complete for grants whose request names a single party and a single target, including the authorization code and client credentials grants. Companion documents bind the grant families that add structure this document does not model, the token exchange family first among them.¶
This note is to be removed before publishing as an RFC.¶
Status information for this document may be found at https://datatracker.ietf.org/doc/draft-gazitt-oauth-authzen-issuance/.¶
Discussion of this document takes place on the Web Authorization Protocol Working Group mailing list (mailto:oauth@ietf.org), which is archived at https://mailarchive.ietf.org/arch/browse/oauth/. Subscribe at https://www.ietf.org/mailman/listinfo/oauth/.¶
Source for this draft and an issue tracker can be found at https://github.com/ogazitt/oauth-authzen.¶
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 6 February 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.¶
Consider the moment an OAuth 2.0 authorization server (AS) has authenticated a client, validated a grant, and must decide whether to mint a token - and if so, with what scopes, what audience, what lifetime, and what claims. Every specification that defines such a moment models its inputs in careful detail and then stops short of the decision.¶
[RFC8693], which defines OAuth 2.0 Token Exchange, is explicit that the decision to issue is governed by policy it does not define. The specifications built on top of it inherit that seam: identity chaining ([I-D.ietf-oauth-identity-chaining]), identity assertion authorization grants ([I-D.ietf-oauth-identity-assertion-authz-grant]), and transaction tokens ([I-D.ietf-oauth-transaction-tokens]) each describe an "administrator-defined policy" or equivalent without describing how such a policy is expressed, evaluated, or externalized.¶
Leaving the decision to local policy is the correct choice for those documents. But it means that the single most security-relevant step in token issuance is, today, an implementation detail - expressed in vendor-specific rules engines, inline hooks, and scripting extensions that do not port between authorization servers and cannot be reasoned about by anything outside the AS.¶
[AUTHZEN] defines an interoperable API between a Policy Enforcement Point (PEP) and a Policy Decision Point (PDP). This document profiles that API for the token issuance moment, casting the authorization server as a PEP.¶
One mechanism, many issuance moments. The decision point is structurally identical across grant types: a party is asking for a token, naming a target and some set of privileges. This document defines that mapping once. Bindings (Section 10) supply what is specific to a given grant or token type, and are expected to be short.¶
Interoperability at the level of policy, not just wire format.
[AUTHZEN] makes exactly five fields mandatory in an evaluation request:
subject.type, subject.id, action.name, resource.type, and
resource.id. Everything else - the properties bag on each entity, and the
context object - is optional. That asymmetry is deliberate. It is what
allows one request shape to be understood by policy engines with very
different internal models: attribute- and policy-based engines that evaluate
expressions over arbitrary input, and relationship-based engines in the style
of [ZANZIBAR] that reason over a typed graph of subjects, relations, and
objects.¶
This is not a claim that a relationship-based engine can consume nothing
beyond the five-tuple. Such engines commonly accept contextual tuples
supplied at query time, and a PDP may project properties or context into
them. It is a claim about where a profile should put the load. The five-tuple
has a shape every conforming PDP can be expected to read the same way; a
free-form bag does not, and a profile that carried its decision-critical
inputs there would nominally use AuthZEN while leaving each PDP to infer the
semantics on its own.¶
This document therefore adopts a design rule:¶
The five-tuple is the primary information model target. Every input on
which the decision depends MUST be expressed in it. properties and
context carry advisory input only, and a conforming mapping MUST be
implementable by a PDP that reads only the five-tuple.¶
The rule is applied throughout and is not re-argued at each mapping.¶
Least surprise for the AS. The profile does not ask the AS to surrender decisions it is authoritative for. A PDP may narrow what is issued; it may not broaden it, re-subject it, or re-target it (Section 6.3).¶
This document covers token issuance: the decision made by an authorization server at its token endpoint, before a token is minted. It does not address enforcement at a resource server, which is the ordinary case AuthZEN already serves and requires no profile.¶
The framework decides an issuance gate. Where a deployment's policy depends on quantitative or transactional constraints - a payment amount, a rate limit - those flow in as advisory context and out as token shaping (Section 6), to be enforced by downstream policy enforcement points. Any conforming PDP can adjudicate the gate, because the gate is expressed entirely in the five-tuple. Whether a given PDP also adjudicates the context is a property of that deployment and is not something this profile guarantees. Stating that boundary is what keeps the design rule above from overpromising.¶
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.¶
This document uses the terms Authorization Server, Client, Resource Server, access token, and scope from [RFC6749]; Policy Decision Point (PDP), Policy Enforcement Point (PEP), Subject, Action, Resource, and Context from [AUTHZEN].¶
The audience of the access being granted - the party the issued token
authorizes its bearer to act against. Usually the value the AS intends for
the token's aud claim.¶
An evaluation request whose action expresses issuance authority - whether the subject may obtain a token of a given type for the issuance target. See Section 5.3.¶
An evaluation request whose action is a requested scope, expressing access authority. See Section 5.3.¶
+--------+ +----------------------+ +-------+
| Client | | Authorization Server | | PDP |
+---+----+ | (PEP) | +---+---+
| +----------+-----------+ |
| 1. token req | |
+-------------------------->| |
| | 2. authn client, |
| | validate grant |
| | |
| | 3. evaluation request |
| +----------------------->|
| | |
| | 4. decision + shaping |
| |<-----------------------+
| | |
| | 5. mint per decision |
| | and shaping |
| 6. token response | |
|<--------------------------+ |
¶
Step 2 is unchanged from the underlying grant: the AS remains solely responsible for authenticating the client, validating the grant or subject token, and verifying any proof of possession. The PDP is consulted only after those checks succeed. A PDP permit does not substitute for any of them.¶
A token endpoint can be a very high volume path. Multi-tenant authorization servers operate at request rates that leave a per-request budget in the low milliseconds, and an issuance decision that added a round trip to a remote service would not be deployable at that scale.¶
This profile does not add one. [AUTHZEN] specifies a request and response contract between a Policy Enforcement Point and a Policy Decision Point; it does not specify where the Policy Decision Point runs. The PDP of Section 3 may be embedded in the authorization server's own process, loaded as a module or as a WebAssembly component, resident on the same host, or reached over a network. Conformance to this profile is a property of the messages exchanged and not of the topology that carries them, and deployments with the strictest budgets are expected to evaluate in process or on the same host. Step 3 of Section 3 is drawn as an arrow because it is a request, not because it is a hop.¶
Two properties of the issuance moment make the budget more forgiving than the volume alone suggests.¶
The decision is made once per token rather than once per request. An access token is presented many times, over a lifetime usually measured in minutes or hours, so the cost of deciding at issuance is amortized across every later presentation. This is the reverse of the resource server deployments [AUTHZEN] was first written for, where the decision recurs on every call and the budget is correspondingly tighter.¶
The inputs are already in hand. By the time an AS reaches this decision it has authenticated the client, validated the grant, and resolved the subject. The evaluation request of Section 5 is assembled from values the AS already holds, and this profile implies no additional lookup to construct it.¶
Some issuance decisions cannot complete within the time a token request will wait, at any topology. A policy may call for human review, for an out-of-band approval, or for a check against a system whose own latency is unbounded.¶
This document defines no mechanism for those, and does not need to. [I-D.gerber-oauth-deferred-token-response] defines a deferred token response, in which an authorization server that cannot answer immediately returns a deferral code and the client retrieves the outcome later. An AS implementing both may treat a decision it cannot obtain synchronously as a deferral rather than as a denial, evaluate it out of band, and apply the response of Section 6 to the token it eventually issues. Delay does not relax Section 6.3: a decision that arrives late constrains the issued token exactly as one that arrives promptly would.¶
Section 3 separates validating a grant from deciding whether to honor it, and asks a PDP only the second question. In a deployed authorization server that separation is often less clean than the figure. Credential handling, grant validation, session and consent state, and token minting are commonly one subsystem, with the inputs this profile needs distributed across it rather than exposed at any single point.¶
The consequence is practical rather than normative. An authorization server that cannot assemble the fields of Section 5 at one point in its issuance path will have to introduce such a point, and for many implementations that will be the substantive work rather than the mapping or the response handling. This profile is defined in terms of the values an AS holds when it makes the decision, not in terms of where an implementation keeps them, so it constrains neither the internal structure nor the refactoring.¶
subject identifies the party the issued token will represent.¶
subject.type MUST be one of the registered values in Section 12.3:¶
user - a natural person.¶
client - an OAuth client acting on its own behalf.¶
workload - a non-human software identity, such as a workload with a
cryptographic identity document.¶
subject.id MUST be the identifier the AS intends to place in the issued
token's subject claim. Where the AS applies a transformation to subject
identifiers - pairwise or pseudonymous identifiers, or a mapping from an
external identity to a local account - that transformation MUST be applied
before the evaluation request is constructed, so that the identifier the
PDP authorizes is the identifier the token carries.¶
resource.type MUST be audience. resource.id MUST be the issuance
target.¶
A single registered type is used rather than a type per kind of target
(service, trust domain, peer authorization server) because the type names
the protocol role the target plays, not a guess at its nature. Policies
written against audience port across deployments; policies written against
locally invented type names do not.¶
Where the request carries an explicit target - an audience parameter, or a
resource parameter in the sense of [RFC8707] - that value determines
resource.id. Where it does not, the AS's default audience for the grant
determines it.¶
Token issuance asks two questions that are frequently conflated:¶
May this subject obtain a token of this kind for this target? This is issuance authority, and in delegation scenarios, delegation authority.¶
May this subject exercise this scope at this target? This is access authority.¶
These are distinct privileges. [RFC8693] defines a may_act claim
precisely because the authority to act on another party's behalf is not the
same as the authority to access a resource. A subject may legitimately be
permitted to hold an access token for an API while being forbidden from
minting a delegated grant aimed at that same API.¶
Because AuthZEN's information model provides exactly one action per
evaluation, these two questions MUST be expressed as separate evaluations
rather than as two interpretations of one action.name.¶
A gate tuple is an evaluation whose action.name has three colon-separated
segments:¶
issue:<token-type>:<grant-type>¶
where <token-type> and <grant-type> are short names registered in
Section 12.4 - for example issue:access_token:authorization_code,
issue:id_token:authorization_code, issue:refresh_token:token_exchange.¶
The issue: prefix is reserved. A deployment MUST NOT use a scope value
beginning with issue: as a scope tuple action.¶
The grant is part of the action because it is not recoverable from the rest of the tuple and it is not implied by the token type. The same subject, audience, and token type arise from an authorization code request and from its later refresh, and from a client requesting a token for itself and that same client exchanging for one. A policy that distinguishes those cases - requiring fresh authorization at a high-value audience, or permitting a client to hold a token but not to exchange for one - has nothing to attach to unless the grant is in the five-tuple.¶
Neither segment subsumes the other. A single authorization code request may
mint an access token, a refresh token, and an ID token, which are separately
gateable; and a token exchange selects its output through
requested_token_type, so its token type is a variable of the request.
Together the two segments name one privilege: what may be minted, and by
what means.¶
Short names registered under Section 12.4 MUST match
[a-z][a-z0-9_]{0,30}, and a composed gate action name MUST NOT exceed 50
characters.¶
The bounds exist for portability. Relationship-based engines commonly
validate relation identifiers against a restricted grammar, admitting a small
character set within a modest length limit. A PDP built on such an engine can
canonicalize an action name defined by this document by replacing each :
with a character the grammar admits, conventionally _. The bounds above are
what make that transformation total: any registered name survives it, so a
policy written against these names ports without being rewritten.¶
Carrying a grant type URI verbatim would not survive it. The composed action name would exceed the length limits such grammars impose before any question of characters arose.¶
The guarantee covers only the vocabulary this document defines. Scope values are carried verbatim (Section 5.3.3) and routinely contain characters no such grammar admits; mapping them remains internal to the PDP.¶
A scope tuple is an evaluation whose action.name is a single requested
scope value, carried verbatim.¶
Scope values are not transformed into policy-engine relation names by the
AS. Any such mapping is internal to the PDP. This keeps action.name a
stable interface: the AS reports what the client asked for, and the PDP
decides what that means in its own policy vocabulary.¶
An AS MUST include a gate tuple in every evaluation request it forms under this profile. A binding MAY require more than one (Section 5.5).¶
The floor is therefore two evaluations for a request naming scopes, and one for a request naming none. Deployments are expected to write issuance policy for every token type and grant combination their AS can produce; a PDP that advertises support for this profile renders a decision on any registered gate action it is sent (Section 7.1), so an AS never has to predict which combinations a given PDP has policy for.¶
The context object carries advisory input. A conforming PDP MUST be able
to render a decision without it.¶
The following keys are defined by this document; bindings may define more:¶
| Key | Type | Value |
|---|---|---|
client_id
|
string | The authenticated client identifier |
acr
|
string | Authentication context class of the subject |
amr
|
array of strings | Authentication methods, per [RFC8176] |
auth_time
|
integer | Time of authentication, as in [RFC7519] |
cnf
|
object | Confirmation method of the presented credential |
The single-type rule of Section 6.1 applies here as well: each key above has one JSON type, and bindings defining further context keys MUST state a type for each.¶
Per Section 1.1, any input on which the decision genuinely depends
belongs in the five-tuple, not here. The grant type is the worked example:
it is decision-critical, so it is a segment of the gate action name
(Section 5.3.1) and does not appear in context at all.¶
Where a request yields more than one tuple, the AS MUST use the Access
Evaluations API of [AUTHZEN] with options.evaluations_semantic set to
execute_all, and MUST place gate tuples at the leading indices of the
evaluations array, beginning at index 0.¶
A request reduces to a single evaluation only when it names no scopes, in which case the gate tuple stands alone.¶
This document produces exactly one gate tuple. Bindings may produce more: the token exchange family evaluates the authority of the requesting party separately from that of the subject, and so produces two.¶
execute_all is required because scope denials must be able to narrow the
grant rather than fail it: an AS that requested three scopes and received
two permits issues a token bearing two scopes, and reports the reduced set
in the scope response parameter as [RFC6749] already requires.¶
A gate denial, by contrast, is fatal. If any leading gate tuple has a
decision of false, the AS MUST fail the request and MUST NOT issue a
token, irrespective of the other results.¶
[AUTHZEN] evaluation semantics are selected per request and cannot mark an individual batch item as a precondition, so this composition rule is enforced by the AS. This is well within the PEP's role - the AS is already interpreting per-item results in order to downscope.¶
Where the request named scopes and every scope tuple is denied, the AS MUST fail the request rather than issue a token with an empty scope set, even though the gate permitted it. A permitted gate authorizes a token of that kind to exist; it does not authorize an empty one.¶
A PDP MAY return, in the response context, information that shapes the
token the AS issues.¶
issuance Envelope
All keys defined by this profile appear within a single issuance member of
the response context:¶
{
"decision": true,
"context": {
"reason_admin": { "200": "matched policy P-4471" },
"issuance": {
"token_lifetime": 300,
"claims": { "groups": ["engineering"] }
}
}
}
¶
An AS implementing this profile MUST process context.issuance and MUST
ignore unrecognized members outside it, preserving the advisory character
that [AUTHZEN] gives response context generally.¶
Every key defined below has exactly one JSON type, and bindings that define
further keys MUST do the same. Where the corresponding OAuth or JWT
construct admits more than one - aud is the notable case, per Section
4.1.3 of [RFC7519] - this profile picks one rather than carrying the
polymorphism forward. An AS validates the response context before acting on
it, and a union type costs more to validate, to schematize, and to project
into a typed representation than the shorthand saves.¶
[AUTHZEN], in the definitions of the decision values in its Decision
section, states that where a PEP does not understand information in the
response context, the PEP MAY reject the decision. That permission is
appropriate for a general-purpose API in which response context is advisory.
It is not sufficient here, because the consequences are asymmetric:¶
Ignoring a key that narrows the grant yields a token broader than the PDP authorized - a silent privilege escalation.¶
Ignoring a key that adds information yields a token narrower than intended - a functional shortfall, not a security failure.¶
This profile therefore adopts the following rule, from which the treatment of every key below is derived:¶
A response-context key is mandatory-to-understand if and only if ignoring it would produce a token broader than the PDP authorized. For such keys, an AS that does not understand and apply the key MUST treat the permit as a denial.¶
A PDP MUST NOT return a shaping value that grants access the AS would not otherwise have granted, and an AS MUST reject a decision that attempts it.¶
The PDP decides whether and how much; it does not decide what else. Without
this rule, an evaluation of files.read could return a token bearing
admin, and the token would assert a privilege no evaluation ever
considered.¶
The keys in this section are mandatory-to-understand under Section 6.2.¶
granted_scope
A space-delimited string in the syntax of the scope parameter of
[RFC6749], giving the scope set the AS is authorized to grant.¶
granted_scope MUST be a subset of the scopes the AS would otherwise have
granted - the requested scopes, or for a request naming none, the AS's
default set for that client and target. The AS MUST reject the decision
otherwise.¶
Its principal use is the gate-only evaluation, where there are no scope tuples and this key is how a PDP answers "permit, and grant this set." Enumerating a grantable set is a search operation rather than a check; a PDP unable to perform it returns a bare permit and the AS falls back to its own defaults, which is a safe degradation.¶
Where scope tuples are present, the per-item decisions already express
downscoping, and a PDP SHOULD NOT also return granted_scope.¶
token_lifetime
A non-negative integer number of seconds, interpreted as a ceiling. The AS MUST issue a token whose lifetime is the lesser of this value and the lifetime it would otherwise have used. It is never a floor: a PDP cannot extend a token's life beyond the AS's own policy.¶
A value of 0 MUST be treated as a denial rather than as an instruction to
mint an already-expired token.¶
audience
An array of strings, narrowing the set of targets for which the token may be
issued. Each value MUST appear among the resource.id values of the
permitted evaluations.¶
The value is an array even when it names a single target. This is the key
where the single-type rule above is most visible, and where it also makes
the aggregation rule of Section 6.6 state plainly: intersection is an
operation over sets. An AS remains free to render a single-element set as a
bare string in the token's own aud claim, where [RFC7519] permits it.¶
Where the resulting set is empty, the AS MUST fail the request; for token
exchange requests the appropriate error is invalid_target ([RFC8693]).¶
crit
An array of strings naming members of claims (Section 6.5.1) that are
themselves mandatory-to-understand. The name and semantics are taken from
the crit header parameter of [RFC7515]: an AS that does not understand
and apply a named member MUST treat the permit as a denial.¶
crit exists because the static classification in this section is
incomplete. An additive claim is normally safe to ignore, except where the
claim is a constraint that a downstream enforcement point is expected to
apply - a ceiling asserted by policy, for instance. Dropping such a claim
broadens what the token effectively authorizes.¶
A PDP MUST NOT include crit unless the AS has declared support for the
corresponding capability (Section 7).¶
claims
An object whose members are claim names, in the sense of [RFC7519], and the values to be included in the issued token. This is the mechanism by which policy-derived attributes reach the token - group memberships, roles, and entitlements of the kind [RFC9068] describes for JWT access tokens, drawn from the schema of [RFC7643].¶
Members of claims are advisory under Section 6.2: an AS that drops them issues
a less capable token. A PDP that requires a member to be honored MUST name
it in crit.¶
A PDP MUST NOT set, and an AS MUST reject a response that sets, any of the following claims:¶
| Reserved | Rationale |
|---|---|
iss, iat, jti
|
Provenance, for which the AS is authoritative |
sub
|
It is subject.id, an input to the decision |
aud
|
It is resource.id, an input to the decision |
exp, nbf
|
Expressed by token_lifetime
|
scope
|
Expressed by granted_scope
|
client_id
|
Established by client authentication |
cnf
|
Derived from a proof of possession the AS verified |
act
|
Delegation chain, constructed by the AS |
authorization_details
|
Has its own key and narrowing rules |
may_act
|
Confers future delegation authority; broadening by construction |
The entries for sub and aud rest on stronger ground than the rest. Both
are inputs to the five-tuple; a PDP that could rewrite either would cause the
AS to issue a token corresponding to a decision that was never evaluated.
Re-subjecting a token is a fresh issuance, not an attenuation of an existing
one, and MUST be evaluated as such.¶
An Access Evaluations response in [AUTHZEN] carries no top-level context;
each element of the evaluations array is a decision with its own optional
context. Token shaping, however, is a property of the token: there is one
lifetime, one claim set, one authorization details array for the token being
minted, while this profile fans scopes and targets out across many
evaluations.¶
An AS MUST therefore compose per-item shaping as follows:¶
| Key | Aggregation |
|---|---|
token_lifetime
|
Minimum over permitted items |
granted_scope
|
Union over permitted items, intersected with what the AS would otherwise grant |
audience
|
Intersection over permitted items |
authorization_details
|
Union of entries, then the per-entry structural check |
claims
|
Merge; see below |
crit
|
Union |
Shaping keys appearing in the context of a denied item MUST be ignored.¶
Where two permitted items return different values for the same member of
claims, the AS MUST reject the decision. There is no general narrowing
merge for arbitrary JSON values, and choosing one arbitrarily could
broaden the result. Identical values are not a conflict. A PDP SHOULD return
token-level shaping on a single item to avoid the situation.¶
A PDP supporting this profile MUST advertise the capability URN registered
in Section 12.2 in the capabilities member of its metadata document,
retrievable at /.well-known/authzen-configuration:¶
{
"policy_decision_point": "https://pdp.example.com",
"access_evaluation_endpoint":
"https://pdp.example.com/access/v1/evaluation",
"access_evaluations_endpoint":
"https://pdp.example.com/access/v1/evaluations",
"capabilities": [
"urn:ietf:params:authzen:token-issuance"
]
}
¶
The URN asserts support for the request mapping and response vocabulary of
this document. It is not a statement about the content of the PDP's policy,
and a PDP MUST NOT be read as claiming to hold rules for any particular
issuance. What a deployment's policy permits is disclosed only through
decisions. This is the same line
[I-D.ietf-oauth-identity-assertion-authz-grant] draws for
authorization_grant_profiles_supported, which indicates that a server
implements a profile's processing rules and not that any particular issuer,
client, subject, or audience will be accepted.¶
Advertising the capability is accordingly a commitment to the request shapes this profile can produce. A PDP that advertises it MUST render a decision for a gate tuple naming any action name composable from the short names registered in Section 12.4, and MUST NOT reject the evaluation on the grounds that it holds no policy for that action. Denying is a decision; a protocol error is not. The same applies to a batch that mixes a gate tuple with scope tuples, which is the ordinary shape of a request naming scopes (Section 5.5).¶
The obligation matters because the gate vocabulary is a product of two registries and grows as bindings register short names. An AS pairs the token type it is about to mint with the grant it received; it cannot know which pairings a given deployment's policy anticipated, and must not have to.¶
For the same reason, this profile defines one capability URN rather than one per token type and grant combination. Finer granularity would oblige the AS to predict what the PDP has policy for, which the rule above exists to avoid, and would publish the shape of a deployment's issuance policy in an unauthenticated metadata document. Capability granularity in this profile tracks vocabulary, not policy. An extension that adds response vocabulary registers its own URN, since an AS must understand what it is asked to enforce; one that adds only advisory context keys or new registered action names does not, since a PDP ignores a context key it does not recognize and the rule above already obliges it to decide any registered gate action.¶
An operator enabling a new grant or token type nonetheless has a real
question to answer: whether the deployment's policy anticipates the gate
actions the AS is about to start sending, or whether every such request will
be denied. That question is about policy content, so its answer belongs on
the authenticated evaluation surface rather than in metadata; [AUTHZEN]
notes that an unauthenticated PDP can be probed for the shape of its policy.
The Action Search API of [AUTHZEN] answers it directly: a search for a
representative subject and an audience resource returns the action names
policy would permit, and gate actions among them indicate the issuances the
deployment is prepared for. This is a deployment-time check, not a
per-request one, and nothing in this profile requires it.¶
An AS MAY declare the capabilities it understands in the request context, using the same URNs:¶
{
"subject": { "type": "user", "id": "U0405936" },
"action": { "name": "issue:access_token:authorization_code" },
"resource": {
"type": "audience",
"id": "https://api.example/files"
},
"context": {
"issuance": {
"capabilities": [
"urn:ietf:params:authzen:token-issuance"
]
}
}
}
¶
Capability URNs are reused on both legs rather than introducing a list of key names, so that extensions obtain granularity from the registry rather than from a second, parallel mechanism.¶
The declaration is an optimization, not a safety mechanism, and this is why
it is OPTIONAL. Safety is already unilateral: a PDP that marks a key crit
obliges any AS implementing this profile to fail closed if it does not
understand it (Section 6.2), and an AS that does not implement this profile
ignores the issuance envelope entirely, crit included. Withholding crit
from an undeclared AS therefore protects nothing. What the declaration buys a
PDP is the ability to choose a decision the AS can actually enforce -
denying, say, rather than permitting subject to a constraint it knows will be
discarded. That is worth having as extensions add vocabulary, and worth
nothing in a deployment using only the keys defined here.¶
An AS is not otherwise required to announce itself. The behaviors this profile depends on - treating a gate denial as fatal, narrowing to the permitted scope subset - are constitutive of implementing it rather than features an AS might separately lack, and [AUTHZEN] already assumes a PDP trusts its PEP to enforce what it decides.¶
The declaration describes the AS's implementation and MUST NOT be treated as an authorization input. A PDP that varied its decision based on it would be allowing a property of the enforcement point to influence policy.¶
| Condition | Authorization server behavior |
|---|---|
| Gate tuple denied | Fail the request; do not issue |
| All scope tuples denied | Fail the request; invalid_scope
|
| Some scope tuples denied | Issue with the permitted subset; report via scope
|
| Target denied or empty audience set |
invalid_target ([RFC8693]) |
| Shaping key violates Section 6.3 | Treat as denial; fail the request |
Unknown crit member |
Treat as denial; fail the request |
| PDP unreachable or malformed response | Fail closed; do not issue |
Reason information returned by a PDP is diagnostic and intended for the operator of the AS. An AS MUST NOT relay PDP reason strings to the client, as they may disclose policy structure to a party that is not authorized to learn it.¶
Where a PDP returns a denial accompanied by authentication requirements -
the step-up pattern of [AUTHZEN], in which the required acr and amr
values are named - an AS SHOULD surface the requirement to the client. This
document does not define that mapping, and neither end of it is presently
specified. [AUTHZEN] illustrates the pattern in a non-normative example
rather than defining the response context keys that carry it, leaving a
profile nothing normative to reference; and on the OAuth side,
insufficient_user_authentication in [RFC9470] is defined for resource
servers rather than for the token endpoint, where no equivalent signal
exists. This is an open item, and closing it requires work in both
specifications.¶
The first example below is shown in full, framed against the HTTPS JSON binding of [AUTHZEN]. The remaining examples show only the JSON payload.¶
The transport is a property of the deployment, not of this profile: an
evaluation carrying the mapping defined here is the same evaluation whatever
binding conveys it. Where the HTTPS JSON binding is in use, the request URL
is the PDP's access_evaluations_endpoint, or access_evaluation_endpoint
for a request that reduces to a single evaluation, as published in the PDP's
metadata; the paths shown below are the defaults that apply when metadata
provides no value.¶
One scope is requested, so the request is the gate tuple and one scope tuple. This is the floor: two evaluations, so the Access Evaluations API.¶
No scopes and no default set, so the gate tuple stands alone. This is the
only shape this document produces that is a single evaluation, and it is
therefore the only one sent to the Access Evaluation API rather than the
Access Evaluations API: the payload is a bare evaluation with no
evaluations array, and under the HTTPS JSON binding it is a POST to
/access/v1/evaluation.¶
{
"subject": { "type": "client", "id": "svc-reporting" },
"action": {
"name": "issue:access_token:client_credentials"
},
"resource": {
"type": "audience",
"id": "https://telemetry.example"
},
"context": {
"issuance": {
"capabilities": [
"urn:ietf:params:authzen:token-issuance"
]
}
}
}
¶
{
"decision": true,
"context": {
"issuance": {
"granted_scope": "telemetry.write",
"token_lifetime": 900
}
}
}
¶
This document defines the mapping and the shaping vocabulary, and registers short names for the grant types listed in Section 12.4. For a grant whose request names a single party and a single target, that is everything an AS needs; the client credentials and authorization code examples above are complete, and no companion document is required to implement them.¶
A binding is required where a grant family adds structure this document does not model. The token exchange family adds two such things: a request names a second party, the requesting party, whose authority is separately at stake; and several of its members issue an artifact whose own audience differs from the audience of the access it describes. Bindings are therefore expected for that family - including identity chaining, identity assertion authorization grants, and transaction tokens - and a profile describing the use of AuthZEN search operations to populate the authorization claims of [RFC9068].¶
Bindings specify the subject derivation for their grant, any additional context keys, the token type short names they register, and any invariants of their own that a PDP cannot override.¶
Every failure of the profile - an unreachable PDP, a malformed response, a
shaping value that violates Section 6.3, an unrecognized crit
member - MUST result in no token being issued. A PDP that cannot be
consulted is not an authorization to proceed.¶
Because the PDP is on the token issuance path, its availability becomes the AS's availability. Deployments should consider caching of decisions, local policy fallback that is explicitly configured rather than implicit, and the latency budget of the token endpoint.¶
A PDP that can shape tokens can narrow every grant an AS issues, and a
compromised PDP can deny service. The constraints in this document bound the
damage in the other direction: because no shaping key may broaden a grant,
because sub, aud, and cnf are reserved, and because the AS validates
every constraining key before applying it, a compromised PDP cannot cause an
AS to issue a token for a different subject, aimed at a different audience,
bound to a different key, or bearing a privilege that no evaluation
considered.¶
This is why the reservations in Section 6.5.1 are normative rather than advisory. An implementation that passed PDP-supplied claims into a token without checking them against that list would give the PDP the ability to mint arbitrary identities.¶
The crit mechanism relies on the response arriving intact. An attacker
able to strip crit from a response is also able to change decision to
true, so crit does not extend the attack surface beyond what transport
protection between the AS and the PDP must already cover. It is not a
substitute for that protection, and deployments requiring non-repudiation of
decisions should use the response signing mechanisms of [AUTHZEN].¶
Evaluation requests carry subject identifiers, client identifiers, targets, and authentication context to the PDP, and do so on every token issuance. Where the PDP is operated by a party other than the operator of the AS, this is a disclosure of authentication and access patterns for every user of the system.¶
Requiring that identifier transformations be applied before the request is constructed (Section 5.1) means that a PDP receiving pairwise or pseudonymous identifiers sees only the identifier the token itself will carry, rather than a durable global identifier. Deployments sensitive to this should prefer such identifiers.¶
Where context conveys authentication context or device posture, deployments
should include only what their policies actually consume. The design rule of
Section 1.1 already bounds how much that ought to be.¶
The registrations requested by this document fall into two groups with different dependency properties, described in Section 12.1.¶
The capability registration in Section 12.2 is an entry in a registry established by another body's specification, and inherits that registry's state. The two registries created in Section 12.3 and Section 12.4 are new registries created by this document, and have no such dependency.¶
[AUTHZEN] Section 12 asks IANA for two things: an authzen sub-namespace of
urn:ietf:params under [RFC3553], and an "AuthZEN Policy Decision Point
Capabilities" registry whose entries are named as URNs within that
sub-namespace. At the time of writing, neither appears in the IANA registries.
The urn:ietf:params sub-namespace registry has a registration policy of IETF
Review [RFC6924], which a specification published outside the IETF stream
cannot satisfy on its own.¶
This document is on the IETF stream, and therefore can. Three resolutions are available, and the choice is for the working group:¶
This document, or a companion document, performs the [RFC3553]
registration of the authzen sub-namespace, satisfying IETF Review. The
capability name then takes the form given in Section 12.2.¶
The capability is named in the urn:openid:authzen namespace rather than
under urn:ietf:params, and no IANA action is requested for it. [ARAP]
takes this route, naming its capability
urn:openid:authzen:capability:access-request and its error conditions
under urn:openid:authzen:access-request:error, so this is the scheme
AuthZEN profiles use in practice. The capability name would be
urn:openid:authzen:capability:token-issuance.¶
This document declines the dependency and registers its capability under
urn:ietf:params:oauth, the sub-namespace established by [RFC6755],
whose registration policy is Specification Required and is therefore not
blocked. The capability name would be
urn:ietf:params:oauth:authzen-capability:token-issuance.¶
A capability identifier is only useful if both parties compute the same string, so one naming scheme for all AuthZEN capabilities is worth more than this document's independence from any particular one. Options 1 and 2 both achieve that, and differ in which body assigns the name; option 2 has the advantage of matching what AuthZEN profiles already do, at the cost of leaving the registry [AUTHZEN] asks for without entries. Option 3 is the fallback if neither is available.¶
IANA is requested to register the following in the "AuthZEN Policy Decision Point Capabilities" registry established by [AUTHZEN], subject to Section 12.1:¶
:token-issuance¶
urn:ietf:params:authzen:token-issuance¶
Support for the OAuth 2.0 token issuance profile, comprising the request
mapping and the issuance response context vocabulary.¶
IETF¶
This document¶
IANA is requested to establish the "OAuth Token Issuance Authorization Entity Types" registry, with a registration policy of Specification Required [RFC8126], containing the following initial entries:¶
| Type | Applies to | Description |
|---|---|---|
user
|
subject | A natural person |
client
|
subject | An OAuth client acting on its own behalf |
workload
|
subject | A non-human software identity |
audience
|
resource | The audience of the access being granted |
IANA is requested to establish the "OAuth Token Issuance Authorization
Action Names" registry, with a registration policy of Specification Required
[RFC8126], for the two short-name vocabularies from which action names in
the reserved issue: space are composed.¶
A gate action name is issue:<token-type>:<grant-type>, so the registry
grows with the number of token types plus the number of grant types, not
with their product. The combinations that are meaningful in a deployment are
a matter of policy, not of registration.¶
Every short name MUST match [a-z][a-z0-9_]{0,30}, and a composed action
name MUST NOT exceed 50 characters. Section 5.3.2 gives the reason:
these bounds are what let the name be transformed mechanically into a
relation identifier that relationship-based engines accept. Registrants
should note that the hyphen is excluded deliberately, and that a short name
therefore differs from the corresponding URI wherever that URI contains one.¶
Token type short names, initially:¶
| Short name | Token type |
|---|---|
access_token
|
urn:ietf:params:oauth:token-type:access_token
|
refresh_token
|
urn:ietf:params:oauth:token-type:refresh_token
|
id_token
|
urn:ietf:params:oauth:token-type:id_token
|
Grant type short names, initially:¶
| Short name | Grant type |
|---|---|
authorization_code
|
authorization_code
|
client_credentials
|
client_credentials
|
refresh_token
|
refresh_token
|
token_exchange
|
urn:ietf:params:oauth:grant-type:token-exchange
|
device_code
|
urn:ietf:params:oauth:grant-type:device_code
|
jwt_bearer
|
urn:ietf:params:oauth:grant-type:jwt-bearer
|
saml2_bearer
|
urn:ietf:params:oauth:grant-type:saml2-bearer
|
Registrations MUST give the URI or parameter value the short name
corresponds to, and MUST state which of the two vocabularies they join.
Names outside the issue: prefix are not registered here, since scope
values are carried verbatim and are not a registered vocabulary.¶
This work was motivated in part by Karl McGuinness, whose initiative to bridge OAuth and AuthZEN - in [ARAP] and its OAuth completion mode - established that a Policy Decision Point belongs behind the token endpoint, and that the response of such a Policy Decision Point may legitimately shape what is issued. This document takes up the other half of that decision.¶
Thanks also to the participants in the OpenID AuthZEN interoperability events, whose December 2025 identity provider scenario demonstrated AuthZEN search operations populating token claims, and to the members of the AuthZEN Working Group and the OAuth Working Group.¶