| Internet-Draft | OAuth Mission Status | August 2026 |
| McGuinness | Expires 22 February 2027 | [Page] |
The Mission-Bound Authorization for OAuth 2.0 profile binds issued
authority to a durable, human-approved Mission and gates issuance on
Mission state, but it observes Mission state only through token lifetime
and optional token introspection. This document
defines the Mission state-management surfaces it defers: the Mission
Status operation (keyed by mission_id) with signed responses, the
Mission projection for token introspection, the Mission Lifecycle
endpoint with revoke, suspend, resume, complete, and discharge
operations, the suspended and completed states with the consolidated
lifecycle state machine this profile owns, and revocation-propagation
guidance.
It also defines Mission completion at the entry grain: terminal_when,
a completion condition met when an authenticated discharge command or
trusted deployment-internal adjudication commits that the task an entry
was granted for is done.
Each capability is independently optional; an implementation can adopt
any subset, and one that adopts none remains a conforming issuance
profile.¶
This note is to be removed before publishing as an RFC.¶
The latest revision of this draft can be found at https://mcguinness.github.io/mission-bound-authorization/draft-mcguinness-oauth-mission-status.html. Status information for this document may be found at https://datatracker.ietf.org/doc/draft-mcguinness-oauth-mission-status/.¶
Source for this draft and an issue tracker can be found at https://github.com/mcguinness/mission-bound-authorization.¶
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 22 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.¶
The issuance profile [I-D.draft-mcguinness-oauth-mission] makes a
Mission a first-class OAuth artifact: a structured, human-approved,
integrity-bound task whose authority bounds and outlives every token
an agent derives. It is, by design, a minimum-viable issuance layer.
It gates derivation on Mission state, carries the mission claim on
every derived token, and offers only OPTIONAL token introspection
([I-D.draft-mcguinness-oauth-mission], Section "Mission State via
Token Introspection") as a way for a Resource Server to observe
Mission state. It names this profile for the canonical Mission Status
surface (keyed by mission_id) and its signed status evidence, and
defers a standardized management endpoint for lifecycle transitions to
this document.¶
This document specifies those surfaces as optional extensions that build on the issuance profile. The capabilities are:¶
A dedicated Mission Status operation
(Section 3), which any consumer holding a mission_id
resolves, with responses signed as a JWS [RFC7515].¶
An extension to OAuth token introspection that carries a Mission projection, which a deployment MAY return as a [RFC9701]-signed response (Section 4).¶
A Mission Lifecycle endpoint (Section 6)
for explicit revoke, suspend, resume, complete, and
discharge operations, distinct from [RFC7009] token revocation.¶
Mission completion and entry discharge (Section 7): the
terminal_when completion condition, carried in a
mission_resource_access entry's constraints, and the
authenticated discharge operation (Section 6.2) that
commits it once the task the entry was granted for is done.¶
Revocation propagation guidance
(Section 8): a mission_max_stale_seconds
bound and how to size token lifetimes to the propagation mechanisms
in use.¶
Authorization Server metadata members (Section 9) advertising the endpoints above.¶
Each capability is independently optional. An implementation states which it supports through the metadata of Section 9 and the conformance language of Section 10. An implementation that supports none of them is unaffected and remains a conforming issuance profile.¶
This document does not restate the issuance profile. The Mission Intent,
authority derivation, the mission_resource_access authorization
details type, the mission claim, the integrity anchors, Mission-bound
token issuance, the subset rule, and lifecycle gating are all defined
in [I-D.draft-mcguinness-oauth-mission] and are referenced, not
re-specified, here.¶
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 defined in the issuance profile
[I-D.draft-mcguinness-oauth-mission], in particular Mission,
Mission Issuer (the Mission issuer: in this document's OAuth binding
the Authorization Server; a standalone Mission Issuer, the Mission
Authority Server [I-D.draft-mcguinness-mission-authority-server],
serves these surfaces with the same semantics; the AAuth Person
Server plays the same role for its native missions through its own
AAuth-native management surface
[I-D.draft-mcguinness-mission-aauth]), Authority Set, the
mission claim, mission_id, and the mission_resource_access
authorization details type. Resource AS is used as defined in the
cross-domain companion
[I-D.draft-mcguinness-oauth-mission-cross-domain]. It additionally
uses:¶
A signed payload returned by the dedicated Mission Status operation (Section 3), reporting a Mission's current state and the audience-scoped evidence a consumer needs.¶
The state of a mission_resource_access entry whose terminal_when
completion condition has been met (Section 7). A discharged
entry's authority is spent: it is no longer derivable.¶
The approved Authority Set after applying every issuer-held, monotonic narrowing mechanism the deployment runs. This profile contributes discharged entries (Section 7.3). Each other narrowing profile defines its own subtraction. No narrowing mechanism adds or restores authority. Membership in this set is necessary, never sufficient, for an action to proceed: the runtime decision evaluates it alongside every other required decision input ([I-D.draft-mcguinness-mission-runtime]).¶
All JSON shown in this document is non-normative and illustrative; the member definitions in the surrounding text are authoritative. HTTP message examples follow the conventions of [RFC9110]; long URLs and form parameters are wrapped for display. JWT and JWS examples are shown as decoded JSON with separate header objects; on the wire the JWS Compact Serialization [RFC7515] applies.¶
This section is OPTIONAL. The issuance profile's stateless baseline needs no dedicated status surface ([I-D.draft-mcguinness-oauth-mission], Section "Mission Lifecycle and Gating"); a deployment that does not stand up this operation, and a consumer that does not use it, are unaffected.¶
The dedicated Mission Status operation is the canonical status surface
the issuance profile defers. Unlike token introspection
(Section 4), which answers "is this
token's authorization still good," the Mission Status operation answers
"what is the state of this Mission" keyed by the mission_id alone. Any
consumer holding a mission_id (including an auditor or a
cross-domain Resource AS) resolves it without holding a token the AS
issued.¶
The Mission Issuer publishes its Mission Status endpoint URL in
Authorization Server metadata (Section 9) as
mission_status_endpoint, which a consumer resolves from a
credential's mission.issuer. The endpoint MUST be served over TLS
1.2 or later (TLS 1.3 RECOMMENDED), following the recommendations of
[RFC9325].¶
The request is an HTTPS POST with an
application/x-www-form-urlencoded body containing:¶
mission_id:REQUIRED. A string. The canonical Mission Identifier, named per the issuance profile's external-surface convention ([I-D.draft-mcguinness-oauth-mission]).¶
audience:CONDITIONAL. A string. The audience identifier of the
requesting consumer. An authorized non-RS consumer (for example an
auditor or a cross-domain Resource AS) that needs only Mission state,
not audience-scoped authority, MAY omit audience; the response is
then state-only and carries no authorization_details
(Section 3.4). A Resource Server resolving authority
for a specific audience MUST send it.¶
nonce:REQUIRED. A string. A client-generated nonce binding the
response to this request. It MUST be unique per request within the
response lifetime. A consumer MUST reject a response whose nonce
does not equal the one it sent. This is a standard client challenge:
echoing it in the signed response anti-replay-binds that response to
this specific request.¶
The request MUST be authenticated. The AS MUST support at least one of the following mechanisms. The client MUST use exactly one of them per request:¶
mTLS client authentication [RFC8705]. The AS validates the
client's X.509 certificate against its configured trust anchors and
the client's registered tls_client_auth metadata.¶
Sender-constrained access token. The client presents a
mission_status-scoped access token (see the authorization
requirement below) in the Authorization header, sender-constrained
either by DPoP [RFC9449] (the DPoP scheme with a DPoP proof
header, the token's cnf.jkt matching the proof key thumbprint) or
by mTLS [RFC8705] (a certificate-bound token, the Bearer scheme,
whose cnf.x5t#S256 matches the presented client certificate). The
token MUST be audience-restricted to this endpoint's
protected-resource identifier (below).¶
Private-key-JWT client authentication [RFC7523]. The client
presents client_assertion_type with the exact value
urn:ietf:params:oauth:client-assertion-type:jwt-bearer and a signed
JWT as client_assertion. The assertion's aud MUST name the URL of
the endpoint being invoked (the mission_status_endpoint for a
Status request, the mission_lifecycle_endpoint for a Lifecycle
request), not the token endpoint; the AS MUST reject an assertion
whose aud names no such endpoint. The AS accepts only the JWS
[RFC7515] algorithms it advertises for that endpoint
(Section 9); none MUST NOT be used.¶
Plain Basic or POST client authentication MUST NOT be used for this
endpoint. The AS MUST refuse a request not authenticated by one of the
three mechanisms with unauthorized (HTTP 401). The mechanism is
determined by wire evidence in order: a request presenting an access
token in Authorization is mechanism 2, and any client certificate is
then evaluated only as that token's mTLS sender constraint; otherwise a
request presenting client_assertion is mechanism 3, and any client
certificate is not treated as client authentication; otherwise a request
presenting only a client certificate is mechanism 1. This order keeps
"exactly one mechanism" satisfiable when mTLS terminates at the edge.¶
An authenticated caller MUST additionally carry an explicit read
authorization: a mission_status scope on the presented access token,
or a deployment-defined equivalent grant bound to the authenticated
client. The mission_status scope authorizes the Mission Status read
operation and mirrors the mission_lifecycle scope of the Mission
Lifecycle endpoint (Section 6). The token-less
path is preserved: a consumer that holds only a mission_id and
authenticates directly as a client (mechanism 1 or 3) carries the
deployment-defined equivalent grant, not a scope, and so resolves
Mission state without holding an access token the AS issued. A caller
carrying no such authorization is refused with the not-found response
of Section 3.7 (Section 3.6).¶
A presented access token (mechanism 2) MUST be audience-restricted to
this endpoint's protected-resource identifier: the resource value the
AS publishes for this endpoint in its Protected Resource Metadata
[RFC9728]. For these surfaces that identifier is the endpoint's own URL
(the mission_status_endpoint or mission_lifecycle_endpoint), so the
mechanism-2 access-token audience and the mechanism-3 private-key-JWT
aud name the same value. The AS MUST reject a token whose audience does
not name that identifier. This token audience is distinct from the request body's
audience parameter (Section 3.1): the token audience
authorizes the call at this endpoint, whereas the request audience
carries no authentication weight and only selects the
Resource-Server-specific authority projection the response returns
(Section 3.4).¶
Which mechanisms and authorization this endpoint accepts are
discoverable per endpoint, not inferred from the token endpoint's
metadata. The AS advertises the methods this endpoint accepts in
mission_status_endpoint_auth_methods_supported (Section 9). For
the sender-constrained access-token path, this endpoint is an OAuth
protected resource: the AS publishes, in its Protected Resource Metadata
for this resource [RFC9728], the resource identifier the token's
audience MUST name, the mission_status scope it requires
(scopes_supported), and the presentation and sender constraints it
accepts (bearer_methods_supported, dpop_bound_access_tokens_required,
tls_client_certificate_bound_access_tokens). For the retained
direct-client-authentication path (mTLS [RFC8705] or private-key JWT
[RFC7523]), the accepted methods and, for private_key_jwt, the
accepted client-assertion signing algorithms are advertised for this
endpoint (Section 9), not read from the token endpoint's
token_endpoint_auth_methods_supported [RFC8414]. Both paths are
therefore discoverable.¶
On success the AS returns a JWS Compact Serialization [RFC7515]
signed with a key published in the AS's jwks_uri. The JWS header
carries typ of mission-status-response+jwt and a kid identifying
the signing key. Per [RFC7515] Section 4.1.9 the typ header omits
the application/ prefix; the full media type
application/mission-status-response+jwt (registered in Section 13) is
used as the HTTP Content-Type. Exact validation of the protected
typ value, together with mutually exclusive validation rules for
the artifact profiles, implements the substitution defense of
[RFC8725], Sections 3.11 and 3.12.¶
[RFC9701] signed introspection responses are scoped to token
introspection and do not apply to a lookup keyed by mission_id; the
dedicated Mission Status operation therefore uses a new media type and a
JWS, not [RFC9701] (see Section 11.4). Implementations
MUST NOT use [RFC9701] for the dedicated Mission Status operation.¶
The signed payload reports the Mission's current state and the audience-scoped evidence the consumer needs.¶
Decoded JWS header:¶
{
"alg": "ES256",
"kid": "sa-key-2026-q3",
"typ": "mission-status-response+jwt"
}
¶
Decoded JWS payload:¶
{
"iss": "https://as.example.com",
"aud": "https://erp.example.com",
"sub": "client_erp-recon-agent",
"nonce": "nonce_K9pV4nT2sR7mB1xQ",
"iat": 1793606400,
"exp": 1793606460,
"mission": {
"id": "msn_8RfX2Lqv9TqMv4z7sA2bN1k0YpEdHc9-",
"issuer": "https://as.example.com",
"authority_hash":
"sha-256:l3KvZ4mP5x0wQrR6tY2nD9bM7sX1cF8gH2vJ4kE5pNQ",
"state": "active",
"version": 4,
"expires_at": "2026-12-31T23:59:59Z",
"fresh_until": "2026-11-02T08:00:45Z"
},
"authorization_details": [
{ "type": "mission_resource_access",
"resource": "https://erp.example.com",
"actions": ["invoices.read", "journal-entries.write"] }
]
}
¶
The members are:¶
The signed JWT envelope iss, aud, sub, nonce, iat, exp.
The aud is the response's audience binding and the nonce its
request binding. When the request omitted audience
(Section 3.1), the response is state-only and the AS
MUST set aud to the authenticated requester's identifier, as the
Lifecycle endpoint does (Section 6); the
consumer's aud verification below then checks that identifier. exp bounds the validity of the signed response
itself; how long the consumer MAY rely on the reported state is
given separately by mission.fresh_until below.¶
mission: the mission object, the same shape as the mission
claim of [I-D.draft-mcguinness-oauth-mission] (Section "The
Mission Claim") with status members added. It carries:¶
id, issuer: the subject Mission's identifier and issuer.¶
authority_hash: the issuance profile's consent commitment over
the Authority Set ([I-D.draft-mcguinness-oauth-mission], Section
"Integrity Anchors").¶
state: the current Mission lifecycle state. The authoritative
state space is the issuance profile's
([I-D.draft-mcguinness-oauth-mission], Section "Mission Lifecycle
and Gating"): the issuance profile states active, revoked, expired, this
profile's suspended and completed when the Mission Lifecycle
endpoint (Section 6) is deployed, and any
further state a companion profile defines and the deployment runs
(for example superseded, defined by the Mission Expansion profile
([I-D.draft-mcguinness-oauth-mission-expansion]) for an expanded
predecessor, or cascaded, defined by the Mission Child Delegation
profile ([I-D.draft-mcguinness-oauth-mission-child-delegation])
for a cascade-terminated Child Mission). A consumer applies the
issuance profile's forward-compatibility rule: only active permits
reliance, and every other value, recognized or not, is non-active.
This profile's reliance behavior does not depend on recognizing
these companion-defined states; the fail-safe rule above governs.¶
expires_at: the point at which the Mission itself expires, the
Mission record's expires_at
([I-D.draft-mcguinness-oauth-mission]).¶
fresh_until: an RFC 3339 [RFC3339] date-time giving the point
until which the consumer MAY rely on the reported state without
re-checking, governing caching (Section 3.5). It is
report-freshness metadata, carried in mission so it travels with
state even on the introspection projection, which has no signed
envelope to carry it (Section 4).¶
suspend_until, on_expiry: CONDITIONAL. Present only while the
Mission is suspended under a deadline
(Section 6): the RFC 3339 [RFC3339]
deadline, and the transition (resume or revoke) the AS applies
when it passes.¶
successor: OPTIONAL. A string, the successor mission_id. Present
only when state is superseded, giving the successor that
replaced this Mission, set atomically at supersession on the
predecessor's record
([I-D.draft-mcguinness-oauth-mission-expansion]).¶
version: REQUIRED. The Mission's state version: a strictly
monotonic per-Mission counter the Mission Issuer maintains,
incremented on each committed lifecycle transition (the approval
event is version 1) and each committed metadata-only change,
current as of the reported state. It orders observations of one
Mission across every surface: an event consumer that
re-established state through this operation re-seats its gap
detection on it (the last-applied Signals version becomes this
value, [I-D.draft-mcguinness-oauth-mission-signals]), a
lifecycle mutation can guard on it (Section 6.8), and a
materialized policy view names the value it materialized
([I-D.draft-mcguinness-mission-runtime]).¶
status_list: OPTIONAL. The referenced-token status object of
[I-D.draft-ietf-oauth-status-list] (idx and uri), present
where the deployment publishes a Mission Status List
(Section 5).¶
authorization_details: the audience-scoped Authority Set entries
relevant to the requesting audience, as the mission_resource_access
shape of [I-D.draft-mcguinness-oauth-mission] (Section "Mission
Authority"), carried at the top level as a sibling of mission (as
on the token and in the introspection response). Entries addressed
to other audiences MUST NOT be disclosed. When the request omits
audience (Section 3.1), there is no requesting
audience: the response is state-only and MUST NOT carry
authorization_details.¶
A consumer MUST verify, before honoring a response:¶
the JWS header typ is mission-status-response+jwt;¶
the JWS header alg is one the AS advertises in
mission_status_signing_alg_values_supported (Section 9),
rejecting none and any algorithm not listed;¶
the JWS signature against a current jwks_uri entry for the
issuer AS;¶
iss equals the expected AS issuer URL;¶
aud equals the consumer's own audience identifier;¶
sub equals the requesting client's identifier;¶
nonce equals the request's nonce;¶
mission.id equals the requested mission_id; and¶
iat is not in the future and exp is not in the past, with up to
30 seconds clock-skew tolerance.¶
Caching follows these rules:¶
Cache key. Consumers SHOULD cache a response keyed on
(mission_id, audience), or on (mission_id, requester
identifier) for a state-only response, until mission.fresh_until.¶
Hard stop. Consumers MUST NOT use a cached response after
mission.fresh_until. In particular, a consumer MUST NOT extend
reliance on a cached suspended (or any non-active) response
beyond mission.fresh_until.¶
Freshness cap. When the AS advertises
mission_max_stale_seconds (Section 9), it MUST NOT set
mission.fresh_until later than the response iat plus that
value.¶
Skew tolerance. When comparing the current time to
mission.fresh_until, a consumer MAY allow up to 30 seconds of
tolerance for the active state only, and no tolerance for any
other state. The tolerance MUST NOT exceed the AS's advertised
mission_max_stale_seconds (Section 9).¶
The freshness cap keeps report freshness within the deployment's
advertised revocation-propagation tolerance. The skew tolerance is a
clock-skew allowance on the reliance path, bounding the disagreement
between the AS's and the consumer's clocks, not a property of state
reversibility. The hard stop is absolute for non-active states
because a suspended Mission may be resumed to active.¶
A mission_id is never a bearer capability. The AS MUST authenticate
the requester and authorize it for the requested mission_id and
audience.¶
Unknown mission_id values and known-but-unauthorized references MUST
produce indistinguishable responses (HTTP 404 with a generic
not-found body; see Section 3.7). The AS MUST return an
identical HTTP status code, response body, and headers for the two
cases. The AS SHOULD NOT vary response timing in a way that
distinguishes the two cases. It SHOULD mitigate timing side channels
(for example by padding response time or by taking a uniform lookup
path for both the unknown and the unauthorized case).¶
Mission Status outcomes are of two kinds. A success outcome is a found,
visible, authorized Mission: the AS returns HTTP 200 with a signed
Mission Status Response, and the outcome is described by mission.state
in that response, not by a separate symbol. A wire error is a hard
failure: the AS returns the matching HTTP status with a JSON object
[RFC8259] body whose error member carries the symbol below.¶
Success outcomes (HTTP 200, signed Mission Status Response, described by
mission.state):¶
| mission.state | Description |
|---|---|
active
|
Mission is active and permits reliance. |
suspended
|
Mission is suspended (non-terminal). |
revoked, expired, completed, superseded, cascaded
|
Mission is in a terminal, non-active state. |
This document uses "terminated" in prose for any terminal
non-active state; it is not itself a mission.state value, and the
terminal set is not closed. The terminal row above and the list that
follows enumerate the companion-defined states this suite currently
runs, for the reader's reference; a deployment reports whichever it
runs, and a consumer's reliance decision never depends on recognizing
them. The terminal states currently defined across this suite are
revoked and expired ([I-D.draft-mcguinness-oauth-mission]),
completed (this document), superseded
([I-D.draft-mcguinness-oauth-mission-expansion]), and cascaded
([I-D.draft-mcguinness-oauth-mission-child-delegation]). The binding
rule is the issuance profile's forward-compatibility rule: every value
other than active is non-active, whether or not the consumer
recognizes it.¶
Wire error codes (carried in the error member of a JSON body):¶
| error | HTTP | Description |
|---|---|---|
invalid_request
|
400 | Malformed request: an unparseable body, a required member missing or malformed, an invalid member combination, or a retransmitted nonce paired with a request that is not byte-identical to the original (Section 6.8). |
unauthorized
|
401 | Request not authenticated. |
not_found
|
404 | Reference does not exist OR is not visible. |
conflict
|
409 | Lifecycle operation not legal from the current state (Section 6.8). |
stale_version
|
409 |
expected_version differs from the current state version (Section 6.8). |
rate_limited
|
429 | Consumer is rate-limited. |
unavailable
|
503 | AS temporarily cannot serve status. |
Note the distinction between the two access failures: unauthorized
(401) means the request carried no valid authentication, whereas a
request that is authenticated but not authorized for the referenced
Mission returns not_found (404), never 401, so that an unauthorized
reference is indistinguishable from an unknown one
(Section 3.6). The error body is:¶
The body MUST contain error and error_description, and MUST
additionally contain nonce when the request carried a well-formed
nonce. A request whose nonce is absent or malformed is refused
invalid_request with no nonce member echoed. The body MUST NOT
contain any member that would let a caller distinguish unknown from
unauthorized references. For rate_limited, the response SHOULD
include a Retry-After header [RFC9110] and a retry_after body
member in seconds.¶
The OAuth-shaped surfaces of this family, this Status and Lifecycle
endpoint, Mission Management
[I-D.draft-mcguinness-oauth-mission-management], and the Mission
Authority Server's submission surface
[I-D.draft-mcguinness-mission-authority-server], share the
error/error_description JSON body idiom for consistency with the
OAuth-shaped APIs they compose with. Each surface's exact member
requiredness is its own: here and in Mission Management,
error_description and nonce are REQUIRED; the Mission Authority
Server makes error_description OPTIONAL and adds the MAS-only
error_reason. The body is application/json with Cache-Control:
no-store. error_description is diagnostic and is never
authorization input. nonce correlates the response to the request in
support of the signed-response and retry model of Section 6.8 and
is not, by itself, replay protection, per the absent-or-malformed-nonce
rule above. RFC 9457 [RFC9457] problem details
is neither used on these surfaces nor disparaged: the AuthZEN binding
[I-D.draft-mcguinness-mission-authzen] carries it where that
ecosystem does, and a future non-OAuth-shaped HTTP API in this family
MAY choose it.¶
This section is OPTIONAL and is a thin delta over the OAuth 2.0 Token
Introspection [RFC7662] projection of
[I-D.draft-mcguinness-oauth-mission] (Section "Mission State via
Token Introspection"). That section already
defines a mission member on the introspection response carrying
id, issuer, authority_hash, and (from the Mission's issuer) the
lifecycle state, together with the caller-authorization,
minimization, and issuer-only-reports-state rules. This document does
not restate those rules.¶
This extension adds the following to that projection:¶
An introspection response that carries a Mission projection is
protected by TLS, as for token introspection generally
([I-D.draft-mcguinness-oauth-mission], Section "Mission State via
Token Introspection"). Where the projection's integrity and provenance
need to be verifiable independently of the transport (for example
when the response transits intermediaries or is retained for audit),
the AS SHOULD return it as a [RFC9701]-signed response, advertised
through the introspection_signing_alg_values_supported metadata
that [RFC9701] registers in the [RFC8414] registry.¶
When the responding AS is the Mission's issuer, the projection MAY
additionally carry fresh_until, an RFC 3339 [RFC3339] date-time
giving the point until which the consumer MAY rely on the reported
state without re-checking, governed by the caching rule of
Section 3.5. When fresh_until is absent (for example
a non-issuer projection), the consumer MUST NOT cache the reported
state across requests and re-checks per use or relies on the
token's own lifetime.¶
This projection and the dedicated Mission Status Response
(Section 3.4) carry Mission facts in a mission object
of the same shape: the open mission claim object of
[I-D.draft-mcguinness-oauth-mission] (Section "The Mission Claim")
with status members (state, fresh_until, the status_list
reference where the deployment publishes one (Section 5), and,
on the dedicated response, expires_at and version) added. This
projection populates the subset a token-holding consumer needs; the
dedicated response populates more. Either way a consumer reads the
same fact from the same place.¶
Example [RFC9701]-signed introspection response (decoded payload),
for a token whose Mission is active:¶
{
"iss": "https://as.example.com",
"aud": "https://erp.example.com",
"iat": 1793606400,
"token_introspection": {
"active": true,
"client_id": "s6BhdRkqt3",
"sub": "user_3p2q8mN1a0kV7tR",
"scope": "invoices.read",
"mission": {
"id": "msn_8RfX2Lqv9TqMv4z7sA2bN1k0YpEdHc9-",
"issuer": "https://as.example.com",
"authority_hash":
"sha-256:l3KvZ4mP5x0wQrR6tY2nD9bM7sX1cF8gH2vJ4kE5pNQ",
"state": "active",
"fresh_until": "2026-11-02T08:00:45Z"
}
}
}
¶
Per [RFC9701], the signed response is a JWT of typ
token-introspection+jwt whose [RFC7662] members, including the
mission projection, ride in the token_introspection claim; only
iss, aud, and iat are top-level.¶
A consumer holding only a mission_id, or one that needs signed
evidence independent of a specific token (an auditor or a cross-domain
Resource AS), uses the dedicated Mission Status operation
(Section 3); the introspection projection is purely a
same-call convenience for token-holding consumers and is never the
sole Mission Status path.¶
One consumer often relies on many Missions at once: a gateway fronting an agent fleet holds a Mission per unit of work, and per-Mission status reads at that scale are a latency tax this profile's caching rules cannot amortize. A Mission Issuer MAY additionally publish Mission state as a Status List ([I-D.draft-ietf-oauth-status-list]): a signed, compressed bit array in which each participating Mission holds an index, fetched once per freshness window and read locally per action.¶
The arithmetic is the point. A fleet of 100,000 participating
Missions at two bits per entry is 25,000 bytes before compression,
and a mostly-active population compresses far below that; a
consumer fetching that list once per 30-second window spends under a
kilobyte per second to hold fresh state for every Mission it relies
on, where per-Mission status reads would cost 100,000 requests per
window. Fleet scale makes state freshness cheaper per Mission, not
more expensive.¶
Reference. A participating Mission's status_list member
(idx and uri, the referenced-token shape of
[I-D.draft-ietf-oauth-status-list]) rides the Mission Status
Response and the introspection projection
(Section 3.4, Section 4), so a
consumer learns its index from the authoritative surface it
already reads.¶
Mapping. VALID (0x00) reports active; SUSPENDED (0x02)
reports suspended; INVALID (0x01) reports every terminal state.
A consumer treats any other value as non-active, per the fail-safe
rule. The list carries reliance bits only: which terminal state, the
successor, and the state version stay on this profile's
authoritative surfaces, and a consumer that observes a bit other
than VALID re-establishes state there before any further reliance.¶
Freshness. The Status List Token's ttl and exp are a
published staleness bound: within them a VALID bit permits reliance
exactly as a fresh Mission Status Response reporting active does,
and an expired or unfetchable list is stale state, never permission
([I-D.draft-mcguinness-mission-runtime]). A committed lifecycle
transition MUST be reflected in the next Status List Token
published for its list, and where Signals runs, the event is the
push complement to the list's pull floor.¶
Privacy. Index assignment MUST NOT be derivable from or correlatable with the Mission Identifier, and the list conveys bits at opaque indices only, so publishing it preserves this profile's anti-oracle posture (Section 3.6) while the fetch itself, covering every index at once, reveals no per-Mission interest.¶
This section is OPTIONAL. The issuance profile lets the Subject,
Approver, or an administrator revoke a Mission by an authenticated,
deployment-defined means and defers a standardized management API and
the richer suspend, resume, and complete operations
([I-D.draft-mcguinness-oauth-mission], Section "Revocation"). This
section standardizes that management surface.¶
The AS publishes its Mission Lifecycle endpoint URL in Authorization
Server metadata (Section 9) as mission_lifecycle_endpoint,
distinct from [RFC7009] token revocation. The endpoint MUST be
served over TLS 1.2 or later (TLS 1.3 RECOMMENDED), following the
recommendations of [RFC9325].¶
Adopting this endpoint extends the issuance profile's lifecycle state
space ([I-D.draft-mcguinness-oauth-mission], Section "Mission
Lifecycle and Gating") with two additional states: suspended (a
non-terminal paused Mission that derives no tokens until resumed) and
completed (a terminal state recording successful completion).
Issuance gating treats any state other than active as
non-deriving, exactly as the issuance profile gates on active.¶
A transition to suspended or completed gates new derivation only.
Tokens already derived under the Mission remain valid until their own
exp, exactly as in the issuance profile's revocation model and
mirroring the treatment of superseded
([I-D.draft-mcguinness-oauth-mission-expansion]). A deployment that
needs a prompt cutoff on outstanding tokens uses the propagation
mechanisms of Section 8.¶
The endpoint accepts authenticated POST requests with a form-urlencoded body:¶
mission_id:REQUIRED. A string. The canonical Mission Identifier, named per the issuance profile's external-surface convention ([I-D.draft-mcguinness-oauth-mission]).¶
operation:REQUIRED. A string. One of revoke, suspend,
resume, complete, discharge.¶
reason:OPTIONAL. A string. A human-readable reason recorded in
audit, maximum 1024 characters. Not used by discharge, which
records its own request members in audit (Section 6.2).¶
suspend_until:OPTIONAL. An RFC 3339 [RFC3339] date-time. Valid only on the
suspend operation. When present, it sets a deadline after which the
AS applies on_expiry.¶
on_expiry:CONDITIONAL. A string, one of resume or revoke. REQUIRED when
suspend_until is present; otherwise MUST NOT be sent. It selects the
transition the AS applies when suspend_until passes.¶
nonce:REQUIRED. A string. A client-generated nonce.¶
The discharge operation carries additional REQUIRED and OPTIONAL
members of its own, defined in Section 6.2.¶
The operations are:¶
revoke: terminate the Mission; transition to revoked.¶
suspend: pause the Mission; transition to suspended.¶
resume: return a suspended Mission to active.¶
complete: mark the Mission completed; transition to completed.¶
discharge: commit that a terminal_when completion condition
(Section 7.2) has fired, discharging a Mission-record entry.
It changes no Mission-level state and is defined in its own
subsection (Section 6.2).¶
A suspend MAY carry suspend_until with a REQUIRED on_expiry. When
suspend_until passes, the AS MUST apply on_expiry (transition to
active for resume, or to revoked for revoke) and emit the
corresponding transition, without a further request. While the Mission
is suspended under a deadline, both suspend_until and on_expiry
surface in the signed Mission Status Response (Section 3.4)
so a consumer sees the pending outcome.¶
discharge commits that a terminal_when completion condition
(Section 7.2) has fired, discharging the named Mission-record
entry (Section 7.3). Beyond mission_id and nonce, it requires:¶
entry_digest:REQUIRED. A string. The Authority Set entry commitment
([I-D.draft-mcguinness-oauth-mission]) of the
mission_resource_access entry to discharge, computed over the
immutable Mission-record entry, never over a narrowed token
projection.¶
condition_digest:REQUIRED. A string. The digest identifying the single
terminal_when condition that fired, defined beside that member
(Section 7.2).¶
event_type:REQUIRED. A string. Echoed from the fired condition and
cross-checked against the condition condition_digest names: a
mismatch joins the not_found collapse, since distinguishing it
would reveal information about a condition selected by digest
(Section 6.2.2). event_type is never a selector by
itself.¶
event_id:REQUIRED. A string, 1*128( ALPHA / DIGIT / "-" / "_" / ":" / "." )
[RFC5234]. The identifier of the asserted external occurrence,
used for evidence correlation and for the event-level deduplication
of Section 6.2.3. It is distinct from nonce, the HTTP
retry key of Section 6.8.¶
evidence_ref:OPTIONAL. A URI, maximum 512 characters. A reference to evidence of the asserted occurrence.¶
evidence_digest:OPTIONAL. A string, the family's prefixed digest form (sha-256:
plus base64url, no-padding encoding), classified as a raw-octet
digest ([I-D.draft-mcguinness-oauth-mission], Section "Commitment
Mechanisms"): computed over the exact octets of the referenced
artifact as exchanged, with no canonicalization. evidence_ref and
evidence_digest MAY both appear: when they do, evidence_digest
MUST commit the bytes evidence_ref names. Present alone,
evidence_digest is independent audit metadata.¶
evidence_ref and evidence_digest are bounded audit metadata about
the asserted occurrence. The AS MUST NOT dereference evidence_ref
in baseline processing and MUST NOT treat either member as
authorization input.¶
observed_at:OPTIONAL. An RFC 3339 [RFC3339] date-time: a caller assertion. The
AS validates it for syntax and reasonable clock bounds only, never as
trusted ordering or freshness, and records its own commit time as
received_at in audit.¶
Semantics:¶
Entry-level OR latch. The entry's terminal_when discharges on
any condition being met (Section 7.2); the request names the
condition that fired. The committed state is one monotonic latch on
the entry, or on its selector equivalence class, one
state-version increment, one audit record, and one notification. A
later delivery presenting any valid condition against an
already-discharged entry, a sibling condition, or the same
condition under a different event_id, is acknowledged
already_discharged (Section 6.2.4) and MUST NOT discharge
the entry again or increment the version again; an exact event
replay (the same tuple and the same fingerprint) is handled first by
the dedup rule of Section 6.2.3. The latch MUST NOT
revert, and issuance gating for a discharged entry is unchanged
(Section 7.3).¶
Duplicate entries. One entry_digest discharges every
recorded entry resolving to that digest as a single
equivalence-class transition, and therefore one version increment,
under the Authority Set entry commitment's selector
equivalence-class rule
([I-D.draft-mcguinness-oauth-mission]).¶
States. discharge applies while the Mission is active or
suspended: a suspended Mission still narrows monotonically. A
delivery reaching the endpoint after completed, revoked,
expired, or another terminal state returns an authenticated
terminal_noop acknowledgement (Section 6.2.4) and MUST NOT
create a transition or a version increment. discharge never
changes Mission-level state; a deployment that also tracks
all-entry completion invokes complete separately. The AS reaches
this determination only after the selector and authorization
validation of Section 6.2.2, so a terminal Mission is
never a shortcut past those checks.¶
No expected_version. A stale-version refusal would delay a
safety-reducing operation; the digest selectors above and the
idempotency rules of Section 6.2.3 are the guards
instead.¶
Atomicity. The entry latch (or its equivalence-class latch), the version increment, the audit and result record, and the durable propagation work (an outbox entry or a signal enqueue) commit as one unit. Where the deployment emits lifecycle events ([I-D.draft-mcguinness-oauth-mission-signals]), the signal enqueue is part of that same unit. Downstream materialization from the durable propagation work, including the child-delegation profile's entry-wise propagation to an already-justified Child Mission ([I-D.draft-mcguinness-oauth-mission-child-delegation]), is asynchronous and is not claimed atomic with this commit. Instead, a Child Mission's derivation MUST consult, or otherwise be gated by, the committed parent latch until that materialization completes, so no Child Mission can derive the discharged parent authority in the gap between the parent's commit and the child's materialized view.¶
An unknown mission_id, an unknown entry_digest, an unknown
condition_digest, an entry with no terminal_when, an event_type
that does not match the condition condition_digest names, and a
caller not authorized for that target all collapse to the endpoint's
existing not_found treatment (Section 3.7). Authentication
failure remains unauthorized (401). Detailed refusal reasons live
only in issuer audit records.¶
The AS validates selector existence (mission_id, entry_digest, and
condition_digest all resolve, the entry carries terminal_when, and
event_type matches the named condition), then condition membership
(the named condition belongs to the named entry), then target
authorization (the discharge authority mapping of
Section 6.2.1), before returning any terminal_noop
acknowledgement (Section 6.2.4). This order keeps a terminal
Mission from acting as a selector-existence oracle: every case the
collapse above refuses is checked before a terminal Mission is ever
distinguished from one whose selectors do not resolve.¶
nonce and event_id
discharge keeps two identities apart. nonce stays the HTTP
operation retry key under Section 6.8's rules: a retransmission
with the same nonce and a byte-identical request returns the stored
signed response verbatim. The same nonce with a different request is
refused invalid_request, never answered with an unrelated original
response.¶
event_id deduplicates the external occurrence, scoped by
(authenticated discharge authority, mission_id, entry_digest,
condition_digest, event_id). A response's nonce MUST equal the
one just sent (Section 3.4), so a retry that supplies
a fresh nonce, as an at-least-once sender legitimately does, cannot
receive the original signed response verbatim. Two cases follow:¶
Same nonce, same request. The stored signed response is
returned verbatim, per the nonce rule above.¶
New nonce, same event tuple and the same assertion
fingerprint (defined below). The AS performs no state-changing
work: no re-latch, no version increment. It issues a new signed
envelope that echoes the new nonce and carries the stored
operation result: the same outcome and selectors, and the
original prior_version and current_version the first commit
produced.¶
Event assertion fingerprint. A semantic assertion object, never
raw form bytes: the JSON object with exactly the decoded members
operation (the literal string discharge), mission_id,
entry_digest, condition_digest, event_type, event_id, and,
when present, evidence_ref, evidence_digest, and observed_at.
The object is canonicalized under the issuance profile's
canonicalization ([I-D.draft-mcguinness-oauth-mission], Section
"Canonicalization Rules") and digested as a canonical-object digest
([I-D.draft-mcguinness-oauth-mission], Section "Commitment
Mechanisms"), since protocol context already fixes what the object
commits. nonce, client authentication material, the DPoP proof, and
transport headers are outside the fingerprint: none of them enter the
assertion object, and none of them affect its value.¶
Over the (discharge authority, mission_id, entry_digest,
condition_digest, event_id) tuple: the same tuple with the same
fingerprint is the replay case above; the same tuple with a different
fingerprint is refused conflict; the same event_id asserted
against another Mission, entry, or condition is a valid, independent
assertion, since one real-world event legitimately fans out to more
than one target.¶
When both rules could apply, the nonce rule is evaluated first,
since it governs the HTTP exchange; the event_id rule governs across
distinct exchanges.¶
Retention. Event-dedup state MUST be retained at least as long as
the deployment's published retry horizon and the replayable result's
usable lifetime, and MAY be bounded by the Mission record's own
retention. After eviction, a repeated assertion is processed fresh
against the latch and yields already_discharged with no version
increment, which is safe because the latch is monotonic.¶
On success, discharge returns the endpoint's existing signed Mission
Status Response envelope (Section 3.4), carrying a
discharge_result object as a sibling of mission:¶
entry_digest, condition_digest, event_id:the request's own selectors, echoed.¶
outcome:one of discharged (this request committed the latch),
already_discharged (a sibling condition, or the same condition
under a different event_id, presented against an already-latched
entry), or terminal_noop (the Mission was already in a terminal
state). An exact event replay is handled first by the dedup rule
(Section 6.2.3), never reaching this determination as a
fresh already_discharged.¶
prior_version, current_version:the Mission's state version immediately before and after the
commit this result reports. For a request that itself commits, that
commit is this request's own. For the new-nonce fresh-envelope
case of Section 6.2.3, which commits nothing, these are
the versions the original commit produced, unchanged. They are equal
for already_discharged and terminal_noop.¶
With the echoed nonce, this is the durable acknowledgement an
at-least-once sender stops retrying against.¶
An operation is legal only from the source states below. A terminal
state (revoked, expired, completed, or the companion-defined
superseded and cascaded) admits no transition. An operation whose
resulting state equals the current state, terminal or not, is
idempotent success (Section 6.8). This table governs Mission-level
state; discharge produces no Mission-state transition and is not a
row of it, following instead the entry-grain rules of
Section 6.2.¶
resume is the sole exception: it is legal only from suspended
(its resulting state, active, is also the baseline a Mission holds
before any suspension), so resume on an active or terminal
Mission is a conflict, not idempotent success.¶
| Operation | Legal from | Resulting state |
|---|---|---|
revoke
|
active, suspended
|
revoked
|
suspend
|
active
|
suspended
|
resume
|
suspended
|
active
|
complete
|
active, suspended
|
completed
|
complete is legal from suspended as well as active: completion is
a monotonic narrowing to a terminal state and needs no derivation
window, so a suspended Mission need not first be resumed to be
completed.¶
Requests are adjudicated by the single rule of Section 6.8: an
operation whose resulting state equals the Mission's current state is
idempotent success, with the resume exception above. Any other
operation not legal from the current state, including resume on a
Mission that is not suspended, is refused as a conflict. A Mission
that reaches its expires_at transitions to expired independently of
this endpoint, from active or suspended.¶
This profile owns the extension of the issuance profile's lifecycle
state space ([I-D.draft-mcguinness-oauth-mission], Section "Mission
Lifecycle and Gating"). The table below is the authoritative view of
that space: every state, every transition, and the source of the event
that drives it. Event sources are the lifecycle endpoint (an operation
of Section 6), the expiry clock (a deadline
reached without a request), and companion adjudication (a transition a
companion profile commits). The lifecycle-endpoint rows are exactly the
Mission-state-changing operations of Section 6.3; discharge
(Section 6.2) is a lifecycle-endpoint operation that
changes no Mission state and so is not a row of this table. Only
active permits derivation; every other state is non-deriving.¶
| From | Event | Event source | To |
|---|---|---|---|
| (none) | approval event | issuance profile |
active
|
active
|
revoke
|
lifecycle endpoint |
revoked
|
suspended
|
revoke
|
lifecycle endpoint |
revoked
|
active
|
suspend
|
lifecycle endpoint |
suspended
|
suspended
|
resume
|
lifecycle endpoint |
active
|
active
|
complete
|
lifecycle endpoint |
completed
|
suspended
|
complete
|
lifecycle endpoint |
completed
|
active
|
expires_at reached |
expiry clock |
expired
|
suspended
|
expires_at reached |
expiry clock |
expired
|
suspended
|
suspend_until reached, on_expiry = resume
|
expiry clock |
active
|
suspended
|
suspend_until reached, on_expiry = revoke
|
expiry clock |
revoked
|
active
|
successor activates | expansion profile |
superseded
|
active
|
parent reaches a terminal state | child-delegation profile |
cascaded
|
suspended
|
parent reaches a terminal state | child-delegation profile |
cascaded
|
revoke and the Mission's expires_at both apply in suspended as
well as active, so a suspended Mission can still be terminated or
expire. The superseded and cascaded rows are companion-defined and
shown here for reference:
superseded is committed by the expansion profile and requires an
active predecessor
([I-D.draft-mcguinness-oauth-mission-expansion]); cascaded is
committed by the child-delegation profile only when a parent reaches a
terminal state. A suspended parent holds a dependent Child Mission
non-active reversibly rather than driving it to cascaded
([I-D.draft-mcguinness-oauth-mission-child-delegation]). Neither
companion state is produced by this profile's endpoint.¶
The lifecycle endpoint uses the same authentication mechanisms as the
Mission Status endpoint (Section 3.2): mTLS client
authentication, a sender-constrained access token (DPoP- or mTLS-bound),
or private-key JWT. Its discovery mirrors that endpoint: the accepted
methods in mission_lifecycle_endpoint_auth_methods_supported and, for
private_key_jwt, the accepted client-assertion algorithms in
mission_lifecycle_endpoint_auth_signing_alg_values_supported
(Section 9). For the sender-constrained access-token path, this
endpoint is an OAuth protected resource exactly as the Mission Status
endpoint is: the AS publishes, in its Protected Resource Metadata for
this resource [RFC9728], the resource identifier the token's
audience MUST name and the scopes it requires (scopes_supported):
mission_lifecycle for revoke, suspend, resume, and complete
(Section 6), and, where the deployment offers
discharge, mission_discharge as well (Section 6.2.1). A
private-key JWT client_assertion MUST name the
mission_lifecycle_endpoint URL in aud, and a presented access token
MUST be audience-restricted to this endpoint's protected-resource
identifier, exactly as at the Mission Status endpoint. Direct mTLS or
private-key-JWT callers continue to use the deployment-defined
equivalent grant, never a scope, exactly as discharge itself does
(Section 6.2.1).¶
Revoke request:¶
Revoke success response: the AS returns the updated status as a signed
Mission Status Response (Section 3.4). Because the
Lifecycle request carries no audience, the response is state-only: the
AS sets aud to the authenticated requester and omits
authorization_details (a lifecycle confirmation reports state, not
audience-scoped authority). Here the response envelope's sub,
distinct from any access token's sub, carries the acting party: the
calling client identified by client_id. The AS records that acting
party and reflects it in this signed response as well as in its audit
log.¶
Decoded JWS payload:¶
{
"iss": "https://as.example.com",
"aud": "client_erp-recon-agent",
"sub": "client_erp-recon-agent",
"nonce": "nonce_8Y3vN0sM6tP1xR9bQ5",
"iat": 1793609600,
"exp": 1793609660,
"mission": {
"id": "msn_8RfX2Lqv9TqMv4z7sA2bN1k0YpEdHc9-",
"issuer": "https://as.example.com",
"authority_hash":
"sha-256:l3KvZ4mP5x0wQrR6tY2nD9bM7sX1cF8gH2vJ4kE5pNQ",
"state": "revoked",
"version": 7,
"expires_at": "2026-12-31T23:59:59Z",
"fresh_until": "2026-11-02T08:54:05Z"
}
}
¶
The AS records the operation, actor, time, and any reason in its
audit log; the response confirms the outcome through the updated
state.¶
Suspend request with a deadline, here also carrying the OPTIONAL
expected_version guard against deciding over stale state
(Section 6.8):¶
Suspend success response: the signed Mission Status Response reports
suspended and surfaces the pending outcome, carrying suspend_until
and on_expiry in mission alongside state. Decoded JWS payload:¶
{
"iss": "https://as.example.com",
"aud": "client_erp-recon-agent",
"sub": "client_erp-recon-agent",
"nonce": "nonce_4Dq2mV8kX1sB7nR3tW",
"iat": 1793607600,
"exp": 1793607660,
"mission": {
"id": "msn_8RfX2Lqv9TqMv4z7sA2bN1k0YpEdHc9-",
"issuer": "https://as.example.com",
"authority_hash":
"sha-256:l3KvZ4mP5x0wQrR6tY2nD9bM7sX1cF8gH2vJ4kE5pNQ",
"state": "suspended",
"version": 6,
"suspend_until": "2026-11-09T08:15:00Z",
"on_expiry": "revoke",
"expires_at": "2026-12-31T23:59:59Z",
"fresh_until": "2026-11-02T08:20:45Z"
}
}
¶
When suspend_until passes without a resume, the AS applies
on_expiry and transitions the Mission to revoked without a further
request.¶
The request nonce (Section 6, Operations) is
the idempotency key: an opaque string of 1 to 255 characters. The AS
treats an absent, empty, longer, or non-string nonce as malformed
(invalid_request, with no nonce echoed). The AS MUST deduplicate
lifecycle requests by the
triple (client, mission_id, nonce) for a bounded window. On a
retransmit carrying a nonce already seen for that client and
mission_id, together with a request byte-identical to the original,
the AS MUST replay the original response rather than re-execute the
operation. The same nonce paired with a request that is not
byte-identical to the original MUST be refused invalid_request
(Section 3.7); the AS MUST NOT answer it with the
unrelated original response. The window MUST be at least the validity
span of the signed response the AS would replay (its iat to exp,
Section 3.4), so any retransmit that could still
present a live response is deduplicated. A deployment MAY use a longer
window. This makes a retransmit safe against reordering: a
delayed suspend retry that arrives after a resume is recognized as
a duplicate and replays the original suspend response, so it cannot
re-suspend an already-resumed Mission.¶
Deduplication guards a retransmitted request; it does not guard a
valid request decided over stale state, a fresh suspend issued from
a console that has not yet seen a newer resume. For that a
lifecycle request MAY carry expected_version, the state version
(Section 3.4) the caller last observed: when present,
the AS MUST refuse the operation with HTTP 409 and error symbol
stale_version, leaving the Mission unchanged, when the Mission's
current state version differs. A deployment SHOULD require
expected_version on the operations it classifies high-risk. The
nonce remains the replay key; the two guards are independent, one
against duplicate delivery, one against stale decisions.¶
Lifecycle operations that change Mission state follow one rule. An
operation whose resulting state (Section 6.3) equals the
Mission's current state is idempotent success, terminal or not: the AS
returns the current Mission Status Response, with no state change and
no event emitted. Any other operation not legal from the current state
(for example suspend against a terminal state) is a conflict: the AS
MUST refuse it with HTTP 409 and a JSON body whose error symbol is
conflict, leaving the Mission state unchanged. discharge changes no
Mission state, so this rule does not bind it; its own idempotency and
outcome vocabulary are defined in Section 6.2.3 and
Section 6.2.4.¶
resume is the sole exception to the idempotent-success arm. It is
legal only from suspended, and its resulting state active is also
the baseline a Mission holds before any suspension, so resume on an
active Mission (one never suspended, or already resumed) or on a
terminal Mission is not idempotent success but a conflict.¶
One idempotent case carries metadata. A suspend against a
suspended Mission whose suspend_until or on_expiry differ from
the recorded values MUST update the recorded values, emitting the
corresponding transition-metadata change and reporting the updated
values in the response; silent acceptance without effect is not
conforming.¶
A Mission revocation through this endpoint cascades to credentials
derived from the Mission per the AS's advertised revocation
propagation (Section 8). The AS MAY additionally invoke
[RFC7009] token revocation for specific outstanding tokens when it
knows their jti. [RFC7009] alone does NOT revoke a Mission; the
lifecycle endpoint is the authoritative Mission state change.¶
This endpoint operates on one Mission at a time. Mission enumeration
and bulk lifecycle operations for incident response, such as revoking
every Mission for a compromised Subject, client, or tenant, are
specified separately by Mission Management
[I-D.draft-mcguinness-oauth-mission-management]; this document does
not require them. The following capabilities remain deferred to future
work. Approver transfer or re-anchoring, changing the party that
anchors a Mission's consent, is not defined here. Administrative
monotonic narrowing, such as shortening a Mission's expires_at, is
not defined here.¶
This section is OPTIONAL. A deployment that ends an entry's authority
only by Mission revocation or expiry is fully conformant to the
issuance profile and is unaffected by this section, which places no
new requirement on the issuance profile: it defines one OPTIONAL
entry member and the rules for handling it. A deployment claims the
completion capability only when it issues or consumes entries
carrying terminal_when. The capability is newer and less exercised
than baseline issuance and runtime enforcement, and is not required by
any Mission Assurance Level; its entry-discharge details may change.¶
The issuance profile gates issuance on Mission state but has no
notion of an approved entry being done. A Mission granted
authority to release a record "for this enrollment" keeps deriving
that authority after the enrollment closes, until a clock or a revoke
stops it. The Intent's success_criteria describe when the task is
complete, but the issuance profile keeps them inert: they are
rendered and committed, and carry no machine effect
([I-D.draft-mcguinness-oauth-mission]).¶
This section supplies the enforceable counterpart. It defines
terminal_when, an OPTIONAL Common Constraint
([I-D.draft-mcguinness-oauth-mission]) on a
mission_resource_access entry that carries one or more completion
conditions. When a condition is met, the entry is discharged: the
Authorization Server no longer derives a token carrying that entry
(Section 7.3), exactly as it refuses derivation for a non-active
Mission.¶
Three properties make this safe inside the Mission model and this section requires all three:¶
Discharge is monotonic. It only removes an entry's authority; it can never widen the entry or the Mission.¶
Discharge composes with the subset rule. A derived entry carries its parent's completion conditions unchanged and MAY add more, the same way constraints may be added or tightened but never dropped.¶
Discharge fails closed on the constraint. A consumer that does
not understand terminal_when refuses the entry rather than
ignoring the condition.¶
The threat analysis of these properties, including why a prompt-injected agent cannot use discharge to escalate and the forced-premature-discharge residual, is given in Section 11.6.¶
Discharge gates at the entry, not the Mission (Section 7.3). It strengthens the kill switch: a task that finishes stops issuing its own authority without waiting for a clock or a revoke.¶
The completion capability depends normatively on the issuance profile
and is not implementable alone. It reuses, without restating, the
issuance profile's Mission, mission_resource_access entry, Authority
Set, subset rule, integrity anchors, lifecycle states, and issuance
gating, and the inert success_criteria member of the Mission Intent.
It uses Mission, Mission Issuer, Authority Set, and derivation as the
issuance profile defines them.¶
It extends the issuance profile in one narrow, additive way: it
registers terminal_when, an OPTIONAL Common Constraint on a
mission_resource_access entry (Section 7.2), whose subset rule
the issuance profile's existing subset comparison applies
(Section 7.4). It changes no Mission lifecycle state and no
meaning of any existing member.¶
This section defines terminal_when, a Common Constraint
([I-D.draft-mcguinness-oauth-mission]) carried in the constraints
object of a mission_resource_access entry. It is a
specification-defined Common Constraint under the issuance profile's
naming convention (Section 13).¶
terminal_when:OPTIONAL. An array of one or more completion conditions. When any condition is met, the entry is discharged (Section 7.3). Each condition is an object with these members:¶
event_type:REQUIRED. A string identifying the completion event. Its semantics
are deployment- or registry-defined and opaque to this document, as
purpose is ([I-D.draft-mcguinness-oauth-mission]).¶
discharge_policy:OPTIONAL. A string, 1*64( ALPHA / DIGIT / "-" / "_" / ":" / "." )
[RFC5234], opaque. A stable selector naming the AS-side
discharge-authority mapping for this condition
(Section 6.2.1).¶
The terminal_when array is part of the entry's constraints and so of
the Authority Set: it is committed by authority_hash and reproducible
under derivation ([I-D.draft-mcguinness-oauth-mission]). Condition
identity is byte equality of the condition object's canonical form
under the issuance profile's canonicalization; an AS refuses a value
carrying two identical conditions, and an intersection of two arrays
deduplicates by that identity and sorts by the lexicographic order of
the canonical bytes (Section 13.4), so the intersected entry
is one reproducible array. Whether a
condition has fired is evaluated state, not part of authority_hash;
folding fired status into the anchor would make the committed authority
time-varying.¶
condition_digest, used to select a condition on the discharge
operation (Section 6.2), is a canonical-object digest
([I-D.draft-mcguinness-oauth-mission]) over the exact canonical bytes
of the single condition object, in the issuance profile's encoded
form: the same canonical form the registration's no-duplicate rule
above already fixes as condition identity (Section 13.4).¶
terminal_when is the enforceable counterpart of the inert
success_criteria ([I-D.draft-mcguinness-oauth-mission]), which
remains inert: success_criteria describe completion for the Approver,
terminal_when acts on it. It is distinct from a cumulative
consumption bound, which meters volume;
a terminal_when condition is a single external event.¶
When a condition in an entry's terminal_when has been met, the entry is
discharged. The Authorization Server MUST NOT derive a token carrying a
discharged entry, at the token endpoint, on refresh, or on Token
Exchange, exactly as issuance is refused for a non-active Mission
([I-D.draft-mcguinness-oauth-mission]). A derivation that would carry
only discharged entries MUST fail. A derivation that carries a mix MUST
omit the discharged entries.¶
Discharge gates at the entry, not the Mission. The Mission remains
active and continues to derive its other entries: a multi-resource
Mission therefore completes partially, one entry at a time, as each
entry's task finishes. The issuance profile's Mission states are
unchanged; a deployment that also tracks Mission-level completion MAY
transition a Mission whose entries are all discharged to the
completed state the Mission Lifecycle endpoint defines
(Section 6), but this section does not require
it. Such a transition is performed through the complete operation,
as an issuer-initiated lifecycle operation, so the consolidated state
machine's event sources remain authoritative (Section 6.4).¶
Discharge gates new derivations only. A token already issued for an entry remains valid until it expires, as with revocation ([I-D.draft-mcguinness-oauth-mission]). A deployment that needs prompt cutoff relies on short token lifetimes or on the runtime layer denying a discharged entry at the point of use (Section 7.7).¶
A discharge is committed one of two ways: through the discharge
operation (Section 6.2), or by deployment-internal
adjudication the issuer trusts, recorded under the same audited basis
as any other lifecycle commit. This document defines no interoperable
event-source polling profile of its own: the discharge operation is
the interoperable path. An event-driven deployment wires its event bus
to the lifecycle call. A deployment that determines completion by
other means, such as a private status query or a recorded
administrative action, invokes the same commit internally once it has
decided.¶
Once committed, a discharge is recorded as Authorization-Server-side
state and MUST NOT revert: a later delivery presenting any valid
condition against an already-discharged entry is acknowledged
already_discharged (Section 6.2.4) and does not restore the
entry's authority.¶
A committed discharge is a committed metadata-only change for the
purposes of the state version (Section 3.4): the
Mission's state version increments at the commit, so a materialized
policy view that commits a state version
([I-D.draft-mcguinness-mission-runtime]) is detectably obsolete
after a discharge. Where Signals is deployed, the commit is carried by
the generic authority_changed discriminator
([I-D.draft-mcguinness-oauth-mission-signals]); where Signals is not
deployed, the version movement is what makes the change observable.¶
Before the AS receives and commits a discharge, it continues issuing against the entry. The posture this implies is stated plainly in Section 11.6.¶
A discharged entry is no longer derivable, so the surfaces that report a
Mission's authority MUST reflect that. Where the Mission Status
operation (Section 3) and the token introspection projection
(Section 4) are deployed, they MUST omit a
discharged entry from the authorization_details they return. This is
consistent with the audience filtering those surfaces already apply: a
discharged entry, like an entry addressed to another audience, is not
authority the caller may rely on.¶
Where Signals is deployed, a discharge commit rides the
mission.lifecycle-change event's generic authority_changed
discriminator [I-D.draft-mcguinness-oauth-mission-signals]: an
active-to-active event carrying it signals that the Mission's
effective authority narrowed even though state did not change.¶
Because terminal_when is a Common Constraint, the issuance profile's
subset comparison ([I-D.draft-mcguinness-oauth-mission]) applies its
defined subset rule with no new clause: for a key present in the
reference entry's constraints, the same key MUST be present in the
candidate entry and its value MUST be no broader under the key's
defined rule.¶
For terminal_when, a candidate value is no broader
than a reference value when the candidate's condition array contains
every condition of the reference, compared structurally after the
canonicalization of the issuance profile
([I-D.draft-mcguinness-oauth-mission]); the candidate MAY add further
conditions.¶
Conditions are compared structurally, not by event semantics. A child
cannot drop or alter a parent's completion condition, only add more, so
discharge composes monotonically: an added condition can only make an
entry discharge sooner, which is a narrowing. Modifying a parent
condition is forbidden because a verifier cannot decide whether the
change discharges earlier or later from opaque event_type values.¶
Because terminal_when is a constraints member, a consumer that does
not recognize it fails closed by the issuance profile's Resource Server
enforcement rule directly: a consumer MUST fail closed on any
constraints key it does not understand, or understands but cannot
enforce, refusing the request rather than granting access while ignoring
the key ([I-D.draft-mcguinness-oauth-mission]). Discharge is
load-bearing narrowing, so ignoring terminal_when would silently widen
the grant. That enforcement rule is the honest basis of discharge's
safety: an unrecognized terminal_when is refused, never dropped.¶
An Authorization Server that does not implement this capability simply
does not emit terminal_when, and is unaffected. The fail-closed rule
binds a consumer that encounters the constraint without implementing
it.¶
This guidance is non-normative. When the Authorization Server derives an entry from the Mission Intent, a reviewable rule governs what each element of the Intent becomes:¶
an action if removing it would leave the task undefined;¶
an ordinary constraints member if removing it would merely make the
task less restrictive; and¶
a terminal_when completion condition, itself a constraints member,
if it defines when the task is satisfied, retiring the entry's
authority rather than widening or restricting it.¶
The third case is what this capability adds. A bound that holds
throughout the task is an ordinary constraint; an event that ends the
task is a terminal_when condition. For example, "only invoices under
500 USD" is a max_amount constraint, while "until the Q3 close is
finalized" is a completion condition.¶
Discharge is an issuance-gating signal and is fully meaningful at the
issuance profile alone. It is also a natural input to the runtime layer
([I-D.draft-mcguinness-mission-runtime]): a runtime Policy
Enforcement Point that recognizes terminal_when SHOULD deny a
discharged entry at the point of use, closing the window between
discharge and token expiry the same way it denies a revoked Mission. A
Policy Enforcement Point learns that an entry is discharged from the
Mission Status operation or the token introspection projection
(Section 7.3.2), the same way it learns a Mission is revoked. A runtime
Policy Enforcement Point that does not recognize terminal_when fails
closed for the entry per Section 7.5.¶
For that point-of-use denial this document defines the denial-reason
identifier authority_discharged, a family-coordinated name under the
AuthZEN binding's denial-reason extension rule
([I-D.draft-mcguinness-mission-authzen]), carried wherever the
runtime layer's denial reasons travel: the decision response's
context.reason and the runtime evidence companion's
denial_reason. It means the entry was approved and its completion
condition fired, so the Mission Issuer discharged it: distinct from a
containment denial (trust withdrawn) and from an out-of-authority
denial (never approved). A consumer treats an unrecognized value as a
deny under the binding's own rule; no other semantics attach.¶
A Mission for alice reconciles Q3 payables. Its Authority Set has two
entries: a read over the ledger, and a write to post journal entries,
bounded to under 500 USD and discharged when the Q3 close is finalized:¶
[
{ "type": "mission_resource_access",
"resource": "https://erp.example.com",
"actions": ["invoices.read"] },
{ "type": "mission_resource_access",
"resource": "https://erp.example.com",
"actions": ["journal-entries.write"],
"constraints": {
"max_amount": { "amount": "500.00", "currency": "USD" },
"terminal_when": [
{ "event_type": "accounting-period-closed",
"discharge_policy": "close-management-2026-q3" } ] } }
]
¶
discharge_policy names the AS-side authority mapping approved for
this condition: the close-management system's workload identity, not
alice's agent, may assert accounting-period-closed
(Section 6.2.1). The agent cannot drive its own discharge: it
holds no mission_discharge authorization for that event_type.¶
While the period is open, the Authorization Server derives both
entries. When the finance team finalizes the Q3 close, the
close-management system calls discharge on the Mission Lifecycle
endpoint, naming the write entry's entry_digest, this condition's
condition_digest, event_type accounting-period-closed, and an
event_id for its own occurrence record. The Authorization Server
authenticates the caller against the resolved discharge_policy
mapping, commits the latch, and returns a signed discharge_result of
outcome discharged (Section 6.2.4). From then on the
Authorization Server refuses to derive the write entry: a refresh
returns a token carrying only the read entry. The Mission stays
active, so the agent can still read the ledger to finish its
reconciliation report, but it can no longer post journal entries. No
revoke and no clock was needed; the write authority retired itself
when the task it was granted for completed.¶
An Authorization Server claiming the completion capability MUST:¶
treat an entry whose terminal_when has been discharged as
discharged and refuse to derive it (Section 7.3);¶
commit a discharge only through the discharge operation, meeting
its authority, anti-oracle, idempotency, and atomicity requirements
(Section 6.2), or through an equivalently audited
deployment-internal adjudication (Section 7.3.1);¶
record a committed discharge as latched state that MUST NOT revert (Section 7.3.1);¶
carry every parent completion condition into a derived entry when narrowing, permitting only added conditions (Section 7.4);¶
where it offers the Mission Status operation or the token introspection
projection, omit a discharged entry from the authorization_details it
returns (Section 7.3.2); and¶
keep the terminal_when condition array committed by authority_hash
and keep fired status out of it (Section 7.2).¶
A consumer claiming the completion capability MUST fail closed for an
entry carrying a terminal_when constraint it does not understand
(Section 7.5).¶
This section is OPTIONAL. The issuance profile bounds outstanding self-contained tokens by their lifetime and OPTIONAL token introspection ([I-D.draft-mcguinness-oauth-mission], Section "Revocation"). A deployment that needs a Mission state change to take effect faster than token lifetime alone combines the propagation mechanisms this suite offers and sizes token lifetimes to match.¶
The mechanisms are each discovered from their own metadata, not from a separate posture list:¶
consulting Mission state at each derivation event (the token endpoint, refresh, Token Exchange), the issuance profile's always-present baseline, which does not invalidate already-issued self-contained tokens;¶
token introspection (Section 4), which returns
active: false for a token whose Mission state disallows use even
before the token expires, discovered from introspection_endpoint
and introspection_signing_alg_values_supported;¶
the Mission Status operation (Section 3) for per-request
state checks by high-assurance Resource Servers, discovered from
mission_status_endpoint; and¶
event-driven propagation of state changes over a Shared Signals
stream ([I-D.draft-mcguinness-oauth-mission-signals]), discovered
from mission_event_stream_endpoint.¶
A deployment advertises mission_max_stale_seconds (Section 9),
the maximum interval it tolerates for a Mission state change to take
effect, so a consumer can size token lifetimes and choose propagation
mechanisms to match. When the member is absent, no propagation bound
is declared: a consumer MUST size reliance to token lifetime alone
and MUST NOT assume a tighter bound.¶
Where the member is present, a status response's mission.fresh_until
MUST NOT exceed the response's issuance time plus the advertised
bound: the advertisement is the ceiling on every reliance window
built from these surfaces, including a runtime permit's validity
window, which is capped by the state view's freshness. As sizing
guidance, the runtime enforcement profile's recommended defaults
target an effective bound under 300 seconds for the high-consequence
classes; the 60-second value in this document's examples is a tight
deployment's choice, not a floor.¶
Where Mission revocation must take effect but only the baseline
derivation-time check is in use, Mission-bound access tokens SHOULD use
TTLs no longer than the declared mission_max_stale_seconds.
Deployments where revocation propagates out of band (token
introspection, per-request status checks, or the event stream) MAY use
longer TTLs.¶
Sizing to the bound is itself a propagation mechanism: expiry performs the state check, and the consumer integrates nothing (the runtime profile names this token-lifetime freshness for the classes below its high-consequence floor). Introspection and per-request status checks tighten specific paths; they are upgrades, not prerequisites.¶
This section is OPTIONAL and applies only to a deployment that adopts
one or more of the extensions above. An AS advertises the surfaces it
supports through the following members of its Authorization Server
metadata document [RFC8414], in addition to the issuance profile's
mission_bound_authorization_supported
([I-D.draft-mcguinness-oauth-mission], Section "Authorization Server
Metadata"). Unlike the issuance profile, which advertises only that
boolean, this document defines OAuth AS metadata members for the
endpoints and classes it introduces, so a consumer discovers them
through standard [RFC8414] discovery.¶
mission_status_endpoint:OPTIONAL. A string containing a URL. The URL of the dedicated Mission Status operation (Section 3). Present when the AS supports it.¶
mission_status_endpoint_auth_methods_supported:OPTIONAL. A JSON array of strings naming the authentication methods
the Mission Status endpoint (Section 3) accepts. Its value
space is a closed set defined by this document, not the OAuth Token
Endpoint Authentication Methods registry: mtls_client_auth
(mutual-TLS client authentication [RFC8705]), private_key_jwt
(private-key JWT client authentication [RFC7523]), and access_token
(a mission_status-scoped, sender-constrained access token, whose
presentation and DPoP or mTLS binding are described by this endpoint's
Protected Resource Metadata [RFC9728]). The first two values are
spelled identically to registered token-endpoint authentication
methods by intent; this member describes this endpoint, not the token
endpoint. Present, and SHOULD be advertised, when the AS serves the
Mission Status endpoint.¶
mission_status_endpoint_auth_signing_alg_values_supported:OPTIONAL. A JSON array of strings, the JWS [RFC7515] algorithm
values the AS accepts for the private_key_jwt client-assertion JWT
(Section 3.2) at the Mission Status endpoint.
This is the client-assertion verification set, not the response-signing
algorithms of mission_status_signing_alg_values_supported below.
none MUST NOT be used. Present when that endpoint lists
private_key_jwt.¶
mission_status_signing_alg_values_supported:OPTIONAL. A JSON array of strings. The JWS [RFC7515] algorithm
values the AS uses to sign the Mission Status Response shape
(Section 3.4), on whichever surfaces of this
profile family serve it (the dedicated Mission Status operation,
the Lifecycle endpoint, and Mission Management), mirroring
introspection_signing_alg_values_supported. These are the
response-signing algorithms, not the algorithms the AS accepts on
private_key_jwt client assertions (the endpoint auth-signing
members). Present when the AS serves any such surface.¶
mission_lifecycle_endpoint:OPTIONAL. A string containing a URL. The URL of the Mission Lifecycle endpoint (Section 6). Present when the AS supports it.¶
mission_lifecycle_endpoint_auth_methods_supported:OPTIONAL. A JSON array of strings naming the authentication methods
the Mission Lifecycle endpoint (Section 6)
accepts, from the same closed value space as
mission_status_endpoint_auth_methods_supported (with access_token
naming a mission_lifecycle-scoped access token). Present, and SHOULD
be advertised, when the AS serves the Mission Lifecycle endpoint.¶
mission_lifecycle_endpoint_auth_signing_alg_values_supported:OPTIONAL. A JSON array of strings, the JWS [RFC7515] algorithm
values the AS accepts for the private_key_jwt client-assertion JWT
(Section 3.2) at the Mission Lifecycle endpoint.
This is the client-assertion verification set, not the response-signing
algorithms of mission_status_signing_alg_values_supported.
none MUST NOT be used. Present when that endpoint lists
private_key_jwt.¶
mission_max_stale_seconds:OPTIONAL. An integer. The maximum tolerated interval, in seconds, for revocation propagation (Section 8). When absent, no bound is declared, and a consumer sizes reliance to token lifetime alone.¶
DPoP and mTLS support for issued credentials are read from the
standard dpop_signing_alg_values_supported [RFC9449] and
tls_client_certificate_bound_access_tokens [RFC8705] metadata;
this document defines no separate sender-constraint member. When the
introspection projection (Section 4) is signed, the
signing is discovered through the standard
introspection_signing_alg_values_supported metadata.¶
A discovery response from
https://as.example.com/.well-known/oauth-authorization-server,
showing the issuance profile members plus the extension members of
this document:¶
An implementation conforms to the issuance profile [I-D.draft-mcguinness-oauth-mission] or implements the Mission Issuer role of a binding that serves these surfaces, such as the standalone Mission Authority Server [I-D.draft-mcguinness-mission-authority-server]. Each extension in this document is independently OPTIONAL; an implementation names the ones it supports (for example, "issuance profile with Mission Status and Mission Lifecycle"), and an implementation that supports none of them is still a conforming issuance profile.¶
An implementation claiming an extension MUST meet its requirements:¶
Mission Status: serve the dedicated Mission Status operation
(Section 3) with JWS-signed responses
(application/mission-status-response+jwt), the authentication and
read authorization of Section 3.2, the
anti-oracle property
(Section 3.6), and the error shape of
Section 3.7; and advertise mission_status_endpoint and
mission_status_endpoint_auth_methods_supported.¶
Introspection projection: carry the Mission projection on the introspection response (Section 4), returning it as a [RFC9701]-signed response where end-to-end integrity is required.¶
Mission Lifecycle: serve the management endpoint
(Section 6), gate the suspended and
completed states it introduces exactly as the issuance profile gates
on non-active state, and advertise mission_lifecycle_endpoint and
mission_lifecycle_endpoint_auth_methods_supported.¶
Mission Completion: issue and gate terminal_when entries per
Section 7, meeting the requirements of
Section 7.9.¶
Revocation propagation: advertise mission_max_stale_seconds
and size Mission-bound access-token TTLs to it
(Section 8).¶
An implementation meets the following requirement independent of which extensions above it claims. Every issuer-held narrowing mechanism a deployment runs, this profile's discharge or a companion profile's own overlay alike, MUST feed the single Effective Authority Set computation. Every derivation and every authority-reporting surface MUST use that same computation; no mechanism computes a parallel view, and no surface reports authority the computation has not reduced.¶
The security considerations of the issuance profile [I-D.draft-mcguinness-oauth-mission] apply in full. This section covers threats specific to the extensions defined here.¶
Per the anti-oracle property (Section 3.6), the AS
MUST NOT let a caller readily distinguish an unknown mission_id from a
known-but-unauthorized one at the Status or Lifecycle endpoint. The
error shape of Section 3.7 requires identical body
content, identical HTTP status, and identical headers between the two
cases, and the AS SHOULD additionally suppress timing side channels
(for example by padding response time or by taking a uniform lookup
path). An implementation that leaks the distinction exposes the Mission
space to enumeration.¶
A Mission Status Response is bound to (caller sub, audience,
nonce, issuance time). Replay against a different caller or audience,
or beyond mission.fresh_until, is detectable by signature
verification and by verifying the bindings; a consumer MUST verify all
the checks of Section 3.4 before honoring a response. A
response cached and replayed by the same caller within
mission.fresh_until is equivalent to a fresh response; a consumer MUST NOT use a cached response after mission.fresh_until, with the skew
tolerance of Section 3.5.¶
The Mission Status operation is on the consumption path of every
Mission-bound credential validation in deployments where consumers query
Mission Status per request.
The AS MUST implement per-consumer rate limiting (returning
rate_limited, Section 3.7) and SHOULD encourage
consumer-side caching (Section 3.5) to reduce traffic.¶
When the introspection projection is signed
(Section 4), it uses [RFC9701], which is scoped to
token introspection. The dedicated Mission Status operation uses a new
media type (application/mission-status-response+jwt, Section 13) and a
JWS [RFC7515], because [RFC9701] does not apply to a lookup keyed by
mission_id. Implementations MUST NOT use [RFC9701] for the
dedicated Mission Status operation, and MUST NOT accept an unsigned
response from the dedicated Mission Status operation in place of the
signed form it requires.¶
The AS signs Mission Status and Lifecycle responses with a key from
its jwks_uri. The AS MUST keep the public JWK for every kid it
has signed such a response under resolvable in its jwks_uri for at
least the Mission record retention period, so an archived
application/mission-status-response+jwt remains verifiable for
audit and dispute. This is the issuance profile's retired-key rule
([I-D.draft-mcguinness-oauth-mission]), with the record retention
period as the bound. A key known or suspected
compromised is the exception: the AS removes it, and the Mandate
profile's compromise-time rule governs how artifacts signed under it
are then classified.¶
The completion capability (Section 7) adds the following:¶
Monotonic by construction. Discharge only removes an entry's authority,
so it is not a path to escalation; a compromised or injected agent
cannot use terminal_when to widen authority, and the worst it can do
is retire its own authority sooner. That is not an escalation, but a
forced premature discharge is a denial-of-service on the task
(authority the task still needs is withdrawn) and, where discharge is
relied on as a guardrail, retires that guardrail early. Discharge
authority (Section 6.2.1) bounds who can force it.¶
Fail closed on unknown constraint. A consumer that does not understand
the terminal_when constraint MUST refuse the entry
(Section 7.5); ignoring the constraint would let a discharged
entry continue to be narrowed, projected, or enforced, defeating
discharge.¶
Notification delivery is a temporary widening, not a fail-closed property. Before the AS receives and commits a discharge, it continues issuing against the entry: a lost or suppressed notification is a temporary widening relative to the real-world event, bounded by authenticated at-least-once delivery with retries to an idempotent acknowledgement (Section 6.2.4), monitoring and reconciliation, and the Mission's and its tokens' own lifetimes. This is not a fail-closed property: a deployment requiring cannot-determine-means-no-issuance runs a synchronous status or policy check outside this baseline.¶
RS enforcement honesty. A stateless Resource Server cannot evaluate issuer-held discharge state from the token alone; it honors the issued token until expiry. Prompt cutoff on a discharged entry requires status (Section 3), introspection (Section 4), or runtime enforcement (Section 7.7); an entry constraint the enforcing party does not understand still fails closed (Section 7.5).¶
Already-issued tokens. The window between discharge and the expiry of a token already issued is the same residual revocation carries, bounded the same way (Section 7.3, Section 7.7).¶
This document inherits OAuth 2.0 Best Current Practice [RFC9700] for the OAuth surfaces it composes with; implementers MUST follow current OAuth security guidance.¶
The privacy considerations of the issuance profile [I-D.draft-mcguinness-oauth-mission] apply in full. This section covers privacy specific to the extensions here.¶
The Mission Status operation (Section 3) and the
introspection projection (Section 4) disclose
Mission state, the
authority_hash, and the audience-scoped authorization_details to
the authenticated, authorized requester. A deployment MUST treat both
as Mission information-disclosure surfaces with the same privacy
posture, audience-filtering the disclosed authority so a consumer
never sees entries addressed to other audiences
(Section 3.4).¶
The AS records Status and Lifecycle requests (containing
mission_id, audience, caller, and timing) in audit logs.
Deployments MUST treat these logs as PII sinks per the issuance
profile's privacy considerations.¶
A terminal_when condition can reveal task structure: event_type may
name a business event, a case, or a record whose mere existence is
sensitive, and it rides the token where the entry is carried. A
deployment SHOULD treat it as it treats other authority detail, and
SHOULD avoid event identifiers that disclose more than the consuming
party needs. discharge_policy is an opaque selector and does not
itself name a business event, but its resolution is deployment-defined
and MAY correlate with a class of sensitive events; a deployment
SHOULD weigh that when publishing its meaning. The event_id,
evidence_ref, evidence_digest, and observed_at a discharge
request carries (Section 6.2) do not ride the token; they
land only in issuer audit records, which deployments MUST treat as
Mission information-disclosure surfaces per the audit-logging rule
above.¶
This document requests IANA actions for OAuth AS metadata members, a
media type, and a registration in the issuance profile's Mission
Common Constraints registry. It defines no new registry of its own:
the endpoint authentication-method value space is a closed set defined
inline (Section 9), and the terminal_when Common Constraint is
registered in the issuance profile's registry
([I-D.draft-mcguinness-oauth-mission]), not established as a
registry here (Section 13.4).¶
IANA is requested to register one media type per [RFC6838].¶
Type name: application¶
Subtype name: mission-status-response+jwt¶
Required parameters: none¶
Optional parameters: none¶
Encoding considerations: binary; JWS Compact Serialization¶
Security considerations: see Section 11¶
Interoperability considerations: see this document¶
Published specification: this document¶
Applications that use this media type: OAuth Mission-Bound consumers¶
Fragment identifier considerations: not applicable¶
Restrictions on usage: none¶
Provisional registration: no¶
Magic number(s): none¶
File extension(s): none¶
Macintosh file type code(s): none¶
Person & email address to contact: Karl McGuinness public@karlmcguinness.com¶
Intended usage: COMMON¶
Author/Change controller: IETF¶
This document requests registration of two states in the issuance profile's Mission Lifecycle States registry ([I-D.draft-mcguinness-oauth-mission]), under that registry's Specification Required policy:¶
| Value | Terminal | Semantics | Change Controller | Reference |
|---|---|---|---|---|
suspended
|
no | A paused Mission that derives no tokens until resumed. | IETF | this document, Section 6 |
completed
|
yes | Records successful completion of the Mission. | IETF | this document, Section 6 |
The completion capability (Section 7) registers one Common Constraint in the issuance profile's Mission Common Constraints registry ([I-D.draft-mcguinness-oauth-mission]), under that registry's Specification Required policy. This document supplies the registration's required fields:¶
Key Name: terminal_when¶
Value Space: a JSON array of one or more completion-condition
objects, each with a REQUIRED event_type (string) and an OPTIONAL
discharge_policy (string, an opaque selector); no two conditions
in one array share a canonical form (Section 7.2). This Value
Space is a breaking change, while this experimental draft's
registration is still open, to the one a prior revision registered:
event_source and max_staleness are removed and discharge_policy
is added.¶
Subset Rule: a candidate value is no broader than a reference value when the candidate's condition array contains every condition of the reference, compared structurally after the issuance profile's canonicalization; the candidate MAY add further conditions (Section 7.4).¶
Intersection Rule: the union of the two condition arrays, where
condition identity is byte equality of each condition object's
canonical form under the issuance profile's canonicalization
([I-D.draft-mcguinness-oauth-mission]): byte-identical conditions
collapse to one, and the union is sorted by the lexicographic order
of those canonical bytes, so two implementations produce the
identical array and the identical authority_hash.¶
Change Controller: IETF¶
Reference: this document, Section 7.2¶
terminal_when is a constraints member of the mission_resource_access
authorization details type defined by the issuance profile
([I-D.draft-mcguinness-oauth-mission]). event_type values are
deployment- or registry-defined and opaque to this document, as
purpose is, so this document establishes no registry of event types.¶
This document registers no new Well-Known URI. The metadata members of
Section 9 are added to the OAuth Authorization Server Metadata
document at /.well-known/oauth-authorization-server [RFC8414].¶
The author thanks the implementers and reviewers of the Mission-Bound Authorization work for feedback that shaped these extensions.¶