| Internet-Draft | OAuth APM | June 2026 |
| Vicente | Expires 7 December 2026 | [Page] |
This document describes the Authorization Posture Mechanism (APM), a method by which an OAuth 2.0 [RFC6749] authorization server, or a resource server acting on its behalf, re-evaluates the mutual consistency of three bound factors -- the client certificate, the access token, and the device posture -- on a per-request basis for privileged operations, rather than only at session establishment. When re-evaluated posture degrades relative to the posture under which the token was issued, APM defines deterministic, least-privilege Graduated Outcomes including scope reduction and method restriction, rather than a binary allow or deny.¶
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 7 December 2026.¶
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.¶
OAuth 2.0 [RFC6749] and related mechanisms bind tokens to a client at issuance time. Certificate-bound access tokens [RFC8705] and Demonstrating Proof of Possession (DPoP) [RFC9449] strengthen the binding between a token and a key. Step-up authentication [RFC9470] allows a resource server to demand stronger authentication for specific requests. These mechanisms are predominantly evaluated per session or per challenge. Continuous Access Evaluation [CAEP] propagates security-event signals between providers but does not, by itself, define a per-request consistency computation across certificate, token, and posture at the point of enforcement.¶
APM addresses a complementary problem: at the granularity of an individual privileged request, re-computing whether the presented certificate, the presented token, and the current device posture remain mutually consistent with the posture under which the token was issued, and defining what happens when they do not.¶
[I-D.ietf-oauth-attestation-based-client-auth] defines attestation-based client authentication but explicitly leaves device-attestation details out of scope and operates at authentication time. APM occupies the intersection: an issuance-time-anchored, per-request consistency check with deterministic graduated outcomes. APM graduates the authorization policy rather than applying a binary permit or deny: when posture degrades, the mechanism reduces to the most permissive authorization the current posture supports. The specific decision function that maps a degradation to an outcome class is implementation-defined and out of scope of this document; see the Applicability section of the corresponding Sanctum SecOps publication.¶
This section specifies functional requirements for an APM solution. Requirements describe what a conforming mechanism SHOULD satisfy; they do not constitute a protocol specification.¶
For each Privileged Request, the enforcing entity SHOULD assemble a
Consistency View comprising (a) the client certificate or DPoP key
thumbprint, (b) the bound access token's claims including cnf, and
(c) an integrity-protected device-posture signal associated with the
request.¶
At token issuance, the authorization server SHOULD record the security posture of the requesting client as the Issuance Posture, associated with the token either as a signed claim or as server-side metadata accessible via token introspection [RFC7662].¶
The enforcing entity SHOULD evaluate the Consistency View against the Issuance Posture synchronously with processing of the Privileged Request. The evaluation function SHOULD be deterministic: identical inputs MUST produce the same outcome classification.¶
The enforcing entity SHOULD produce Graduated Outcomes ordered by the least-privilege principle: Permit, Scope Reduction, Method Restriction, and Full Denial, applied proportionally to the degree of degradation.¶
Method Restriction SHOULD be a distinct outcome class, expressible in
terms of HTTP methods or RAR actions per [RFC9396] §2.2. The
response MUST convey the permitted method or operation set.¶
Scope Reduction MUST NOT be implemented by modifying the access token. It MUST be applied by the resource server or APM Enforcement Point as an additional constraint during request processing.¶
A deployment SHOULD define a policy that maps posture degradation dimensions to outcome classes in a deterministic, auditable manner independent of transient state beyond the Consistency View and Issuance Posture.¶
The device-posture signal MUST be integrity-protected. Integrity protection SHOULD be cryptographic. The signing authority SHOULD be distinct from the client itself.¶
An APM mechanism MUST operate as an additive layer over existing
sender-constraining mechanisms. It MUST NOT weaken the cnf/x5t#S256
binding of [RFC8705] or the cnf/jkt binding of [RFC9449].
Implementations that do not recognize APM parameters MUST ignore them.¶
A Scope Reduction or Method Restriction outcome MUST NOT be interpreted as a token revocation event. The token remains valid for subsequent requests, which may yield different outcome classifications if posture is restored.¶
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.¶
The following terms are used throughout this document:¶
the tuple of (client certificate, access token and its bound claims, current device-posture signal) assembled for a single privileged request.¶
the device-posture state recorded at the time the access token was issued.¶
a determination that the current device-posture signal is materially weaker than the Issuance Posture.¶
one of a defined set of deterministic, least-privilege responses to a detected Posture Degradation: scope_reduction, method_restriction, or full_denial.¶
an authorization server or resource server that implements the consistency-view evaluation described in this document.¶
For each privileged request, an APM Enforcement Point executes the following five-step state machine:¶
+----------------------+
| Request Received |
+----------+-----------+
|
v
+----------+-----------+
| Step 1: Assemble |
| Consistency View |
+----------+-----------+
|
+----------v-----------+
| Step 2: Cert |
| Thumbprint Check |
+----------+-----------+
| |
PASS FAIL -----> FULL_DENIAL
v
+----------+-----------+
| Step 3: DPoP Key |
| Binding Check |
+----------+-----------+
| |
PASS FAIL -----> FULL_DENIAL
v
+----------+-----------+
| Step 4: Posture vs. |
| Issuance Posture |
+----------+-----------+
| |
CONSISTENT DEGRADED
| |
v v
200 OK Step 5: Dispatch
Graduated Outcome
(scope_red | method_rest | full_deny)
¶
An endpoint determines which requests are "privileged" by local policy. APM is a defense-in-depth control expected to be applied to a subset of high-value operations. Applying APM to every request increases the side-channel surface described in Section 9.4.¶
When Posture Degradation is detected, an APM Enforcement Point applies one of the following Graduated Outcome classes, ordered from least restrictive to most restrictive:¶
scope_reduction: narrowing the effective authorization per [RFC9396];¶
method_restriction: limiting the permitted HTTP method;¶
full_denial: refusing the request.¶
Policy authors MUST design graduated outcomes so that every downgrade path leads to a safe, self-consistent authorization state. Each Graduated Outcome MUST correspond to a complete access control policy, not a partial policy derived by removing permissions from the full policy.¶
The pseudocode below specifies the normative evaluation procedure:¶
function EvaluateConsistencyView(request, token, postureSignal):
# Step 1: Assemble Consistency View.
view = ConsistencyView {
cert: request.mtlsClientCertificate,
token: token,
posture: postureSignal
}
# Step 2: RFC 8705 cert thumbprint check.
tokenCertHash = token.cnf["x5t#S256"]
presentedCertHash = BASE64URL(SHA256(DER_ENCODE(view.cert)))
if tokenCertHash != presentedCertHash:
return FULL_DENIAL("cert_thumbprint_mismatch")
# Step 3: RFC 9449 DPoP key binding check (if applicable).
if token.isDPoP:
dpopProof = request.header["DPoP"]
dpopKey = dpopProof.header["jwk"]
tokenKeyThumbprint = token.cnf["jkt"]
proofKeyThumbprint = JWK_SHA256_THUMBPRINT(dpopKey)
if tokenKeyThumbprint != proofKeyThumbprint:
return FULL_DENIAL("dpop_key_mismatch")
if not ValidateDPoP(dpopProof, request.method, request.uri, token):
return FULL_DENIAL("dpop_proof_invalid")
# Step 4: Posture consistency evaluation.
issuancePosture = token.claims["apm_issuance_posture"]
currentPosture = view.posture
degradationResult = ComputePostureDegradation(
issuancePosture, currentPosture)
# ComputePostureDegradation is implementation-defined.
# Its parameters, scoring, and thresholds are out of scope.
if degradationResult == CONSISTENT:
return GRANT(token.scope)
# Step 5: Decision-function dispatch (implementation-defined).
outcome = DispatchGraduatedOutcome(degradationResult)
if outcome.class == "scope_reduction":
effectiveScope = outcome.effective_scope
if request.requiresScope NOT IN effectiveScope:
return HTTP_403(authorizationDetails(outcome))
else:
return HTTP_200_WITH_REDUCED_SCOPE(effectiveScope,
authorizationDetails(outcome))
if outcome.class == "method_restriction":
permittedMethods = outcome.permitted_methods
if request.method NOT IN permittedMethods:
return HTTP_405(allow=permittedMethods,
authorizationDetails(outcome))
else:
return HTTP_200_WITH_METHOD_RESTRICTION(
authorizationDetails(outcome))
if outcome.class == "full_denial":
return HTTP_403(authorizationDetails(outcome))
¶
Implementations MUST NOT cache introspection responses for tokens where APM is active, or MUST use a freshness window for cached responses shorter than the expected posture-change window.¶
When a Graduated Outcome is accompanied by an invitation to
re-authenticate (step-up per [RFC9470]), the resource server SHOULD
return a WWW-Authenticate challenge:¶
For Bearer-bound tokens:¶
WWW-Authenticate: Bearer
error="insufficient_user_authentication",
error_description="Device posture degraded; re-authentication required",
acr_values="<acceptable ACR values>",
scope="<scope hint for step-up>"
¶
For DPoP-bound tokens:¶
WWW-Authenticate: DPoP
error="insufficient_user_authentication",
acr_values="<acceptable ACR values>"
¶
+--------------------+-------------------+-----------------------------+ | APM Outcome Class | HTTP Status | Rationale | +--------------------+-------------------+-----------------------------+ | scope_reduction | 200 OK or | If effective_scope permits | | | 403 Forbidden | the resource, 200 with | | | | reduced scope. If not, 403. | +--------------------+-------------------+-----------------------------+ | method_restriction | 405 Method Not | Allow header SHOULD list | | | Allowed | permitted_methods. | +--------------------+-------------------+-----------------------------+ | full_denial | 403 Forbidden | Explicit denial regardless | | | | of token validity. | +--------------------+-------------------+-----------------------------+ | Step-up invitation | 401 Unauthorized | When re-authentication at | | | with WWW- | higher assurance would | | | Authenticate | restore access. | +--------------------+-------------------+-----------------------------+¶
APM treats the posture signal as an opaque, integrity-protected input. The specific attestation format, measurement protocol, and trust chain for the posture signal are outside the scope of this document.¶
An APM Enforcement Point MUST require that:
(1) the posture signal is integrity-protected (signed or MAC'd by a
trusted posture authority);
(2) the posture signal includes an iat (issued-at) claim for freshness
evaluation;
(3) the posture signal includes a subject identifier binding it to the
device or client instance;
(4) the posture signal SHOULD include a unique identifier (jti) for
replay detection.¶
While not mandating a specific format, this document recommends the following JWT shape for implementations requiring an interoperable baseline:¶
{
"iss": "https://posture.example.com",
"sub": "device-12345",
"iat": 1735689600,
"jti": "4f9a2b1c-e8d7-4a3b-9c2e-1d0f8a7b6c5d",
"posture": {
"attestation_class": "hardware_tpm",
"device_compliance": "compliant",
"last_attestation_iat": 1735689590,
"binding_cert_thumbprint_s256": "OKy4RNzHvwY..."
}
}
¶
This schema MUST NOT include scoring weights, risk-band thresholds, or
decision budgets. The fields above expose only the observable posture
properties. The attestation_class field is an implementation-defined
string (e.g., hardware_tpm, software_tee, none); ordering and thresholds
are implementation-defined and out of scope.¶
The following table describes how APM relates to each relevant protocol:¶
+----------------------------------+--------------------------------------+ | Mechanism | Relationship and What APM Adds | +----------------------------------+--------------------------------------+ | RFC 8705 mTLS Certificate-Bound | APM consistency view includes the | | Tokens | mTLS cert thumbprint check (Step 2). | | | APM re-verifies per privileged | | | request; RFC 8705 binds at issuance. | +----------------------------------+--------------------------------------+ | RFC 9449 DPoP | APM consistency view includes DPoP | | | proof validation (Step 3). APM | | | re-verifies per request. | +----------------------------------+--------------------------------------+ | RFC 9470 Step-Up Authentication | APM MAY trigger step-up by returning | | | 401 + WWW-Authenticate with | | | acr_values. RFC 9470 defines the | | | challenge; APM decides when to use | | | it based on posture evaluation. | +----------------------------------+--------------------------------------+ | RFC 9396 Rich Authorization | APM graduated outcomes are conveyed | | Requests | as urn:apm:graduated-outcome:v1 | | | authorization_details objects. | +----------------------------------+--------------------------------------+ | RFC 7662 Token Introspection | Orthogonal. Introspection determines | | | token validity; APM determines | | | posture consistency within the | | | valid-token window. APM is layered | | | on top of introspection. | +----------------------------------+--------------------------------------+ | draft-ietf-oauth-attestation- | Orthogonal. Attestation-based client | | based-client-auth | auth operates at authentication time.| | | APM extends attestation into per- | | | request enforcement throughout the | | | token lifetime. | +----------------------------------+--------------------------------------+ | OpenID CAEP 1.0 | Composable. CAEP provides async | | | event-push; APM provides synchronous | | | per-request enforcement. CAEP events | | | can feed APM's posture-state cache. | | | CAEP SETs MUST be signed and | | | verified against a trusted-issuer | | | allowlist before use as posture | | | inputs. | +----------------------------------+--------------------------------------+¶
The RECOMMENDED layering for deployments that combine all mechanisms is: Layer A (token validity) per [RFC7662]; Layer B-core (cert binding) per [RFC8705]; Layer C (DPoP) per [RFC9449] where applicable; Layer D (APM consistency) per this document.¶
The following table enumerates gaps in existing mechanisms and how APM addresses each.¶
+---------------------------+------------------------------+---------------------------+ | Prior art | Gap | How APM addresses it | +---------------------------+------------------------------+---------------------------+ | RFC 8705 mTLS cert-bound | Proves key possession at | APM adds per-request | | tokens | issuance; does not re-check | cert-thumbprint check | | (https://www.rfc-editor | cert validity, revocation, | (Step 2) and per-request | | .org/rfc/rfc8705) | or device posture per | posture evaluation | | | request (RFC 8705 §6.5). | (Steps 4-5). | +---------------------------+------------------------------+---------------------------+ | RFC 9449 DPoP | Proves key possession and | APM extends DPoP | | (https://www.rfc-editor | method/URI binding per | per-request enforcement | | .org/rfc/rfc9449) | request; does not evaluate | to include device-posture | | | device posture | consistency evaluation. | | | (RFC 9449 §11.7, §11.11). | | +---------------------------+------------------------------+---------------------------+ | RFC 9470 Step-Up | Reactive, fires on | APM produces graduated | | Authentication | authentication failures; | outcomes (scope_reduction,| | (https://www.rfc-editor | outcome is binary (re-auth | method_restriction) for | | .org/rfc/rfc9470) | or deny); no device posture. | minor degradations rather | | | | than binary deny. | +---------------------------+------------------------------+---------------------------+ | RFC 9396 Rich | Fine-grained initial grants | APM applies post-issuance | | Authorization Requests | are static for the token | narrowing of effective | | (https://www.rfc-editor | lifetime; no post-issuance | scope and methods via | | .org/rfc/rfc9396) | narrowing on posture change | Graduated Outcomes. | | | (RFC 9396 §5.3). | | +---------------------------+------------------------------+---------------------------+ | OpenID CAEP 1.0 | Asynchronous event push; | APM provides synchronous | | (https://openid.net/specs | temporal gap between event | per-request enforcement; | | /openid-caep-1_0-final | and enforcement; binary | CAEP events MAY feed | | .html) | compliance vocabulary; no | APM's posture-state cache | | | per-request posture check. | (composable). | +---------------------------+------------------------------+---------------------------+ | draft-ietf-oauth- | Attestation operates at | APM extends attestation | | attestation-based-client- | authentication time; no | into per-request | | auth | normative mechanism to force | enforcement throughout | | (https://datatracker.ietf | re-attestation on posture | the token lifetime. | | .org/doc/draft-ietf-oauth | degradation within a JWT's | | | -attestation-based-client | validity window. | | | -auth/) | | | +---------------------------+------------------------------+---------------------------+¶
APM is a defense-in-depth mechanism and MUST NOT weaken any binding defined by [RFC8705] or [RFC9449]. The posture signal is an input to an authorization decision and MUST be integrity-protected; an APM Enforcement Point MUST NOT base a Graduated Outcome on an unauthenticated posture signal. Specific tuning parameters used by implementations of this mechanism are out of scope of this document; see the Applicability section of the corresponding Sanctum SecOps publication.¶
A posture signal valid at token-issuance time may be captured and replayed
by an adversary to make the resource server believe posture has not
degraded. Mitigations: (1) the posture signal MUST include an iat claim;
the APM Enforcement Point SHOULD reject signals with an iat older than
an implementation-defined freshness window; (2) the resource server MAY
include a server-generated nonce in a challenge, providing challenge-
response-based replay protection; (3) if the posture signal is bound to
the access token via the same DPoP key [RFC9449], replaying it under a
different token requires breaking the binding. The formal model for replay
resistance in authenticated protocols is established in [BellareRogaway].¶
An adversary who can manipulate the posture-signal channel can inject a degraded posture signal to obtain a downgraded token -- for example, obtaining a scoped-down token that avoids audit scrutiny, or triggering a method_restriction outcome that permits read access without the write- access audit trail. Mitigations: (1) the posture signal MUST be integrity- protected; (2) policy authors SHOULD design graduated outcomes so that every downgrade path leads to a safe, self-consistent authorization state; an operation that is only safe at full authorization SHOULD map to full_denial rather than scope_reduction when posture degrades.¶
The confused-deputy problem arises in APM when a partially-authorized (downgraded) request is processed by a resource server that believes it is acting on behalf of a fully-authorized principal. Each Graduated Outcome MUST correspond to a complete access control policy, not a partial policy derived by removing permissions from the full policy. Policy authors MUST audit every graduated outcome in isolation, not only relative to the full-authorization policy.¶
Because APM re-evaluates posture on every privileged request, the resource server observes the posture signal at high frequency. Implementations MUST NOT return different response codes or timing based solely on posture quality in a way that leaks posture details not already visible from the authorization outcome. APM SHOULD be applied only to operations designated as privileged. The principle that authenticated key exchange security requires binding identities to session keys via signatures and MACs together ([Krawczyk2003]) is analogous to APM's multi-factor consistency check; the same binding-integrity properties SHOULD be maintained throughout the APM enforcement path.¶
The remaining threat considerations (compromise of the posture-signal channel, DPoP and mTLS binding compromise, CAEP signal injection) are addressed by the posture-signal integrity requirements in Section 4, the trusted-issuer allowlist requirement for CAEP inputs in Section 7, and the independence requirement that the posture signal used by APM SHOULD be a direct attestation from the device itself, not solely derived from CAEP events.¶
This section records the status of known implementations of the protocol defined by this specification at the time of posting, as required by [RFC7942].¶
Organization: Sanctum SecOps LLC¶
Description: An experimental Go implementation of the APM Consistency View
assembly and graduated-outcome dispatch, covering the certificate-thumbprint
check (Step 2), DPoP-key-binding check (Step 3), and graduated-outcome
application for all three outcome classes defined in Section 4.
The wire format encoding of authorization_details per Section 5 and
the WWW-Authenticate challenge format per [RFC9470] are implemented.
Located at poc/apm/ in the companion repository at
https://github.com/Sanc-Admin/sanctum-ietf (private until counsel
hand-off).¶
Coverage: Consistency View assembly and all five steps of the algorithm in Section 4, wire-format encoding of APM outcome objects, and HTTP status code mapping per Section 5.¶
Maturity: Experimental reference implementation. This implementation is provided for early interoperability testing only and MUST NOT be deployed in production or used for security-critical operations without review by qualified security and legal counsel.¶
All JWT and certificate thumbprints are synthetic. No real credentials are used.¶
Context: Device compliance has dropped (MDM reports a policy violation).
Current posture has device_compliance = non_compliant while the Issuance
Posture had compliant.¶
Current posture signal JWT payload (synthetic):¶
{
"iss": "https://posture.example.com",
"sub": "device-12345",
"iat": 1735689700,
"jti": "9e8d7c6b-5a4f-3e2d-1c0b-9a8f7e6d5c4b",
"posture": {
"attestation_class": "hardware_tpm",
"device_compliance": "non_compliant",
"last_attestation_iat": 1735689690
}
}
¶
APM Consistency View evaluation:¶
Step 2: cert.thumbprint matches token cnf -- PASS
Step 3: DPoP not bound -- SKIP
Step 4: issuancePosture.device_compliance = compliant
currentPosture.device_compliance = non_compliant -- DEGRADED
Step 5: DispatchGraduatedOutcome -> scope_reduction
effective_scope = "read" (admin and write removed)
¶
Response (resource requires write scope, not in effective_scope):¶
HTTP/1.1 403 Forbidden
Content-Type: application/json
WWW-Authenticate: Bearer
error="insufficient_user_authentication",
acr_values="urn:example:acr:high-assurance",
scope="read write"
{
"error": "insufficient_scope",
"error_description": "Device posture degraded; authorization reduced",
"authorization_details": [{
"type": "urn:apm:graduated-outcome:v1",
"class": "scope_reduction",
"original_scope": "read write admin",
"effective_scope": "read",
"reason_code": "DEVICE_COMPLIANCE_CHANGED",
"apm_decision_id": "apm-7f3c2b1a-0d9e-4c8b-a2f1-3d4e5f6a7b8c"
}]
}
¶
The client MUST obtain a new token after re-establishing device posture at the required compliance level before accessing write-scoped resources.¶
NIST SP 800-207 [NIST.SP.800-207] defines a three-component decision plane for Zero Trust Architecture. APM maps to this architecture as follows:¶
+---------------------+------------------------------------------------+ | ZTA Component | APM Role | +---------------------+------------------------------------------------+ | Policy Enforcement | The APM Enforcement Point (resource server or | | Point (PEP) | co-located component). Assembles the | | | Consistency View (REQ-1), executes sender- | | | constraint verification (Steps 2-3), and | | | enforces the Graduated Outcome. Corresponds | | | to NIST SP 800-207 Section 3 PEP. | +---------------------+------------------------------------------------+ | Policy Engine (PE) | Consumes the Consistency View and Issuance | | | Posture and produces an outcome class. May be | | | co-located with the PEP or queried per-request.| | | Implements the deterministic outcome mapping | | | required by REQ-7. | +---------------------+------------------------------------------------+ | Policy | Communicates scope-reduction and method- | | Administrator (PA) | restriction policy from the authorization | | | server to the PEP. Also records the Issuance | | | Posture at token issuance time (REQ-2). | +---------------------+------------------------------------------------+¶
APM does not introduce new architectural roles beyond those defined in [NIST.SP.800-207]. It specifies the information flows -- specifically, the Consistency View and Issuance Posture -- that enable the PE to make the per-request graduated-outcome decisions that ZTA requires.¶
Informative reference: [NIST.SP.800-207].¶
The author thanks the OAuth Working Group for the certificate-binding, proof-of-possession, and step-up foundations on which this mechanism builds.¶