| Internet-Draft | OAuth Push Device Discovery | July 2026 |
| Bandyopadhayaya | Expires 30 January 2027 | [Page] |
This document defines a discovery, registration, attestation, and device-lifecycle layer for out-of-band OAuth 2.0 authenticator devices, allowing a single spec-compliant authenticator application to register with, and receive push-based wake signals from, any conforming Authorization Server, without requiring the Authorization Server operator to build and distribute its own dedicated mobile application. This document is intentionally agnostic to which back-channel authentication protocol ultimately consumes it; OpenID Connect Client-Initiated Backchannel Authentication (CIBA) Core is its first binding, defined in a separate companion document, but nothing in this document depends on CIBA or on OpenID Connect.¶
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 30 January 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.¶
Push-based multi-factor authentication (MFA) today is implemented as a closed, vertically integrated stack per Authorization Server (AS) vendor: a proprietary API, a proprietary push backend, and a proprietary mobile application. This produces three compounding costs for application and AS developers:¶
Vendor lock-in — the authenticator application only speaks to the AS that shipped it.¶
Fragmentation — no shared registration ceremony exists, unlike [RFC6238] (TOTP), where any application can generate codes for any AS from a shared secret.¶
Developer cost — offering push MFA requires building and maintaining a full mobile application, not just a backend integration.¶
This document defines a registration and device-lifecycle layer that removes these costs by letting any spec-compliant authenticator application serve push MFA for any spec-compliant AS.¶
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.¶
[RFC9126] (Pushed Authorization Requests, PAR)
covers moving authorization request parameters to a back-channel
POST before redirect. It does not address push delivery or
out-of-band devices. This document does not depend on PAR or its
pushed_authorization_request_endpoint; Section 4 instead borrows PAR's design pattern
(pushing sensitive parameters over a back-channel POST and
receiving a short-lived opaque reference in return) as its own
self-contained mechanism.¶
[RFC8414] (OAuth 2.0 Authorization Server Metadata) establishes the pattern this document follows for its own discovery document: a dedicated well-known metadata document with additive-only evolution and no explicit version field (Section 3.1).¶
OIDC CIBA Core [OIDC.CIBA] defines
/bc-authorize, auth_req_id, and the poll/ping/push
delivery modes. This document does not reference or depend on
CIBA; a device registered per this specification is usable by any
back-channel authentication protocol that defines a binding to it.
A companion document defines the CIBA binding: an
interaction_type request parameter on
/bc-authorize (Section 3.3) and a
device_revoked error extending CIBA's error surface (Section 5.1). This split follows the precedent of
WebAuthn [WebAuthn2] (a browser-facing API defined
by the W3C) and CTAP (an authenticator-facing protocol defined by
the FIDO Alliance) as companion specifications from different
bodies serving different interfaces to the same underlying model.¶
This document defines the registration and lifecycle layer; it takes no position on, and places no requirements on, the authentication protocol that ultimately wakes a registered device.¶
A conforming AS publishes a discovery document at a dedicated
well-known URI [RFC8615], following the [RFC8414] pattern rather than extending
/.well-known/openid-configuration. This keeps the
push-auth metadata document independently versionable and
cacheable, at the cost of a second discovery round trip for
clients that need both documents. A CIBA-binding AS additionally
publishes CIBA's own discovery fields per the companion binding
document; the two documents are independent but MAY
be operated by the same AS simultaneously.¶
GET /.well-known/oauth-push-notification HTTP/1.1 Host: oauth.example.com¶
{
"registration_endpoint":
"https://oauth.example.com/push/register",
"delivery_modes_supported": ["push", "ping", "poll"],
"interaction_type_supported":
["boolean", "number_choose", "input_manual"],
"minimum_interaction_type": "number_choose",
"registration_token_ttl": 300,
"signing_alg_values_supported": ["ES256"],
"push_relay_endpoint":
"https://relay.authenticator-vendor.com/notify",
"fallback_order": ["push", "poll"],
"client_attestation_required": true,
"trusted_authenticator_registries": [
"https://mds.push-auth-wg.org/v1",
"https://mds-backup.push-auth-wg.org/v1"
],
"minimum_attestation_level": "certified",
"revocation_endpoint":
"https://oauth.example.com/push/revoke",
"key_rotation_endpoint":
"https://oauth.example.com/push/rotate-key",
"device_management_endpoint":
"https://oauth.example.com/push/devices",
"max_devices_per_user": 5,
"push_wait_timeout_seconds": 10,
"error_response_format": "application/problem+json"
}
¶
Fields are flattened, not nested, to match established discovery document convention and to simplify JSON Schema validation. The document SHOULD be published against a formal JSON Schema (2020-12 [JSON.SCHEMA]); field registration follows an IANA registry established by this document (Section 9.2), so new fields, including protocol-binding-specific ones defined by companion documents, can be added without a version bump.¶
This document defines no explicit version field.
Following [RFC8414] precedent, evolution is
purely additive: new capabilities are advertised via new
_supported arrays or new optional fields, and
conformant clients MUST ignore members they do
not recognize. A version field would solve a breaking-change
problem this specification does not yet have; one can be
introduced later without disruption if that changes.¶
All endpoints defined in this document (registration_endpoint,
revocation_endpoint, key_rotation_endpoint,
device_management_endpoint) return errors as
application/problem+json per [RFC9457],
not the bare OAuth error/error_description
shape from Section 5.2 of [RFC6749]: these
endpoints need extension members that shape does not
accommodate cleanly.¶
{
"type":
"https://push-auth-wg.org/errors/registration_token_already_used",
"title": "Registration token already used",
"status": 400,
"detail":
"This registration token has already been redeemed.",
"device_id": null
}
¶
| Type slug | Status | Meaning |
|---|---|---|
| registration_token_already_used | 400 | Token already redeemed (register) |
| registration_token_expired | 400 | Token used past its TTL (register) |
| attestation_missing | 400 | Attestation required but absent (register) |
| attestation_invalid | 403 | Attestation failed verification (register) |
| attestation_untrusted | 403 | Issuer not trusted/below minimum level (register) |
| interaction_type_unsupported | 400 | Device below the AS's minimum ceremony (register) |
| nonce_replayed | 400 | Replay-Nonce reused/missing (revoke, rotate) |
| rate_limited | 429 | Too many requests (register, revoke, rotate) |
A consuming protocol's binding document MAY
define additional error codes for its own wake surface (e.g.
the CIBA binding's device_revoked, returned from
/bc-authorize) without modifying this registry.¶
registration_endpoint MUST return
429 with a Retry-After header on excessive
attempts, keyed by source IP and/or registration token; this is
the highest-value pre-authentication enumeration target.
revocation_endpoint and key_rotation_endpoint
SHOULD apply the same, keyed by device_id.¶
interaction_type describes the ceremony the user
performs on the authenticator when a request lands, a distinct
concern from delivery_modes_supported, which is
transport (push/ping/poll), not interaction. Three values are
defined:¶
Rich transaction detail (e.g. "Approve $500 to X") and
biometric-gated local confirmation are explicitly not additional
interaction_type values; they are payload-content and
local-authorization concerns respectively, and compose with any
of the three values above rather than replacing them.¶
This document defines the ceremony vocabulary and the
discovery-level capability/floor fields
(interaction_type_supported,
minimum_interaction_type). It does not define how a
specific back-channel authentication protocol requests a
ceremony per request, or carries the ceremony's content to the
user; that is a binding concern, defined by the companion CIBA
binding document for CIBA specifically.¶
Downgrade protection:
minimum_interaction_type lets the AS set a floor: a
consuming protocol's binding MUST NOT allow a
caller to request an interaction_type weaker than the
AS's floor. Without this, a caller could request
boolean on every request regardless of AS risk policy,
silently bypassing anti-fatigue protection the AS intends to
enforce.¶
Unsupported type: if an authenticator's
registration-time capability list (Section 4)
does not include the AS's minimum_interaction_type, the
AS MUST reject registration with
interaction_type_unsupported rather than accepting the
device and silently degrading to boolean at wake time.
A silent degrade would recreate the exact fatigue exposure
number_choose exists to close.¶
The user scans a QR code encoding a URL with the registration
token in the fragment, not the userinfo component:
https://oauth.example.com/push/enroll#{REGISTRATION_TOKEN}.
Fragments are never transmitted to servers, proxies, or logged
in access logs, unlike the deprecated
user:pass@host userinfo form (Section 3.2.1 of [RFC3986]), which risks leaking the
token via browser history, referrer headers, and QR-scanner
applications that open the link in a WebView before the
authenticator ever sees it. Authenticator vendors
MAY alternatively register a custom URL scheme
for direct OS-level handling.¶
REGISTRATION_TOKEN is itself a signed JSON Web Token
(JWT) [RFC7519] containing:¶
registration_token_ttl.¶
The authenticator resolves the discovery document at the host
encoded in the token's iss.¶
The authenticator POSTs to registration_endpoint with
the registration token, its push address (an APNs or FCM
token, delivered via the relay), a public key, the
interaction_type values it supports (Section 3.3), and attestation evidence per
client_attestation_required (Section 7). The AS MUST reject
registration with interaction_type_unsupported if the
device's supported set does not include
minimum_interaction_type.¶
This POST is modeled on the design pattern of [RFC9126], not on PAR itself: sensitive registration parameters are pushed over a back-channel POST and the AS returns a short-lived opaque reference plus the durable device credential:¶
{
"device_credential": "{opaque bearer credential,
scoped push_device}",
"registration_ref": "urn:push-reg:6a2f...",
"expires_in": 300
}
¶
The AS MUST reject a jti it has
already consumed (registration_token_already_used)
and MUST reject a token presented past
exp (registration_token_expired). The AS
MUST purge the consumed-jti record
only after exp has passed, not before, so an
expired-but-unconsumed token cannot be replayed after its
record is dropped.¶
device_credential is scoped push_device,
restricted to exactly: resolution by the consuming
authentication protocol (a device-address lookup, not a
bearer-scope check), and self-service calls to
revocation_endpoint / key_rotation_endpoint
for the same device (push:revoke:self,
push:rotate:self). AS admin console and RP-triggered
revocation use distinct scopes (push:revoke:admin,
push:revoke:rp respectively; see Section 5.1).¶
Once registered, the device is discoverable by any back-channel authentication protocol for which the AS has a binding; see the relevant companion document for how that protocol locates and wakes the device.¶
This endpoint follows the general revocation model of [RFC7009] (an authenticated POST that invalidates a credential), extended with the device-specific cascade and scope requirements below.¶
POST /push/revoke HTTP/1.1
Host: oauth.example.com
Authorization: Bearer {device_credential_or_client_assertion}
Content-Type: application/x-www-form-urlencoded
device_id={id}&reason={reason}
¶
Idempotent: revoking an already-revoked device returns
200.¶
Must cascade: any pending authentication request bound to
the device MUST be invalidated immediately. A
consuming protocol's binding document defines how this
surfaces to that protocol's callers (e.g. CIBA's
device_revoked error); this document only requires
that the cascade happen.¶
The AS SHOULD push a wake signal so the application can clear local key material without waiting for its next authentication attempt. This reuses the same opaque wake-and-pull mechanism as ordinary authentication requests (Section 6): there is no separate revocation payload shape.¶
{"wake_reason": "device_revoked", "ref_id": "{device_id}"}
¶
The application performs its normal authenticated pull to retrieve the reason and wipe local key material.¶
Distinct callers (application self-revocation, AS admin
console, RP-triggered offboarding) MUST use
distinct token scopes: push:revoke:self,
push:revoke:admin, push:revoke:rp
respectively.¶
Requests MUST include a
Replay-Nonce (issued by the AS on the prior response,
per the pattern of Section 6.4 of [RFC8555]) as
a JWS-protected nonce claim over the request body.
The AS validates single use and rejects reused or missing
nonces with nonce_replayed.¶
POST /push/rotate-key HTTP/1.1
Host: oauth.example.com
Authorization: Bearer {current_device_credential}
Content-Type: application/json
{
"device_id": "{id}",
"new_public_key": "{pem}",
"proof_of_possession":
"{signature over challenge, signed by the OLD key}"
}
¶
Rotation MUST be signed by the outgoing key.
Without proof of possession, rotation is a forgeable takeover
path for anyone holding a stolen device_id and bearer
token.¶
Grace window: the old public key remains
valid for verification by the consuming authentication
protocol until either (a) the new key completes one
successful signed authentication, or (b)
grace_period_seconds elapses (AS-configured,
RECOMMENDED default 300), whichever occurs
first. Rotation confirmation is asynchronous: the AS
MUST NOT invalidate the old key synchronously
in the rotate-key response, since an in-flight authentication
request may already be signed under it. When the rotation
reason is compromised rather than routine,
the AS SHOULD reduce or skip the grace
window.¶
Replay protection: same
Replay-Nonce requirement as Section 5.1.¶
Credential binding:
device_credential itself is bound using DPoP [RFC9449] to the key established at registration: a
jkt thumbprint is embedded in the credential at
issuance, and rotate/revoke/device-management calls
MUST present a DPoP proof for that key. This
extends the same binding Section 6 already
requires for the pull step to the credential itself, so
credential theft alone, without the private key, is
insufficient to rotate or revoke a device.¶
GET /push/devices HTTP/1.1
Host: oauth.example.com
Authorization: Bearer {user_session_token}
¶
Returns the list of registered devices (platform, registration time, last used, attestation status) backing a user-facing "manage your devices" view.¶
The AS enforces max_devices_per_user (discovery
document, RECOMMENDED default 5,
AS-configurable) at registration time.¶
Device replacement is a distinct, atomic
ceremony from plain add-new-device: pass
replaces_device_id on the registration POST (Section 4).¶
{
"registration_token": "...",
"replaces_device_id": "{old_id}"
}
¶
The old device is revoked only upon successful completion of
the new device's registration, avoiding a lockout if
registration fails partway through. Plain registration
(without replaces_device_id) is subject to the
max_devices_per_user cap.¶
Primary-device selection: the
RECOMMENDED default is to wake only the
most-recently-used registered device, not fan out to all,
matching common industry practice rather than a
multi-authenticator fan-out model, since push MFA lacks a
synchronous prompt moment to let the user disambiguate which
device just alerted. A device MAY be marked
is_primary via device_management_endpoint to
override recency-based selection. An AS or RP
MAY instead opt into a fan-out-to-all mode as a
documented alternative. A stated default matters here because
this document's value proposition depends on one generic
authenticator application behaving predictably across
different AS implementations.¶
A hard lockout (device lost, no other device registered) is out of scope for the device protocol itself; recovery mechanisms embedded in the credential protocol tend to become bypass vectors. It MUST have a defined path at the AS/tenant level:¶
Mandatory baseline: admin-console-forced
re-registration. A tenant or AS admin MAY
revoke all devices for a user (push:revoke:admin) and
issue a fresh registration token out of band (e.g. via a
verified-identity support flow), re-entering the flow at
Section 4. This requires no new protocol
mechanism; it is existing revoke plus existing registration,
admin-initiated.¶
Optional enhancement: the AS MAY support single-use backup codes, issued at registration time, redeemable by the consuming authentication protocol in place of a device-signed assertion, for self-service recovery when no device is reachable. Backup codes reintroduce a shared-secret bearer credential and reduce the phishing-resistance value of device attestation; RPs SHOULD gate this by risk tier rather than enabling it by default.¶
Three delivery approaches were evaluated:¶
| Approach | Verdict |
|---|---|
| Poll (user-initiated) | Fallback only; no ambient nudge |
| AS to APNs/FCM directly | Rejected; recreates per-AS platform lock-in |
| Push via relay | Recommended; only the authenticator vendor needs platform push credentials |
Payload security requirements:¶
The push payload MUST be an opaque wake signal only:¶
{"wake_reason": "auth_request" | "device_revoked",
"ref_id": "..."}
¶
No scope, binding message, or user context, since platform push infrastructure can inspect payloads in transit. A single wake shape covers both ordinary authentication requests and device-revocation signals; there is no separate revocation payload type.¶
On wake, the application MUST perform an authenticated pull (mTLS or a DPoP-bound token) to retrieve request details.¶
The pull response MUST be encrypted to the
device's registered public key (JWE), mirroring the Web Push
encryption model of [RFC8291], which mandates
payload encryption to the subscriber's public key precisely
because push infrastructure is an untrusted intermediary. This
converts the relay from a trusted courier into a zero-trust hop
that only ever sees ciphertext plus a routing reference
(ref_id is deliberately not secret; it is routing
metadata only).¶
The authenticator's report of which delivery mode it actually used (push vs. poll fallback) MUST itself be signed by the device key and logged by the AS. The AS SHOULD alert or step-up-challenge on repeated push-to-poll fallback from the same device. This does not prevent an attacker from blocking push at the network layer, but makes a forced downgrade observable and rate-limitable instead of silent.¶
Push-wait timeout: APNs and FCM are both
best-effort platforms with no contractual delivery guarantee.
This document does not attempt to specify a relay uptime
commitment; that is a business matter between the AS and the
relay operator, out of scope here, matching [RFC8030] and [RFC9126], which likewise
specify only protocol timeouts, never operator SLAs. What this
document does specify: the client MUST NOT
switch to active polling before
push_wait_timeout_seconds (discovery document,
RECOMMENDED default 10) has elapsed since the
wake was expected, and MUST switch to polling at
the consuming protocol's own poll interval once it has. This
bounds worst-case wake latency to
push_wait_timeout_seconds plus one poll interval
without the two timers racing.¶
A persistent socket (WebSocket or MQTT) in place of platform push is explicitly rejected: it does not survive OS-level application suspension and defeats the purpose of platform push.¶
A three-tier attestation ladder, modeled on WebAuthn/FIDO2 [WebAuthn2]:¶
Device integrity (required): App Attest / Play Integrity API. Proves the running binary is unmodified and on a genuine device.¶
Authenticator attestation: a WebAuthn-style attestation object, signed by the authenticator vendor's build-time root key, proving which vendor produced this instance.¶
Vendor registry: the AS checks the
attestation certificate against
trusted_authenticator_registries, one or more neutral,
certified metadata services modeled directly on the FIDO
Alliance's Metadata Service (MDS) [FIDO.MDS3].
Default-deny unless listed.¶
Registry entries are distributed as a signed JWT BLOB
(MetadataBLOBPayload), adopting the FIDO MDS3 format: a
single JWT signed by the registry operator's root key, containing
per-authenticator entries (attestation root certificates, status
reports), served over HTTPS with the signature providing
integrity independent of transport. The AS MUST
pin the registry's root signing certificate (distributed out of
band, as with FIDO MDS's root) and the registry operator
MUST publish a documented key-rotation ceremony
(overlap period plus published fingerprint) before retiring a
root key.¶
trusted_authenticator_registries accepts a list rather
than a single URL so an AS can configure fallback registries. A
registry operator MUST publish a successor pointer
before ceasing operation, so ASes and vendors have a migration
path rather than a silent single point of failure.¶
Governance model: multi-registry federation. No single body
operates trusted_authenticator_registries; each AS or
tenant owner configures its own list of trusted registries,
choosing which neutral, certified metadata services it
recognizes. This is distinct from per-AS authenticator
allowlisting, which remains explicitly rejected, since it
recreates vendor lock-in one layer up: the AS is choosing which
registry operators it trusts, not which individual
authenticator vendors. A protocol-level meta-registry (a curated
"list of known registries") was considered and rejected: the
closest real precedent for a federation-of-registries aggregator
shows that a non-binding aggregator tends to accrete de facto
gatekeeping authority once relying parties begin treating
inclusion as a legitimacy signal, recreating the single-curator
capture risk the federation model exists to avoid. Registry
discovery is therefore left entirely out of band (specification
text, vendor documentation, industry reputation).¶
Per-AS bespoke allowlisting of individual authenticator vendors is explicitly out of scope and rejected; it recreates fragmentation one layer up.¶
AS signing-key rotation (the AS's own protocol-signing keys, as
distinct from device keys above) is out of scope for this
document: it composes with existing jwks_uri and
kid-tagged multi-key JWKS rotation per [RFC7517] and requires no additional device-side
handling.¶
This section consolidates security properties defined throughout this document.¶
Registration token exposure. The registration token is carried in a URL fragment rather than the userinfo component (Section 4), since fragments are never sent to servers, proxies, or recorded in access logs; userinfo-form URLs are a known credential-leak vector and are deprecated by Section 3.2.1 of [RFC3986].¶
Replay protection. Registration tokens are
single-use, enforced via jti consumption (Section 4). Revocation and key-rotation requests
require a Replay-Nonce (Section 5.1,
Section 5.2) modeled on Section 6.4 of [RFC8555].¶
Credential binding. device_credential is
DPoP-bound ([RFC9449]) to the key established at
registration (Section 5.2), so credential theft
alone, without the corresponding private key, is insufficient to
rotate or revoke a device.¶
Key-rotation takeover. Rotation requires proof of
possession signed by the outgoing key (Section 5.2);
without this, rotation would be a forgeable takeover path for
anyone holding a stolen device_id and bearer token.¶
Relay as an untrusted intermediary. Pull responses are mandatorily JWE-encrypted to the device's public key (Section 6), converting the relay into a zero-trust hop that only ever observes ciphertext and a non-secret routing reference.¶
Downgrade attacks. A client's report of which
delivery mode it actually used is signed and logged (Section 6), so an attacker forcing a fallback from push
to poll at the network layer produces an observable,
rate-limitable signal rather than a silent downgrade. Similarly,
minimum_interaction_type (Section 3.3) prevents an RP from silently
requesting a weaker approval ceremony than the AS's risk policy
requires, which is the mechanism that specifically defends
against MFA-fatigue/prompt-bombing attacks.¶
Attestation and registry trust. The three-tier attestation ladder and signed-BLOB registry distribution (Section 7) bound the impact of a compromised or malicious authenticator vendor; registry root-key pinning and a mandatory successor-pointer requirement bound the impact of a registry operator's key compromise or cessation of operation.¶
Backup codes. The optional account-recovery backup-code mechanism (Section 5.4) reintroduces a shared-secret bearer credential and reduces the phishing-resistance value that device attestation otherwise provides; implementers are advised to gate its availability by risk tier rather than enabling it unconditionally.¶
This document requests IANA register the following well-known URI in the "Well-Known URIs" registry defined by [RFC8615]:¶
| Field | Value |
|---|---|
| URI suffix | oauth-push-notification |
| Change controller | IETF |
| Specification document | This document |
| Status | permanent |
This document requests IANA establish a new registry, "OAuth
Push-Auth Discovery Metadata", under the existing OAuth
parameters registry group, using the same registration
procedure (Specification Required, per [RFC8126]) as the "OAuth Authorization Server Metadata"
registry established by [RFC8414]. The initial
contents are the field names defined in Section 3: registration_endpoint,
delivery_modes_supported,
interaction_type_supported,
minimum_interaction_type, registration_token_ttl,
signing_alg_values_supported, push_relay_endpoint,
fallback_order, client_attestation_required,
trusted_authenticator_registries,
minimum_attestation_level, revocation_endpoint,
key_rotation_endpoint, device_management_endpoint,
max_devices_per_user, push_wait_timeout_seconds,
and error_response_format.¶
Error type values defined in Section 3.2 are identified by URI as required by
[RFC9457] and do not require a central IANA
registry.¶
This section is to be removed before publication as an RFC.¶
Relay SLA business terms remain outside
this document's scope by design (Section 6);
the protocol-level bound is push_wait_timeout_seconds.¶
Registry-discovery convenience. Whether a non-normative, unofficial community page listing known registries is worth maintaining outside this document, given the rejection of a protocol-level meta-registry (Section 7).¶
The design of this document draws on prior art from the OAuth, OpenID Connect, WebAuthn/FIDO2, ACME, and Web Push communities, each cited at the relevant point in the text.¶