| Internet-Draft | OAuth Actor Receipts | October 2026 |
| McGuinness | Expires 4 April 2027 | [Page] |
This document defines OAuth Actor Receipts, an optional companion to the OAuth Actor Profile for Delegation. Each receipt is a signed JSON Web Token (JWT) attesting which issuer added an actor hop and, optionally, the hop's historical presenter binding. The actor_receipts claim carries a hash-linked chain of receipts that recipients verify against each hop's issuer. This document specifies receipt processing rules and the associated metadata parameters and introspection response members.¶
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/draft-mcguinness-oauth-actor-profile/draft-mcguinness-oauth-actor-receipts.html. Status information for this document may be found at https://datatracker.ietf.org/doc/draft-mcguinness-oauth-actor-receipts/.¶
Discussion of this document takes place on the Web Authorization Protocol Working Group mailing list (mailto:oauth@ietf.org), which is archived at https://mailarchive.ietf.org/arch/browse/oauth/. Subscribe at https://www.ietf.org/mailman/listinfo/oauth/.¶
Source for this draft and an issue tracker can be found at https://github.com/mcguinness/draft-mcguinness-oauth-actor-profile.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 4 April 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 OAuth Actor Profile for Delegation [I-D.mcguinness-oauth-actor-profile] makes actor identity visible in delegated tokens through a common act claim. A recipient can read that chain but cannot, on the basis of the outer token alone, verify prior hops independently of the current token issuer. The core profile treats inner actors as context whose authenticity rests on the outer token issuer, and leaves per-hop provenance to companion profiles that add top-level claims.¶
This document defines OAuth Actor Receipts, an optional companion profile that adds independently signed per-hop provenance. Each issuer adding a covered actor hop signs a receipt; receipts travel with the token in actor_receipts, linked by hashes and verifiable against the individual issuers' keys. The design center is:¶
keep the visible actor chain in act;¶
keep active presenter binding in the token's top-level cnf;¶
carry prior-hop provenance, including historical cnf values when disclosed, in separately signed receipts.¶
Deployments can enable receipts per resource or trust domain without changing client request flows, and resource servers that do not consume receipts need no change. A token that carries receipts follows the core actor profile's rules for companion profiles: its top-level cnf identifies only the current token presenter, and its nested act objects carry no independently trusted prior-hop key history.¶
Receipts do not:¶
replace the outer token's signature or issuer trust model;¶
change the request semantics of [RFC8693] or of Transaction Tokens, audience and scope evaluation, AS-to-RS trust establishment, or sender-constrained token validation for the current presenter, which follow OAuth [RFC6749] and the core actor profile;¶
prove which scope, audience, or token lifetime was in force when a receipt was created;¶
reconcile subject identifiers that differ across receipts (Section 7.2); or¶
define a cross-token correlation identifier, transparency logs, or non-repudiation.¶
Receipts are most useful when several issuers contribute hops: recipients can verify each attestation independently of the current outer token issuer. In a single-issuer deployment, the outer token's signature already supplies that issuer's attestation, so deployments SHOULD weigh receipt overhead against that limited benefit. Recipients must configure trust for every receipt issuer (Section 11.3), so large deployments need a trust-distribution mechanism, such as federation, which this document does not define.¶
Unlike token introspection [RFC7662], which returns the AS's current view of token status and claims, receipts preserve signed hop history that can be verified without an introspection endpoint, including after intermediate systems become unavailable. A deployment can use either mechanism, both (Section 7.5), or neither.¶
Related drafts differ chiefly in where delegation evidence resides and who can verify it. [I-D.mw-oauth-actor-chain] carries an issuer-signed cumulative commitment in the token while the per-hop evidence stays at the authorization server, so recipients depend on issuer retention and out-of-band access; receipts are themselves the evidence, carried with the token at the cost of per-hop token growth. [I-D.liu-oauth-authorization-evidence] and [I-D.liu-oauth-chain-delegation] carry authorization-server-signed consent and per-hop delegation records that are not chained to one another and are re-signed at trust-domain boundaries; receipts are byte-preserved and linked by prh, so recipients verify each hop against the issuer that created it. This informative comparison does not preempt working group discussion of convergence.¶
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 OAuth terminology from [RFC6749] and [RFC8693], and Transaction Token terminology from [I-D.ietf-oauth-transaction-tokens]. AS, RS, and TTS denote authorization server, resource server, and Transaction Token Service, respectively.¶
This document uses the following terms:¶
A signed JWT that attests one visible actor hop in a delegated token chain.¶
The access token (JWT-formatted or opaque), JWT assertion grant, or Transaction Token with which a receipt chain is associated. A JWT-formatted outer token carries the actor_receipts claim inline; for an opaque token, the receipts are returned via introspection (see Section 7.5).¶
The ordered actor_receipts array carried in a token or introspection response.¶
The presenter-binding state of a hop at the time the hop was created. When recorded, it appears as the receipt's cnf claim, equal to the top-level cnf value of the token issued at that hop. Historical presenter binding is informational provenance; it does not create an active proof-of-possession obligation for the current request.¶
A condition in which the number of receipts in actor_receipts equals the number of visible actor hops in the token's act chain, and every receipt aligns with the corresponding visible hop.¶
Examples in this document are illustrative and omit unrelated claims, signatures, and validation steps that a complete deployment would need.¶
The actor_receipts array is ordered newest first and preserves older entries unchanged. Index 0 corresponds to the outermost act object, index 1 to act.act, and so on.¶
A valid receipt chain records issuer attestations of past delegation. It conveys no authority and does not establish that delegation remains active. Current authorization decisions MUST evaluate the current outer token, current policy, and current state, not the receipt chain alone.¶
actor_receipts Claim
This document defines actor_receipts as a top-level JWT claim for tokens that conform to both the core actor profile and this companion provenance profile.¶
actor_receipts:OPTIONAL. An array of strings. Each string MUST be the compact serialization of a signed JWT receipt as defined in Section 5. When present, the array:¶
MUST NOT be empty; issuers MUST omit the claim rather than including an empty array;¶
MUST be ordered from newest covered hop to oldest covered hop;¶
MUST NOT contain more entries than the visible actor-chain depth of the token's act claim;¶
MUST represent a contiguous outermost prefix of the visible act chain.¶
If a token carries the actor_receipts claim, it MUST also carry an act claim conforming to the core actor profile.¶
actor_receipts_complete:OPTIONAL. A boolean JWT claim in the outer token. When true, the issuer attests that actor_receipts covers every visible hop in the token's act chain.¶
The attestation is relative to the visible chain at issuance time; it does not attest that the visible chain is itself unfiltered (see the chain_complete introspection member in the core actor profile [I-D.mcguinness-oauth-actor-profile]). Step 4 of Section 7 defines consumer enforcement, including the count-equality check.¶
Issuers SHOULD set actor_receipts_complete to true for complete coverage and false for partial coverage; an issuer extending a chain sets true only as step 8 of Section 6.2 allows. An absent claim provides no completeness attestation; consumers that require the literal value true treat absence as false.¶
Each element of the actor_receipts array is a signed JWT represented using JWS compact serialization [RFC7515].¶
The JOSE header of an actor receipt:¶
MUST include an asymmetric digital-signature alg value;¶
MUST NOT use alg: none or a MAC-based symmetric algorithm;¶
MUST include the typ header parameter with the value actor-receipt+jwt;¶
SHOULD include the kid header parameter when the issuer publishes multiple verification keys;¶
MAY include the crit header parameter per Section 4.1.11 of [RFC7515]; step 5 of Section 7 rejects a receipt whose crit header parameter lists an extension header parameter the consumer does not understand.¶
Receipt issuers and consumers MUST apply the JWT best practices in [RFC8725] when creating and validating receipts, except for the audience requirements of Section 3.9 of [RFC8725], from which this profile departs by prohibiting the aud claim as described in Section 5.2.¶
The JWT payload of an actor receipt uses the claims defined below, grouped by purpose.¶
iss:REQUIRED. The issuer that created and signed the receipt for the corresponding actor hop. This value identifies the receipt signer.¶
The act.iss value inside the receipt identifies the namespace authority for act.sub, with the meaning defined by the core actor profile. These two values MAY identify the same entity or different entities. When they differ, consumers MUST evaluate two distinct trust questions:¶
trust in iss as a receipt signer: whether this issuer's signature attests receipts under local policy;¶
trust in act.iss as the namespace authority for act.sub: whether this issuer's namespace produces actor identifiers the recipient accepts.¶
These evaluations are independent even when the same entity holds both roles. A difference between iss and act.iss alone does not make the receipt invalid under this profile.¶
sub:REQUIRED. The top-level sub value that was present in the token issued at this hop.¶
The receipt iss claim identifies the signer, not the subject namespace. Recipients interpret sub in the namespace of the represented hop, which MAY differ across receipts. Reconciliation relies on trusted local mappings; see Section 7.2.¶
sub_iss:OPTIONAL. The namespace authority under which the receipt sub value is interpreted.¶
The (sub_iss, sub) pair identifies the subject just as (act.iss, act.sub) identifies the actor. If sub_iss is absent, recipients MUST determine the namespace, when needed, from trusted local context for the represented hop. This flat pair records the token's issued claims; it does not use the structured Subject Identifier formats in [RFC9493].¶
sub_profile:OPTIONAL. The top-level sub_profile value, when the token issued at this hop carried one.¶
act:REQUIRED. A single-hop actor object. This object:¶
MUST conform to the core actor profile's actor-object rules;¶
MUST NOT contain cnf;¶
MUST NOT contain a nested act.¶
Historical presenter binding belongs in the receipt-level cnf claim. Other core-profile actor extensions MAY appear unless prohibited here; a receipt containing act.cnf is invalid.¶
These restrictions apply to the receipt's actor object. The issuer constructs that object for visible-hop alignment (step 7 of Section 7), separately from the token's act chain. A confirmation member in the token's actor object remains subject to the core profile's extension and preservation rules; creating a receipt does not remove it from the token.¶
cnf:OPTIONAL. A confirmation claim as defined in [RFC7800]. When present, it MUST equal the top-level cnf claim of the token issued at this hop.¶
Its source is the top-level cnf claim of the token issued at that hop, not a confirmation member in the token's act chain. Whether an issuer includes cnf is governed by Section 11.10; omitting cnf does not invalidate the receipt.¶
prh:OPTIONAL. Previous receipt hash. When present, prh MUST be the base64url encoding without padding ([RFC7515]) of the hash of the ASCII octets of the complete compact serialization of the next older receipt in the chain, computed using the algorithm identified by prh_alg (defaulting to SHA-256 when prh_alg is absent). The oldest receipt in the chain, including a single-element chain in which the sole receipt is both newest and oldest, MUST omit prh.¶
prh_alg:OPTIONAL. An identifier of the hash algorithm used to compute prh.¶
Values MUST be drawn from the IANA "Named Information Hash Algorithm Registry" [RFC6920], which uses lowercase forms such as sha-256, sha-384, and sha-512.¶
When absent, the default is sha-256.¶
When present, the value MUST identify a hash algorithm whose collision and preimage resistance is at least equivalent to sha-256.¶
All receipts in an array MUST carry the same prh_alg value or all omit it. Mixing omission with explicit sha-256 is invalid even though both select SHA-256. A single-element chain MAY carry prh_alg, but the value has no effect unless a later receipt links to it.¶
An issuer extending an inbound chain preserves the inbound prh_alg or rejects the chain (step 7 of Section 6.2).¶
iat:REQUIRED. The time at which the receipt was created, as defined in [RFC7519].¶
exp:REQUIRED. The expiration time of the receipt, as defined in [RFC7519].¶
The exp of a newly created receipt MUST NOT be earlier than the exp of the outer token issued with it, and SHOULD cover the expected maximum token lifetime of any token that will carry or inherit this receipt. An exp value set too early causes propagation failure: issuers that later retain the receipt apply the following receipt lifetime rule.¶
When an issuer retains receipts in a token it issues (extending the chain under Section 6.2, or reissuing or refreshing under Section 6.3) and a retained receipt's exp is earlier than the exp the issuer would set, the issuer:¶
MAY lower the issued token's exp to the earliest retained receipt exp;¶
otherwise, where local policy permits the issued token to lack the retained receipts, MUST drop the array;¶
otherwise MUST fail the request, with the invalid_grant error code on a refresh or JWT bearer grant request (Section 5.2 of [RFC6749]) or the invalid_request error code on a Token Exchange request (Section 2.2.2 of [RFC8693]).¶
Because the originating issuer cannot enumerate every downstream issuer that might inherit a receipt, deployments typically coordinate a bounded delegated-session lifetime to avoid propagation failure while limiting signing-key exposure; see Section 6.3.¶
jti:REQUIRED. A unique identifier for the receipt, as defined in [RFC7519].¶
origin_jti:RECOMMENDED. The jti of the outer token at the time this receipt was created (the receipt's origin outer token). This value is fixed at receipt creation; after reissuance, the current outer token's jti can differ.¶
It binds the chain to the current token only when both receipt[0].iss and receipt[0].origin_jti match that token's iss and jti, respectively.¶
Issuers SHOULD include origin_jti when the issued token has a jti claim. See Section 7.1 and Section 11.4.1 for validation and reissuance handling.¶
aud:Prohibited. Issuers MUST NOT include aud in a receipt, and consumers MUST reject a receipt that carries it (step 5 of Section 7).¶
Receipts are validated as part of outer-token processing, not as independent JWTs against an audience; the outer token carries the audience scoping for the request. A present aud would suggest an independent audience constraint, which receipts do not assert; rejecting it gives the result that Section 4.1.3 of [RFC7519] requires when the processing principal does not identify itself with the aud value.¶
A receipt MAY contain additional claims defined by another specification or by deployment policy. Consumers ignore unrecognized claims unless another specification or local agreement defines their meaning, per Section 4 of [RFC7519].¶
A new receipt prepended to an inherited chain includes a prh claim computed over the older receipt that follows it; a receipt that is the only one in the array omits prh (Section 5.2; step 6 of Section 6.2).¶
The hash input is the exact compact JWS string, without JSON [RFC8259] canonicalization. Systems that carry, store, or forward actor_receipts arrays MUST preserve each receipt byte-for-byte. Re-encoding changes the hash even when the claims remain equivalent.¶
When an issuer adds a new outermost actor hop and creates the corresponding receipt, that issuer also signs the outer token. Consequently, receipt[0].iss equals the outer token's iss for tokens issued under Section 6.1 or Section 6.2. When the issuer includes origin_jti, receipt[0].origin_jti equals the outer token's jti in those originating-issuance cases.¶
Reissuance without a new actor hop (Section 6.3) is the only case in which receipt[0] can legitimately diverge from the current outer-token instance; the consumer rules in Section 7 rely on this property to scope the bind-to-current checks for receipt[0].¶
When an issuer creates a delegated token with a new outermost actor hop and no inbound actor_receipts are being preserved, the issuer MAY create a new one-element actor_receipts array.¶
If the issuer does so, the new receipt:¶
MUST describe the new outermost actor hop;¶
MUST set iss to the issued token's iss;¶
MUST set sub to the issued token's top-level sub;¶
MUST set act.sub and act.iss to identify the new outermost actor;¶
MAY copy the issued token's top-level cnf, if any, into the receipt cnf, subject to the disclosure considerations in Section 11.10;¶
includes origin_jti as recommended in Section 5.2;¶
omits prh (Section 5.2).¶
A one-element array is complete coverage only when the visible act chain has depth 1; the actor_receipts_complete value follows the rules in Section 4.¶
When an issuer adds a new outermost actor hop and also preserves the actor_receipts array of the token carrying the inbound delegation chain ([I-D.mcguinness-oauth-actor-profile]), such as the token in the subject_token parameter of a Token Exchange request, the issuer:¶
MUST validate the inbound receipt chain by applying the consumer processing rules in Section 7 before relying on it or carrying it forward.¶
MUST apply the receipt lifetime rule in Section 5.2 when an inbound receipt's exp is earlier than the issued outer token's exp. Issuers MAY allow a small, deployment-defined clock-skew margin consistent with consumer validation, but MUST NOT accept a larger expiry gap.¶
MUST preserve each inbound receipt byte-for-byte unchanged.¶
MUST create exactly one new receipt for the new outermost actor hop, with claims set as in Section 6.1 except prh and prh_alg, which steps 6 and 7 govern.¶
MUST prepend that new receipt to the inherited array.¶
When the inherited array is non-empty, MUST set the new receipt's prh to the hash of the exact compact serialization of the receipt now at the next array index, computed using the algorithm named by prh_alg (defaulting to SHA-256 when prh_alg is absent).¶
MUST set the new receipt's prh_alg to the inherited value, or omit prh_alg if the inherited chain omits it (preserving the SHA-256 default for the chain). An issuer that does not support the inbound prh_alg value MUST reject the chain rather than rehash; rehashing would invalidate prior issuers' signatures.¶
MUST NOT set actor_receipts_complete to true unless every inbound receipt validated and the issued token's receipt count equals its visible actor-chain depth, and SHOULD set it to false otherwise.¶
Byte-for-byte preservation (Section 5.3) precludes reserializing, re-signing, normalizing, trimming, or otherwise altering a prior receipt.¶
If inbound receipts fail validation, the issuer MUST NOT propagate them. It MAY continue without them only when local policy permits the issued token to lack them, and it MAY then begin a new chain at its own hop under Section 6.1; the result is partial coverage and MUST NOT carry actor_receipts_complete: true. Otherwise, it MUST fail the request under the error model of the underlying protocol.¶
An issuer that reissues, translates, or introspects and re-emits a token without adding a new outermost actor hop:¶
MAY carry forward, unchanged, an actor_receipts array received in an inbound token or its introspection response, and MUST first validate it against that token under Section 7, as step 1 of Section 6.2 requires for extension; an array the issuer retained across refresh follows the refresh rules below instead. If the array fails validation, the issuer MUST NOT carry it forward, and MUST fail the request under the error model of the underlying protocol unless local policy permits the issued token to lack it;¶
MUST NOT create a new receipt;¶
MUST preserve actor_receipts_complete when carrying the array unchanged. An issuer that would change that value MUST drop the array entirely instead; disclosure is all-or-nothing (Section 7.5);¶
MUST NOT continue to carry an inherited actor_receipts array if it cannot preserve the visible hop alignment required by Section 7;¶
MUST NOT change the top-level sub claim while retaining receipts. Subject re-expression breaks alignment with receipt[0].sub and requires dropping the array;¶
MUST NOT set the outer token's exp later than the earliest exp among the retained receipts; an issuer that would set a later exp applies the receipt lifetime rule in Section 5.2.¶
If such an issuer changes the visible outermost actor, it has added a new hop and MUST follow Section 6.2.¶
Reissuance MAY change aud, scope, cnf, and other current-request claims without changing receipts, and MAY change exp within the limit above. The receipt cnf claim remains historical, so key rotation alone does not invalidate the chain.¶
Reissuance can make receipt[0] diverge from the current outer-token instance in two ways:¶
Different-issuer reissuance: receipt[0].iss differs from the outer token's iss, for example when an introspection endpoint operated as a separate trust principal re-emits the token, or a token translator at a domain boundary reissues it. A common case is a Resource Authorization Server that redeems an Identity Assertion JWT Authorization Grant (ID-JAG) or other JWT assertion grant ([I-D.mcguinness-oauth-actor-profile]) without adding a hop; the actor alignment and subject alignment of steps 7 and 8 of Section 7 still apply.¶
Same-issuer reissuance: receipt[0].iss matches the outer token's iss, but a present receipt[0].origin_jti differs from the outer token's jti, for example when an AS refreshes its own access token.¶
In either case, origin_jti remains historical and no longer binds the chain to the current instance. Recipients accept different-issuer reissuance only under the reissuing-issuer policy in Section 11.4 (case 4 of Section 7.1), and same-issuer reissuance only as provenance without instance binding (case 3 of Section 7.1).¶
Refresh-token reissuance is a special case of reissuance under this section. An AS that supports refresh tokens for delegated access tokens:¶
needs to retain the actor_receipts array associated with the original access token in issuer-controlled state across refresh, either in durable storage (for example, a token-state database or refresh-token state) or embedded in a self-contained refresh token, so that each refreshed access token can carry the receipts forward unchanged.¶
needs receipt exp values (Section 5.2) that accommodate a bounded maximum delegated-session lifetime that local policy defines; otherwise refresh and downstream extension shorten tokens or lose receipt-based provenance.¶
takes the array from that retained state rather than from the previous access token: it validates the refresh request per Section 6 of [RFC6749], checks the retained receipts against its issuance state, and does not require the previous access token to remain unexpired or re-run Section 7 against it.¶
applies the receipt lifetime rule in Section 5.2 when a retained receipt's exp is earlier than the exp it would set for the refreshed token. Refresh adds no actor hop, so receipt provenance resumes only through a new delegated issuance that adds a hop and begins a chain under Section 6.1.¶
This document permits partial receipt coverage for progressive deployment. An issuer MAY begin a new receipt chain even when older inner actor hops remain visible but uncovered.¶
However:¶
a partial chain still covers a contiguous outermost prefix of the visible actor chain (Section 4), so an issuer cannot skip an outer visible hop and issue a receipt only for an inner visible hop;¶
when local policy or resource requirements require full provenance, the issuer MUST either emit complete receipt coverage or fail the request under the error model of the underlying protocol.¶
Partial coverage leaves the oldest hops uncovered, including the original subject-to-actor delegation. Deployments needing evidence for that hop should enable receipt support at the origin issuer first.¶
When an introspection server filters the visible act chain (see the chain_complete introspection member defined in the core actor profile [I-D.mcguinness-oauth-actor-profile]), actor_receipts covers only the visible filtered chain. In that case, actor_receipts_complete describes coverage relative to the visible filtered chain, not the unfiltered delegation chain; recipients that need true-chain completeness evaluate chain_complete separately. Filtering only inner actors that no receipt covers preserves the full array and its alignment; filtering a covered actor breaks hop alignment (step 7 of Section 7), so the array cannot be kept (Section 7.5).¶
For JWT-formatted outer tokens, this document defines no chain_complete JWT claim. A recipient that needs true-chain completeness for such tokens obtains that signal from trusted deployment context, introspection, or another profile; actor_receipts_complete: true alone attests only to complete receipt coverage of the visible act chain.¶
A TTS that adds a presenter as the new outermost actor follows Section 6.2, or Section 6.1 if no receipts exist. The new receipt can record the presenter's cnf value under Section 5.2; inherited receipts retain their historical bindings.¶
[I-D.ietf-oauth-transaction-tokens] defines no jti claim but permits additional claims (Section 9.2 of [I-D.ietf-oauth-transaction-tokens]), so a TTS MAY include a jti claim in a Transaction Token. Without a jti claim, a Transaction Token's receipt chain is never instance-bound, because case 1 of Section 7.1 requires the outer token's jti; recipients that require instance binding need a TTS that includes jti.¶
An issuer, resource server, or other recipient that relies on actor_receipts MUST perform the following steps.¶
Validate the outer token according to its token type and the core actor profile.¶
If actor_receipts is absent, treat the token as lacking receipt-based provenance. Local policy or Protected Resource Metadata parameters (such as actor_receipts_required and actor_receipts_complete_required, defined in Section 8) determine whether that is acceptable. If actor_receipts_complete is present with the value true while actor_receipts is absent, the combination is malformed; the recipient MUST treat this as a failed required check and apply the rejection rule following step 11.¶
Verify that actor_receipts, if present, is a non-empty JSON array of strings. Verify that actor_receipts_complete, if present, is a JSON boolean.¶
Verify that the number of receipts does not exceed the visible actor-chain depth of the outer token. If the outer token carries actor_receipts_complete: true, verify that the receipt count exactly equals the visible actor-chain depth; if it does not, the check fails.¶
For each receipt, in array order:¶
parse the string as a compact JWT;¶
verify that typ equals actor-receipt+jwt;¶
verify that the receipt issuer is within the recipient's pre-configured trusted-issuer set before performing any network retrieval for that issuer's metadata or keys;¶
verify that the JOSE header uses an asymmetric digital-signature alg value accepted for that receipt issuer, and reject receipts that use alg: none or a MAC-based symmetric algorithm;¶
resolve the signing key from the receipt issuer's authorization server metadata jwks_uri [RFC8414] (where the receipt's iss claim identifies the receipt issuer, which can differ from the outer token's issuer) or from local configuration;¶
validate the JWT signature;¶
reject a receipt whose crit header parameter lists an extension header parameter the consumer does not understand;¶
verify that all REQUIRED receipt claims are present and have the expected JSON types, including iss, sub, act, iat, exp, and jti;¶
verify that OPTIONAL claims used by this profile have the expected JSON types when present, including sub_iss, sub_profile, cnf, prh, prh_alg, and origin_jti;¶
verify that the receipt act object is single-hop, contains no nested act, and contains no cnf;¶
reject a receipt that contains aud (Section 5.2);¶
enforce exp, iat, and other JWT validity rules. An expired receipt is invalid even for an older hop; only the small clock-skew leeway of Section 4.1.4 of [RFC7519] applies;¶
for receipt[0], apply Section 7.1. For older receipts, origin_jti is historical information only.¶
Verify receipt-chain linkage:¶
each receipt other than the oldest MUST include prh;¶
each non-oldest receipt's prh MUST hash the next older receipt using the algorithm named by prh_alg, defaulting to sha-256 when prh_alg is absent;¶
all receipts in the chain MUST carry the same prh_alg value (or all omit it); a mixed-algorithm chain MUST be rejected;¶
the named algorithm MUST be one the recipient supports; a chain naming an unsupported algorithm MUST be rejected;¶
the oldest receipt MUST omit prh.¶
Verify visible-hop alignment:¶
receipt[0].act.sub MUST equal the outer token's act.sub, and receipt[0].act.iss MUST equal the outer token's act.iss;¶
receipt[1].act.sub MUST equal the outer token's act.act.sub, and receipt[1].act.iss MUST equal the outer token's act.act.iss;¶
and so on for the number of receipts present;¶
when act.sub_profile is present in the receipt act object, the corresponding visible act object MUST contain act.sub_profile with the same value;¶
sub_profile values are compared as sets: the space-delimited values are compared case-insensitively, their order is insignificant, and duplicate values are ignored (Section 3.3 of [I-D.mora-oauth-entity-profiles]); comparison never rewrites a signed receipt;¶
when act.sub_profile is present only in the visible act object, the receipt remains aligned for this profile. The visible value is not independently attested by that receipt, and recipients that require receipt coverage for actor classification MUST reject the receipt chain or apply explicit local mapping rules.¶
Verify subject alignment:¶
receipt[0].sub MUST equal the outer token's top-level sub;¶
when receipt[0].sub_iss is present and the recipient has a top-level subject namespace authority for the outer token's sub from local configuration, an inbound subject token's claims, or another deployment-defined source, the two MUST identify the same namespace authority, evaluated by case-sensitive string comparison; treating lexically distinct identifiers as the same authority requires explicit trusted local mapping rules;¶
when receipt[0].sub_profile is present and the outer token contains top-level sub_profile, the values MUST match under the set comparison of step 7;¶
when receipt[0].sub_profile is present but the outer token does not contain top-level sub_profile, recipients that require receipt coverage for subject classification MUST reject the receipt chain or apply explicit local mapping rules;¶
when receipt[0].sub_profile is absent but the outer token contains top-level sub_profile, the receipt remains aligned for this profile. The visible value is not independently attested by that receipt, and recipients that require receipt coverage for subject classification MUST reject the receipt chain or apply explicit local mapping rules;¶
older receipts MAY carry differing sub, sub_iss, or sub_profile values; see Section 7.2.¶
Treat each receipt cnf value, if present, only as historical provenance for that hop. A mismatch between the current outer token's top-level cnf and the outermost receipt cnf MUST NOT by itself invalidate the receipt chain under this profile.¶
Receipt cnf values MUST NOT replace validation of the current request against the outer token's top-level cnf.¶
Apply any additional consumer-processing rules defined by companion profiles whose claims appear in the receipt or outer token (see Section 10). Companion-profile rules can add rejection conditions but cannot relax any requirement needed for conformance to this profile. Unless a companion profile states otherwise, a failure under its rules rejects only that companion's evidence and is not a failed required check of this profile.¶
Step 1 is a prerequisite: an outer token that fails its own validation is rejected under the rules for its token type, not treated as lacking receipts. If any later required check fails, the recipient MUST reject the receipt chain and treat the token as lacking receipt-based provenance (step 2). The recipient rejects the token only when local policy or Protected Resource Metadata requires that evidence, using the underlying protocol's error handling for the stage at which the failure occurred.¶
A recipient that has rejected a receipt chain under this profile MAY, under explicit local policy, extract structural information from the chain for use by companion profiles (for example, applying a companion's verification rules to the trusted prefix of an otherwise-invalid chain). The recipient MUST NOT treat such partial validation as conformance with this profile; the rejection requirements defined above still apply. Companion profiles defining partial-validation modes MUST do so under their own normative scope.¶
Consumer step 5 applies the following cases, in order, to receipt[0]:¶
If its iss matches the outer issuer and its origin_jti is present and matches the outer token's jti, the chain is bound to that token instance.¶
If the issuers match but the outer token has no jti, the chain supplies provenance without instance binding. Any origin_jti is informational.¶
If the issuers match and the outer token has jti, but origin_jti is absent or differs from that jti, the recipient MAY accept provenance under local policy. It MUST NOT treat the chain as instance-bound.¶
Otherwise (the issuers differ), the recipient MUST reject the chain unless local policy trusts the outer issuer to reissue chains led by this receipt issuer (Section 11.4.1).¶
A recipient that requires instance binding MUST reject the chain unless case 1 applies.¶
Only receipt[0].sub is matched against the outer token's top-level sub; older receipts can carry different subject identifiers (step 8 of Section 7).¶
Matching actor identities alone do not establish subject continuity. A receipt from an unrelated subject chain that shares the same actor identity can satisfy the hop-alignment check, whether by accident or because a compromised upstream issuer minted it for insertion.¶
Deployments requiring subject continuity SHOULD establish it either by exact, namespace-aware matching of subject identifiers throughout (the same sub under the same namespace authority; see sub_iss in Section 5.2) or by positive reconciliation through trusted mappings. When neither applies, recipients MUST treat continuity as unverified and MUST NOT use the differing older receipts to support authorization that requires subject continuity (for example, a decision that treats every covered hop as having acted for the current token's subject).¶
Coverage is structurally complete when all validation succeeds and the receipt count equals the visible actor-chain depth. This suffices when local policy requires only structural completeness.¶
With actor_receipts_complete_required: true, the token or introspection response MUST also carry actor_receipts_complete: true. Recipients MUST reject tokens that fail the applicable completeness requirement.¶
Resource servers can use validated receipts as provenance input for authorization, diagnostics, and audit, subject to the limits in Section 11.1. A valid receipt chain proves only that trusted issuers attested specific visible actor hops. It conveys no authority, does not replace authorization of the current token, does not imply that the represented delegation remains active, and does not prove that the current token's audience, scope, or expiration were in force when older receipts were created.¶
When an authorization server returns actor-receipt information in an OAuth Token Introspection response [RFC7662], it:¶
MAY return actor_receipts using the same array format defined in Section 4;¶
MAY return actor_receipts_complete to indicate whether the returned array provides complete coverage for the visible chain as known to the introspection server.¶
For opaque tokens, the issuer stores receipts and returns them to authorized resource servers through introspection. The same format and consumer rules apply, with the introspection response treated as the outer token's claim set.¶
An introspection response carrying receipts MUST include the members needed for Section 7: the token's top-level sub, the visible act chain, and the token's iss. It SHOULD include the token's jti when maintained by the server; when the response omits jti, recipients apply the no-jti case in Section 7.1. If present, actor_receipts_complete MUST be a boolean.¶
An RS receiving both inline and introspected receipts MUST select an authoritative source under local policy. If it consumes both, differing arrays or completeness values MUST cause rejection of receipt-based provenance.¶
An introspection server MUST return the full stored array or omit actor_receipts. Removing an older entry breaks prh linkage; removing the newest entry breaks hop alignment. A server that filters the visible act chain can still return the full array when it filters only inner actors that no receipt covers; if it filters a covered actor, it MUST omit both actor_receipts and actor_receipts_complete. When the returned array does not cover every hop of the returned act chain, the introspection server MUST include actor_receipts_complete: false.¶
For an inactive token, the introspection server MUST NOT return actor_receipts or actor_receipts_complete.¶
Consumers that rely on both signals evaluate chain_complete and actor_receipts_complete independently (Section 6.4); complete receipt coverage does not prove that no actors were filtered.¶
The following parameters are defined for use in Protected Resource Metadata [RFC9728]:¶
actor_receipts_required:OPTIONAL. A boolean. When true, the resource server indicates that delegated requests are expected to carry valid actor receipts covering at minimum the outermost visible actor hop. When false or absent, the resource server makes no metadata declaration about receipt-based provenance requirements.¶
This parameter is a policy declaration for deployment coordination, not a request-time protocol signal: this document defines no parameter by which a client requests receipt issuance, so a deployment satisfies the declaration by configuring receipt issuance at the authorization servers that serve the resource. Clients MAY use it, together with actor_receipts_supported, to select an authorization server that can issue receipt-bearing tokens.¶
actor_receipts_complete_required:OPTIONAL. A boolean. When true, the resource server indicates that it requires complete receipt coverage: the receipt count equals the visible actor-chain depth and actor_receipts_complete is true in the outer token or the introspection response. This parameter refines actor_receipts_required; a resource server SHOULD NOT set actor_receipts_complete_required: true without also setting actor_receipts_required: true. When false or absent, partial receipt coverage is acceptable to the resource server, subject to any further local policy.¶
No metadata parameter indicates that a resource server requires receipts to carry cnf. Because issuers omit receipt cnf by default (Section 11.10), resource servers that need historical sender-constraint provenance coordinate that requirement with issuers through deployment policy.¶
The following members are defined for use in OAuth Token Introspection responses [RFC7662]:¶
actor_receipts:OPTIONAL. An array of strings using the same syntax as the actor_receipts JWT claim.¶
actor_receipts_complete:OPTIONAL. A boolean. When true, the introspection response indicates that the returned actor_receipts array covers every visible hop in the token chain as known to the introspection server. When false, the response makes no attestation of complete coverage.¶
Consumer use of these members is described in Section 7.5; introspection-server failure handling is addressed in Section 9.3.¶
Companion profiles that define their own per-hop signed artifact arrays SHOULD use the same naming convention, SHOULD advertise support in AS metadata [RFC8414], and SHOULD advertise requirements in Protected Resource Metadata [RFC9728]:¶
| Purpose | Name |
|---|---|
| Artifact array |
<name>
|
| Coverage attestation |
<name>_complete
|
| AS support |
<name>_supported
|
| Resource requirement |
<name>_required
|
| Complete-coverage requirement, if applicable |
<name>_complete_required
|
Companion profiles add per-hop signal in two distinct patterns, and SHOULD pick the one that matches their signer:¶
Parallel artifact arrays: a companion outer-token claim parallel to actor_receipts, following the <name> plus <name>_complete convention above. Each entry is a separately signed JWT. This pattern is appropriate when the artifact needs its own signer trust independent of the receipt issuer (for example, actor-signed proofs whose threat model differs from AS-signed receipts, or recipient-signed acknowledgments).¶
Per-receipt extension claims: a claim added to each receipt JWT and verified as part of the receipt's signature. This pattern is appropriate when the receipt issuer already attests the assertion (for example, per-hop authority bounds, delegation-flow correlation, or lifecycle-state snapshots). Recognition of such claims follows the unrecognized-claims rule in Section 5.2, and cross-receipt verification follows Section 10.¶
The two patterns serve different threat models and have different completeness semantics: parallel-array companions inherit the claim-pair coverage mechanism defined here; per-receipt-claim companions define their own completeness rules over the set of receipts that carry the claim.¶
Receipt validation failures use the underlying protocol's error mechanism for the stage at which validation occurs. This document defines no new OAuth error codes.¶
When a resource server rejects a request because actor_receipts validation fails under Section 7, it SHOULD return the invalid_token error code per the bearer-token error model in Section 3.1 of [RFC6750]. For a Transaction Token, the recipient instead rejects the request through the deployment's Transaction Token handling, because [I-D.ietf-oauth-transaction-tokens] defines no error response.¶
When the failure is specifically that required receipts are absent or coverage is incomplete (per actor_receipts_required or actor_receipts_complete_required), the resource server SHOULD include an error_description value identifying a receipt-coverage failure so that clients and operators can distinguish it from generic token-validation failures.¶
When an introspection server cannot return receipts that the requesting resource server requires, it returns the introspection response per [RFC7662], not an OAuth error, with actor_receipts absent or with a partial array and actor_receipts_complete: false; the resource server then applies its local policy to decide whether to accept the token.¶
Companion profiles that build on the OAuth Actor Profile for Delegation [I-D.mcguinness-oauth-actor-profile] can extend this profile through five surfaces:¶
New claims inside a receipt JWT for additional per-hop attributes (for example, historical scope or additional binding data). Consumers ignore unrecognized claims (Section 5.2), so additive claims do not break the validation rules of this document.¶
New top-level claims on the outer token, parallel to actor_receipts, for per-hop artifacts that need their own signature semantics, following the claim-pair convention in Section 8.¶
New JOSE typ values for receipt-shaped artifacts that are not AS-signed receipts conforming to this document. The typ value actor-receipt+jwt defined here is reserved for receipts conforming to this document and MUST NOT be used by other artifacts.¶
New outer-token binding claims, analogous to origin_jti, that record an outer-token field other than jti (for example, a workflow correlation identifier). Such claims are independently verifiable as current-token bindings only on the same terms as origin_jti; see Section 11.4.¶
Events not tied to a new visible actor hop, such as re-authorization without a hop change, lifecycle-state changes, receiver acknowledgments, or sender-constraint rotation. Companion profiles SHOULD use a separate JWT type and a parallel outer-token array. They SHOULD anchor each event to a receipt jti or a defined flow identifier, such as Transaction Token txn [I-D.ietf-oauth-transaction-tokens]. Event chaining with prh / prh_alg and the completeness convention are optional. Companion profiles MUST NOT add event entries to actor_receipts, which is reserved for the AS-signed hop receipts defined by this document.¶
Companion profile authoring rules:¶
Companion profiles MAY extend consumer processing under Section 7 by adding rejection conditions; they MUST NOT relax any requirement needed for conformance to this profile.¶
Companion-profile claims and discovery metadata MUST be registered with IANA in the registries used by this document.¶
Companion profiles MAY reuse the prh and prh_alg chain-linkage construction defined in Section 5.2 when their per-hop signed artifacts form a similar chain structure, so that recipients can apply a single chain-validation routine across companions.¶
Companions whose artifacts do not form a chain (for example, independent per-hop attestations or recipient acknowledgments that are not linked to one another) MAY define their own integrity structure.¶
Companion profiles MAY define cross-receipt verification rules (for example, monotonicity rules over per-hop authority bounds, alignment rules between per-hop attestations, or aggregation rules over per-hop assertions) that compare claims across receipts in the chain. Companion profiles defining cross-receipt rules MUST tolerate sparse coverage (not every receipt is required to carry the companion's claims) unless they explicitly require completeness.¶
Cross-companion alignment: companion artifacts that need to reference a specific receipt (for example, an actor-signed proof at hop N referencing the corresponding AS-signed receipt at hop N) SHOULD do so by the receipt's jti, which is REQUIRED on receipts and, as Section 4.1.7 of [RFC7519] requires when an application uses multiple issuers, free of collisions across issuers. This profile does not define a hop-index claim; cross-companion alignment is established through jti reference plus the prh chain's structural integrity, not through array-position metadata.¶
Conflict resolution: when a recipient implements multiple companion profiles whose rules conflict, local policy determines precedence. Companion profiles SHOULD be designed to add, not contradict, other profiles' rejection conditions, so that conflicts arise only between profiles whose threat models are genuinely incompatible.¶
The OAuth 2.0 Security Best Current Practice [RFC9700] and the JWT best practices in [RFC8725] apply to systems implementing this profile, except that the audience requirements of the latter do not apply to receipt JWTs (see aud in Section 5.2).¶
Compromised downstream issuer fabricating prior-hop provenance. Such an issuer cannot forge prior issuers' receipt signatures, and the prh chain prevents it from dropping or reordering inner receipts.¶
Token mutation in transit. Each receipt is independently signed; modification invalidates the receipt's signature and any newer receipt's prh.¶
Receipt transplantation between tokens with matching visible act chains. The outer-token signature prevents parties other than the issuer from constructing a substitute outer token to host transplanted receipts. receipt[0].origin_jti adds diagnostic confirmation in the originating-issuance case (Section 11.4) but no defense against a compromised outer issuer (Section 11.6).¶
Partial-coverage misclaim. Step 6 of Section 7 rejects a chain with a dropped inner receipt or a trimmed oldest end, so an issuer can withhold coverage of the oldest hops only by beginning a new chain, and it cannot claim actor_receipts_complete: true unless the receipt count matches the visible actor-chain depth.¶
Compromised current outer token issuer. Such an issuer can wrap previously harvested valid receipts in a new outer token (Section 11.6).¶
Compromised receipt signing key for any one issuer. Forged receipts are indistinguishable from legitimate ones and cannot be revoked individually. Remediation: remove the compromised issuer from the trusted-issuer set; a short receipt exp bounds the exposure window.¶
Compromised actor at a hop. Receipts attest issuer assertions, not actor non-repudiation. Actor-signed proofs from a companion profile (Section 10) show that an actor's key signed its participation, but do not mitigate a compromised actor key or a malicious actor.¶
Cross-namespace subject graft with a compromised upstream issuer. An attacker who compromises one upstream issuer can mint receipts for any subject in that issuer's namespace and graft them onto a re-expressed downstream chain. Mitigation: exact, namespace-aware subject matching across the chain or trusted out-of-band subject mapping (Section 7.2).¶
Replay of an entire token plus its receipts. This profile does not define replay detection; receipts inherit the outer token's replay characteristics (Section 11.7).¶
Companion profiles (Section 10) can extend the set of mitigated adversaries; for example, an actor-signed-proofs companion can prevent a current outer token issuer from fabricating actor participation at proof-covered hops when recipients require those proofs and resolve actor keys independently of that issuer, though not from re-embedding a proof submitted to it.¶
When the outer token carries a top-level cnf claim ([RFC7800]), the current request is always validated against it, using the proof mechanism appropriate to the token type and deployment, such as DPoP [RFC9449] or mutual-TLS [RFC8705] (steps 9 and 10 of Section 7). Recipients MUST distinguish receipt JWTs (identified by typ value actor-receipt+jwt) from outer tokens that carry cnf for current-request proof-of-possession; receipt cnf records historical binding and never satisfies a current-request PoP requirement under [RFC7800], [RFC9449], or [RFC8705].¶
A syntactically valid signed receipt is not by itself grounds to trust its issuer. A recipient needs to establish which issuers it trusts for receipt validation before relying on actor_receipts. Trust MUST be established through explicit pre-configuration, bilateral agreement, federation policy, or another explicit trust framework.¶
Authorization servers that support this document SHOULD advertise actor_receipts_supported: true in their AS metadata [RFC8414]. Consumers SHOULD use that metadata signal as one input to trust establishment, but metadata advertisement alone is not sufficient grounds to trust a receipt issuer; the issuer must also be within the recipient's configured trust boundary.¶
To avoid attacker-controlled key resolution, step 5 of Section 7 checks the trusted-issuer set before any network retrieval for an issuer's metadata or keys.¶
Trust is per-issuer and not transitive: each receipt is validated against the recipient's own trusted-issuer set, independent of the outer token's issuer or neighboring receipts. If any receipt in the presented actor_receipts array is signed by an issuer that is not trusted for receipt validation, the recipient MUST reject the receipt chain for the purposes of this profile. This document does not define trusted-prefix validation across an untrusted inner receipt, so deployments need to establish trust with every receipt issuer that can appear in tokens they accept.¶
Receipts do not prove that the current outer token's audience, scope, expiration, or other authorization details were in force when older receipts were created. A recipient MUST NOT treat a valid receipt chain as evidence of historical authorization scope or audience beyond what the current outer token authorizes.¶
In the originating-issuance case, a present receipt[0].origin_jti, signed by the issuer that signed the outer token and equal to that token's jti, binds receipt[0] to that outer-token instance and prevents transplantation from a different token whose visible act structure happens to match; prh then extends that binding to every inner receipt. Without that leading anchor (case 1 of Section 7.1), the chain supplies issuer-signed hop provenance only; inner origin_jti values are historical.¶
A compromised issuer can omit some or all of its own receipts and any outermost receipts from issuers it controls, but it cannot fabricate, reorder, or selectively drop receipts signed by other trusted issuers.¶
Divergence in issuer or token identifier removes current-instance binding (Section 7.1). This profile provides no in-band means to distinguish legitimate reissuance from malicious rewrapping, so unexpected divergence warrants investigation.¶
Companion profiles MAY define additional outer-token binding claims following the origin_jti pattern: each records an identifier from the outer token at receipt creation, with consumer verifiability conditioned on issuer alignment and equality with the current outer-token field.¶
When no trusted reissuing issuers are configured, recipients use strict mode, in which issuer divergence causes rejection. A missing or differing leading origin_jti under a matching issuer does not; case 3 of Section 7.1 governs it.¶
Strict mode is the recommended default; deployments that accept tokens reissued by a different issuer, such as re-emitted or translated tokens, configure the trusted reissuing issuers explicitly, through local policy or an out-of-band trust framework.¶
The prh_alg claim (Section 5.2) selects a hash algorithm other than the sha-256 default from the IANA Named Information Hash Algorithm Registry [RFC6920], without requiring a successor specification. Migration is whole-chain, not partial: a chain begun under one algorithm remains on it for its lifetime, consumers reject mixed or unsupported algorithms (step 6 of Section 7), and an extending issuer does not rehash inbound receipts, which would invalidate prior signers' prh values (step 7 of Section 6.2). New chains can adopt a different algorithm independently.¶
Deployments SHOULD begin issuing new chains under the target algorithm well before any indication that the legacy algorithm is reaching end of life, so that legacy chains expire naturally.¶
Receipts mitigate fabrication of prior-hop provenance by a compromised or dishonest downstream issuer (Section 11.1), not a compromised current outer token issuer. Such an issuer can assemble a new outer token wrapping previously harvested valid receipts for the same visible chain prefix. Deployments needing stronger guarantees can combine this profile with transparency, transaction binding, or replay-detection mechanisms.¶
Receipts can outlive the outer token they were issued with and can be carried forward across reissuance and refresh (Section 6.3) while their exp permits. Receipt expiration bounds use of the artifact, not the delegation's lifetime: reuse of a receipt within its exp window, including in extended, fanned-out, and reissued tokens, is not in itself an attack, and replay protection for the whole token follows its token type. Active delegation status, fresh authorization, and current revocation state come from the AS via introspection ([RFC7662]), fresh token issuance, or another mechanism.¶
Deployments SHOULD keep receipt exp no longer than the delegated-session lifetime it needs to cover (Section 5.2), to limit the window during which receipts signed with a compromised key remain valid. When a key compromise is detected, deployments SHOULD treat all tokens carrying receipts from the affected issuer as lacking trusted provenance for those hops and SHOULD require re-issuance through a trusted issuer.¶
The chain grows linearly with delegation depth. At a typical 400 to 800 bytes per signed receipt, chains beyond approximately 10 hops approach the 8 KB Authorization header budget common in HTTP infrastructure (an illustrative figure).¶
Deployments SHOULD verify that the outer token plus its actor_receipts array fits within the header-size budget of every component on the request path; returning receipts via introspection (Section 7.5) instead of embedding them avoids header pressure for bearer-token clients.¶
cnf Disclosure
Receipt cnf values reveal stable prior-hop public key identifiers or certificate thumbprints to any party that receives the token or introspection response, enabling cross-request and cross-service correlation of actors and services over time. Issuers SHOULD NOT include cnf in receipts unless the recipients that will receive the token have been evaluated for that disclosure risk and the risk is acceptable.¶
Receipts expose delegation history that recipients can retain and verify after the outer token expires.¶
Receipts can expose, to any party that receives the token or introspection response:¶
the set of issuers that participated in the delegation chain (receipt iss values);¶
historical presenter-key identifiers across requests, enabling cross-session correlation of actors and services;¶
internal service identities and intermediary actors that a deployment might otherwise have kept visible only to intermediate issuers;¶
workload identifiers (for example, act.sub values) that might reveal organizational structure or orchestration topology;¶
subject re-expression patterns across namespaces, which can reveal cross-domain identity mappings.¶
Deployments SHOULD minimize receipt disclosure when full provenance is not required:¶
Issuers and introspection servers MAY suppress actor_receipts entirely when policy does not permit disclosure.¶
Resource servers SHOULD request or require actor receipts only when they materially improve authorization, audit, or risk controls.¶
Deployments SHOULD prefer per-resource-server policy on receipt requirements over blanket inclusion in every token.¶
This profile does not define a per-claim selective-disclosure mechanism for receipts: chain integrity requires byte-for-byte preservation of each receipt JWT, so selective omission of individual claims within a receipt would break the chain. Selective disclosure is therefore coarse-grained:¶
Issuers MAY emit partial-coverage chains that cover only the outermost hops (see Section 6.4); this is the only mechanism for omitting individual hops, and it operates at issuance time.¶
Issuers and introspection servers MAY withhold the actor_receipts array entirely; a strict subset of an existing array cannot validate under Section 7 (see Section 7.5).¶
Finer-grained selective disclosure would require a different chain-linkage construction, for example one linking against a stable hash that survives claim redaction; adding a selective-disclosure claim alone cannot achieve it within the current prh construction.¶
A receipt is carried with the outer token to whichever audiences the outer token serves; receipts have no independent audience scoping (Section 5.2). Deployments needing audience-specific disclosure constraints SHOULD partition receipt issuance by audience at issuance time (for example, issue receipt-bearing tokens only to audiences with adequate disclosure agreements) rather than relying on receipt-level audience restriction, which this profile does not provide.¶
Receipts expose every hop the issuer chose to include. Some hops might be deployment-internal (orchestration layers, internal workload-identity services) that the deployment would not otherwise expose to recipients. Issuers SHOULD evaluate, at issuance time, which hops are appropriate to expose to which audiences. Where inner hops are not appropriate to expose, issuers SHOULD use partial coverage (omitting the inner-hop receipts) rather than fabricating, suppressing, or rewriting visible act chain entries; the latter would violate the core actor profile.¶
Stable identifiers in receipts (iss, act.sub, cnf, and any companion correlation claim such as a delegation-flow identifier) enable cross-service correlation of actors, subjects, and workflows over time. Deployments operating in privacy-sensitive contexts SHOULD evaluate the correlation risk before enabling receipts:¶
An audit pipeline that aggregates receipts across services builds a graph of who delegated to whom and when, across organizational boundaries.¶
Receipts from a single workflow are linked by prh chain hashes, exposing the delegation graph even when individual hops are routed through privacy-preserving infrastructure.¶
Receipts persist longer than the outer tokens they were issued for and might be retained in audit logs indefinitely; correlation risk is not bounded by token lifetime.¶
Extension claims can expose additional scope, audience, resource, or lifecycle information. Companion profiles defining extension claims SHOULD document the disclosure and correlation risks specific to their claims, including retention beyond token lifetime.¶
Any holder with the issuers' public keys can verify receipts, including unintended recipients. Deployments SHOULD treat token distribution as disclosure of the full carried provenance and SHOULD limit distribution accordingly.¶
This document requests registration of the following media type in the "Media Types" registry [RFC6838]:¶
Type name: application¶
Subtype name: actor-receipt+jwt¶
Required parameters: N/A¶
Optional parameters: N/A¶
Encoding considerations: 8bit; an actor receipt is a JWS compact-serialized JWT [RFC7515] [RFC7519] consisting of base64url-encoded segments separated by period (.) characters.¶
Security considerations: See Section 11 of this document and [RFC8725].¶
Interoperability considerations: N/A¶
Published specification: This document¶
Applications that use this media type: Applications that issue, exchange, or validate OAuth Actor Receipts.¶
Fragment identifier considerations: N/A¶
Additional information:¶
Person & email address to contact for further information: Karl McGuinness, public@karlmcguinness.com¶
Intended usage: COMMON¶
Restrictions on usage: None¶
Author: Karl McGuinness, public@karlmcguinness.com¶
Change controller: IETF¶
The JOSE typ value actor-receipt+jwt used by this document is the media type subtype name without the application/ prefix, following common JWT typing practice.¶
This document requests registration of the following JWT Claims in the "JSON Web Token Claims" registry [RFC7519]:¶
Claim Name: actor_receipts¶
Claim Description: Array of signed actor-hop receipts providing delegation provenance¶
Change Controller: IETF¶
Specification Document(s): This document¶
Claim Name: actor_receipts_complete¶
Claim Description: Boolean indicating whether actor_receipts covers every visible hop in the token's act chain¶
Change Controller: IETF¶
Specification Document(s): This document¶
Claim Name: sub_iss¶
Claim Description: Issuer or namespace authority for the subject in an Actor Receipt JWT¶
Change Controller: IETF¶
Specification Document(s): This document¶
Claim Name: prh¶
Claim Description: Base64url-encoded hash of the immediately preceding (older) receipt in an Actor Receipt JWT chain¶
Change Controller: IETF¶
Specification Document(s): This document¶
Claim Name: prh_alg¶
Claim Description: Hash algorithm identifier (from the IANA Named Information Hash Algorithm Registry) naming the algorithm used to compute prh in an Actor Receipt JWT¶
Change Controller: IETF¶
Specification Document(s): This document¶
Claim Name: origin_jti¶
Claim Description: The jti of the outer token at the time an Actor Receipt JWT was created (the receipt's origin outer token)¶
Change Controller: IETF¶
Specification Document(s): This document¶
This document requests registration of the following metadata names in the "OAuth Protected Resource Metadata" registry [RFC9728]:¶
Metadata Name: actor_receipts_required¶
Metadata Description: Indicates that the resource expects delegated requests to carry valid actor receipts covering at minimum the outermost visible actor hop¶
Change Controller: IETF¶
Specification Document(s): This document¶
Metadata Name: actor_receipts_complete_required¶
Metadata Description: Indicates that the resource requires complete receipt coverage for all visible actor hops¶
Change Controller: IETF¶
Specification Document(s): This document¶
This document requests registration of the following names in the "OAuth Token Introspection Response" registry [RFC7662]:¶
Name: actor_receipts¶
Description: Array of signed actor-hop receipts returned by introspection¶
Change Controller: IETF¶
Specification Document(s): This document¶
Name: actor_receipts_complete¶
Description: Indicates whether the returned actor receipts provide complete visible-hop coverage¶
Change Controller: IETF¶
Specification Document(s): This document¶
This document builds on the OAuth Actor Profile for Delegation [I-D.mcguinness-oauth-actor-profile], on the OAuth 2.0 Token Exchange specification [RFC8693], on the OAuth 2.0 Transaction Tokens work [I-D.ietf-oauth-transaction-tokens], and on prior OAuth Working Group discussion of delegation transparency, sender-constrained tokens, and proof-of-possession mechanisms ([RFC7800], [RFC8705], [RFC9449]). The author thanks the working group for that foundation.¶
Contributors and reviewers will be acknowledged in future revisions.¶
The examples in this appendix show decoded receipt contents. Actual receipts are JWS compact-serialized JWT strings carried in the actor_receipts array. The iat and exp values shown are illustrative only; in deployments, receipt exp is set per Section 5.2 and Section 6.2 so that no inbound receipt expires before the outer token that carries it.¶
Examples that contain the cnf claim illustrate explicit disclosure of historical presenter binding. Whether to include it follows Section 11.10.¶
The following example shows an outer token that carries a two-hop visible actor chain:¶
{
"jti": "d3a1b2c0-9f4e-4a1d-b8e7-12345678abcd",
"iss": "https://as.travel-provider.example",
"sub": "https://idp.enterprise.example/users/alice",
"act": {
"sub": "https://tools.travel-provider.example/booking-tool",
"iss": "https://as.travel-provider.example",
"sub_profile": "service",
"act": {
"sub": "https://agents.enterprise.example/travel-assistant",
"iss": "https://as.enterprise.example",
"sub_profile": "ai_agent"
}
},
"cnf": {
"jkt": "ToolJKT"
},
"actor_receipts": [
"<receipt-0>",
"<receipt-1>"
],
"actor_receipts_complete": true
}
¶
actor_receipts[0] is the newest receipt, created by the travel-provider AS when it added the booking tool as the new outermost actor:¶
{
"iss": "https://as.travel-provider.example",
"sub": "https://idp.enterprise.example/users/alice",
"act": {
"sub": "https://tools.travel-provider.example/booking-tool",
"iss": "https://as.travel-provider.example",
"sub_profile": "service"
},
"cnf": {
"jkt": "ToolJKT"
},
"prh": "0QvKZr5A4XW7N9LQW0u4e7z8k2Kqz6I7xL4V4Vh2nRc",
"iat": 1776745200,
"exp": 1776832000,
"jti": "c8e29c11-0c3a-4e6f-a0a6-30a52c4a8149",
"origin_jti": "d3a1b2c0-9f4e-4a1d-b8e7-12345678abcd"
}
¶
actor_receipts[1] is the older receipt, created by the enterprise AS when it first added the AI agent:¶
{
"iss": "https://as.enterprise.example",
"sub": "https://idp.enterprise.example/users/alice",
"sub_iss": "https://idp.enterprise.example",
"act": {
"sub": "https://agents.enterprise.example/travel-assistant",
"iss": "https://as.enterprise.example",
"sub_profile": "ai_agent"
},
"cnf": {
"jkt": "AgentJKT"
},
"iat": 1776741600,
"exp": 1776832000,
"jti": "1d4c4d30-fb6d-4172-b7eb-775b6b9c2b85",
"origin_jti": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
¶
This example shows the key provenance property of this profile: the current token is bound to ToolJKT, while the older receipt records that the earlier actor hop was bound to AgentJKT when it was created. The sub_iss claim in receipt[1] records that the subject identifier https://idp.enterprise.example/users/alice is interpreted under the enterprise IdP's namespace authority, which is distinct from the receipt's signer (https://as.enterprise.example, the enterprise AS).¶
Suppose the booking tool exchanges the access token above at a TTS, and the TTS rebinds the issued Transaction Token to an internal workload identified as https://wimse.travel-provider.example/payments.¶
The resulting Transaction Token can carry:¶
{
"jti": "f0e1d2c3-b4a5-6789-cdef-012345678901",
"iss": "https://tts.travel-provider.example",
"sub": "https://idp.enterprise.example/users/alice",
"act": {
"sub": "https://wimse.travel-provider.example/payments",
"iss": "https://tts.travel-provider.example",
"sub_profile": "service",
"act": {
"sub": "https://tools.travel-provider.example/booking-tool",
"iss": "https://as.travel-provider.example",
"sub_profile": "service",
"act": {
"sub": "https://agents.enterprise.example/travel-assistant",
"iss": "https://as.enterprise.example",
"sub_profile": "ai_agent"
}
}
},
"cnf": {
"jkt": "PaymentsJKT"
},
"actor_receipts": [
"<receipt-tts>",
"<receipt-0>",
"<receipt-1>"
],
"actor_receipts_complete": true
}
¶
The new leading receipt created by the TTS is:¶
{
"iss": "https://tts.travel-provider.example",
"sub": "https://idp.enterprise.example/users/alice",
"act": {
"sub": "https://wimse.travel-provider.example/payments",
"iss": "https://tts.travel-provider.example",
"sub_profile": "service"
},
"cnf": {
"jkt": "PaymentsJKT"
},
"prh": "C4zv2FK0kPjxzJz8F7G3mslmbb0TQmVQvls0gA1lV3Q",
"iat": 1776747000,
"exp": 1776832000,
"jti": "8b1ab6d1-c345-4bd3-8af2-f302d54444b7",
"origin_jti": "f0e1d2c3-b4a5-6789-cdef-012345678901"
}
¶
The inherited receipts for the booking tool and the AI agent are carried forward unchanged.¶
When receipt support is rolled out progressively across issuers, downstream tokens can carry coverage for only the outermost hops. Suppose the enterprise AS has not yet deployed receipt support, and the travel-provider AS has. The enterprise AS issues a delegated token introducing the AI agent without a receipt. The travel-provider AS exchanges that token, adds the booking tool as the new outermost actor, and creates a single receipt for that hop.¶
The resulting access token carries:¶
{
"jti": "b6d94f2a-3c81-47e5-9a0d-5f6e7a8b9c0d",
"iss": "https://as.travel-provider.example",
"sub": "https://idp.enterprise.example/users/alice",
"act": {
"sub": "https://tools.travel-provider.example/booking-tool",
"iss": "https://as.travel-provider.example",
"sub_profile": "service",
"act": {
"sub": "https://agents.enterprise.example/travel-assistant",
"iss": "https://as.enterprise.example",
"sub_profile": "ai_agent"
}
},
"cnf": {
"jkt": "ToolJKT"
},
"actor_receipts": [
"<receipt-0>"
],
"actor_receipts_complete": false
}
¶
The single receipt covers the outermost hop:¶
{
"iss": "https://as.travel-provider.example",
"sub": "https://idp.enterprise.example/users/alice",
"act": {
"sub": "https://tools.travel-provider.example/booking-tool",
"iss": "https://as.travel-provider.example",
"sub_profile": "service"
},
"cnf": {
"jkt": "ToolJKT"
},
"iat": 1776745200,
"exp": 1776832000,
"jti": "9b7a4e30-2c1f-4d8a-9b5e-f0e8a3c4b6d2",
"origin_jti": "b6d94f2a-3c81-47e5-9a0d-5f6e7a8b9c0d"
}
¶
The prh claim is omitted because this is a single-element chain. actor_receipts_complete: false signals to recipients that the inner AI-agent hop is uncovered. Resource servers that set actor_receipts_complete_required: true in their Protected Resource Metadata reject this token; resource servers that accept partial coverage validate the receipt-attested outermost hop and treat the inner hop as carried solely by the visible act chain, with no independent receipt-level provenance.¶
Suppose an introspection endpoint, operated as a trust principal separate from the originating travel-provider AS, introspects the access token from the Two-Hop Delegation Chain example and re-emits it as a JWT for an internal service. Re-emission adds no actor hop, so per Section 6.3 the re-emitting issuer carries the inbound actor_receipts array forward unchanged and creates no new receipt.¶
The re-emitted token carries the following claims:¶
{
"jti": "f4a7b9c2-1d3e-4f5a-8b6c-7d8e9f0a1b2c",
"iss": "https://introspection.travel-provider.example",
"sub": "https://idp.enterprise.example/users/alice",
"act": {
"sub": "https://tools.travel-provider.example/booking-tool",
"iss": "https://as.travel-provider.example",
"sub_profile": "service",
"act": {
"sub": "https://agents.enterprise.example/travel-assistant",
"iss": "https://as.enterprise.example",
"sub_profile": "ai_agent"
}
},
"cnf": {
"jkt": "ToolJKT"
},
"actor_receipts": [
"<receipt-0>",
"<receipt-1>"
],
"actor_receipts_complete": true
}
¶
The receipts are byte-for-byte identical to those in the Two-Hop Delegation Chain example. Two divergences from the originating-issuance pattern, both legitimate under Section 6.3, are visible at the outer-token level:¶
outer.iss is https://introspection.travel-provider.example, while receipt[0].iss remains https://as.travel-provider.example.¶
outer.jti is f4a7b9c2-1d3e-4f5a-8b6c-7d8e9f0a1b2c, while receipt[0].origin_jti remains d3a1b2c0-9f4e-4a1d-b8e7-12345678abcd (the original outer token's jti).¶
Under Section 7.1, origin_jti is historical here because the outer issuer and token identifier have changed, and acceptance requires explicit trust in the reissuing issuer (Section 11.4). When an AS refreshes its own token with a new jti, case 3 applies instead: local policy can accept the chain as provenance, but not as instance-bound.¶
[[ To be removed from the final specification ]]¶
-01¶
Restructured and tightened the text: each rule has one home, dependencies are cited rather than restated, a table covers the claim-pair convention, scope and related work are in the Introduction, and Security Considerations point to the rules they rely on.¶
Added Receipt Instance Binding; strict mode rejects only issuer divergence, and a same-issuer chain whose origin_jti differs, as after refresh, is accepted without instance binding.¶
Named ID-JAG and other assertion-grant redemption without a new hop as different-issuer reissuance.¶
Defined one lifetime rule for extension, reissuance, and refresh (lower the token's exp, drop the array, or fail), added a floor for receipt exp, and made an expired older receipt invalid.¶
Refresh no longer starts a new chain, and retained receipts are validated against the issuer's state rather than the previous access token.¶
An extending issuer takes the inbound receipts from the token carrying the delegation chain, a new receipt's iss equals the issued token's iss, and a reissuer validates a chain before carrying it forward.¶
A failed receipt chain removes only receipt-based provenance unless policy or metadata requires receipts, and a failed companion rule removes only that companion's evidence unless the companion specifies otherwise.¶
Prohibited aud in receipts.¶
Aligned error codes with [RFC8693] and [RFC7523]: invalid_request on Token Exchange, invalid_grant on JWT bearer grants and refresh, and actor_unauthorized for actor-authorization failures.¶
Clarified completeness: an extending issuer sets actor_receipts_complete: true when the receipt count matches, an introspection false makes no completeness attestation, and filtering is limited to introspection servers.¶
Compared sub_profile values as sets.¶
Allowed a TTS to include jti for instance binding, and deferred Transaction Token rejection at the resource server to the deployment.¶
Checked typ and alg before key resolution, and rejected a chain with any untrusted receipt issuer.¶
Narrowed the threat-model claims about actor-signed proofs.¶
Removed BCP 14 keywords from guidance no other party can observe, named the IETF as change controller, and aligned the examples with the base profile.¶
-00¶
Initial version.¶