Internet-Draft Identity Continuation Assertion September 2026
McGuinness & Parecki Expires 13 March 2027 [Page]
Workgroup:
Web Authorization Protocol
Internet-Draft:
draft-mcguinness-oauth-id-continuation-assertion-02
Published:
Intended Status:
Standards Track
Expires:
Authors:
K. McGuinness
Independent
A. Parecki
Okta

Identity Continuation Assertion for OAuth 2.0 Token Exchange

Abstract

This document defines the Identity Continuation Assertion, a short-lived, sender-constrained JSON Web Token (JWT) used as an OAuth 2.0 Token Exchange subject token. It enables a workload acting on a user's behalf to obtain an Identity Assertion JWT Authorization Grant (ID-JAG) for another service when it lacks a suitable credential, including when the user is no longer present.

A trusted issuer attests that a resource authorization server accepted an earlier ID-JAG and that the resulting authorization remains active and eligible for continuation. The workload exchanges this assertion at the identity provider, which evaluates the requested access under the chain authorization and current policy before issuing an onward ID-JAG. The profile supports multi-hop access across resource authorization servers that trust a common identity provider.

About This Document

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-id-continuation-assertion/draft-mcguinness-oauth-id-continuation-assertion.html. Status information for this document may be found at https://datatracker.ietf.org/doc/draft-mcguinness-oauth-id-continuation-assertion/.

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-id-continuation-assertion.

Status of This Memo

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 13 March 2027.

Table of Contents

1. Introduction

The Identity Assertion JWT Authorization Grant (ID-JAG) [I-D.ietf-oauth-identity-assertion-authz-grant] allows an application to exchange the user's identity assertion at the IdP Authorization Server (IdP) for a grant that it redeems at a target Resource Authorization Server (RAS) for an access token. A service receiving that access token may need to call a further service on the user's behalf, including when the user is no longer present. It may hold neither the user's identity assertion nor another credential accepted by the next authorization server.

This profile addresses deployments in which RASes trust a common IdP. The receiving workload's incoming access token is not accepted at the next RAS. When pairwise subject identifiers are used, the workload may also be unable to determine the user's subject at that RAS. This profile enables multi-hop access when the request's path is not known in advance, such as at a Model Context Protocol (MCP) tool gateway (Appendix B.1).

This document defines the Identity Continuation Assertion, a short-lived, sender-constrained JSON Web Token (JWT) [RFC7519] that the workload obtains from a Continuation Assertion Issuer (CAI). The IdP trusts the CAI to attest the following (Section 5.4):

The CAI binds the assertion to the key the workload proves to it (Section 5.4.1). The accepting RAS may also perform the CAI role.

The workload presents the assertion to the IdP as the subject token of an OAuth 2.0 Token Exchange [RFC8693] request. The assertion identifies the accepted authorization and the current actor; the continuation request, not the assertion, names the target and the requested authority. The IdP authenticates the workload, verifies possession of the assertion's bound key, evaluates the requested access, and resolves the user's subject for the target RAS. If authorized, it issues an onward ID-JAG that the workload redeems at that RAS (Section 5.5). The assertion conveys no downstream authority.

Each ID-JAG issued in a chain represents a hop. A root ID-JAG and the hops descending from it form a chain. An opaque continuation handle identifies each ID-JAG's hop within a chain (Section 4). The IdP records the relationships between hops and associates each chain with the authorization established at its root exchange. Each continuation is evaluated under that authorization and current policy (Section 5.1.4). RAS acceptance enables continuation; incoming access-token scopes do not automatically limit authority at another target.

A workload that continues once can reuse the resulting access token for further calls, subject to the conditions in Section 8.

This document extends ID-JAG, referred to as the base profile, and complements OAuth Identity Chaining [I-D.ietf-oauth-identity-chaining]. This profile does not replace mechanisms for narrowing an existing token within one trust domain (Appendix A.1).

The IdP, the continuing workload, a RAS from which workloads continue, and the CAI implement this extension. Root clients use the base exchange; chain establishment requires a resolvable session anchor or, optionally, a grant anchor (Section 6.1), and without one the IdP issues an ordinary ID-JAG without a handle. A terminal RAS needs only the base profile's support for redeeming a DPoP-bound ID-JAG (Section 5.5.5). This document defines no new access-token format.

1.1. Protocol Overview

The following flow illustrates one continuation. AgentApp calls a tool gateway on Alice's behalf, and the gateway calls a wiki API for her. Appendix B.1 provides the corresponding requests, responses, and tokens.

Alice authenticates at the IdP. The gateway and wiki have separate RASes. The gateway is the continuing workload, and its RAS also performs the CAI role (Section 8.1).

Steps are numbered as in the figure; "as in ID-JAG" marks what is unchanged from the base profile, "new" what this profile adds.

AgentApp     IdP       GatewayRAS    ToolGateway         WikiRAS
  |           |             |             |                 |
  | (1) exchange ID Token for ID-JAG      |                 |
  |---------->|             |             |                 |
  | ID-JAG with handle H0  [new claim]    |                 |
  |<----------|             |             |                 |
  | (2) present ID-JAG (jwt-bearer grant) |                 |
  |------------------------>|             |                 |
  | access token; RAS binds H0 to it  [new]                 |
  |<------------------------|             |                 |
  | (3) call: access token                |                 |
  |-------------------------------------->|                 |
  |           |             |             |                 |
  |           |             | (4) exchange access token: assertion [new]
  |           |             |<------------|                 |
  |           |             | assertion: H0 accepted, active, eligible [new]
  |           |             |------------>|                 |
  |           | (5) exchange assertion for next ID-JAG  [new]
  |           |<--------------------------|                 |
  |           | ID-JAG for wiki, handle H1 (child of H0)    |
  |           |-------------------------->|                 |
  |           |             |             | (6) present ID-JAG
  |           |             |             |---------------->|
  |           |             |             | access token; base profile
  |           |             |             |<----------------|
  1. As in ID-JAG, AgentApp exchanges Alice's ID Token at the IdP for an ID-JAG for the gateway's RAS (GatewayRAS in the figure). New: the IdP records the root hop, H0, and its chain authorization, and includes H0's handle in the ID-JAG's identity_continuation_handle claim (Section 5.1, Section 4).

  2. As in ID-JAG, AgentApp presents the ID-JAG to the gateway's RAS and receives an access token. New: the RAS binds the handle to the authorization it creates (Section 5.2). A RAS that does not implement this profile ignores the claim.

  3. AgentApp calls the gateway (ToolGateway) with the access token.

  4. New: the gateway exchanges that access token at its RAS's token endpoint for an Identity Continuation Assertion (Section 3). The RAS resolves the token's hop binding and attests H0's activity, eligibility for continuation, and association with the gateway (Section 5.4).

  5. New: the gateway presents the assertion to the IdP as the subject_token of a continuation exchange, with its own credential and a DPoP proof (Section 5.5). The IdP checks the wiki and the gateway against what it recorded in step 1 and current policy, resolves Alice's subject for the wiki, and issues an ID-JAG as hop H1, a child of H0 (Section 5.5.3).

  6. As in ID-JAG, the gateway presents the ID-JAG to the wiki's RAS (WikiRAS) and receives an access token. New: if that RAS implements this profile it binds H1 as in step 2 and the chain can continue; otherwise it ignores the handle and the chain ends there.

In step 4, the CAI attests acceptance and activity for the hop's RAS. In step 5, the IdP uses that attestation to evaluate continuation and resolve Alice's subject for the wiki.

2. Conventions and Definitions

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

This document uses the following terms, listed alphabetically:

Actor-lineage depth:

The number of entries in the actor lineage the IdP derives from its own hop records, after consecutive entries for the same actor are merged and before any narrowing of what the onward act discloses (Section 5.5.5). Tenant policy bounds it per branch (Section 6.3).

Chain:

An IdP-held tree of hops under one chain authorization; each hop's parent reference gives the tree its shape (Section 5.5.5), and the authorization bounds its lifetime (Section 6).

Chain authorization:

The tenant's authorization decision recorded by the IdP at the root exchange and associated with the chain's lifecycle anchor (Section 6.1). It determines which actors may continue and what authority they may obtain, subject to current policy (Section 5.1.4).

Continuation Assertion Issuer (CAI):

The role the IdP trusts to issue Identity Continuation Assertions for a tenant and the RAS whose hops it attests (Section 5.4).

Continuation Handle (identity_continuation_handle):

An opaque, unguessable, IdP-generated reference to one hop of a chain (Section 4).

Continuation-capable:

Describes an ID-JAG that carries the identity_continuation_handle claim (Section 4).

Current actor:

The workload presenting the assertion to the IdP, named by act. Its canonical actor identity is the (iss, sub) pair that its authentication to the IdP resolves to (Section 5.5.2).

Durable chain:

A chain anchored to a refresh token's OAuth grant rather than to the user's IdP session, so that it can continue after logout (Section 6.1).

Hop:

One link of a chain: the IdP's record of an ID-JAG it issued, with an immutable reference to its parent hop unless it is the root (Section 5.5.5). Its hop lineage is its path to the root; a hop from which no workload continues is terminal.

ID-JAG:

An Identity Assertion JWT Authorization Grant [I-D.ietf-oauth-identity-assertion-authz-grant] issued for a target RAS.

Identity Continuation Assertion:

A short-lived, sender-constrained JWT from a CAI, presented to the IdP as a Token Exchange subject_token to obtain an onward ID-JAG (Section 3).

IdP Authorization Server (IdP):

The authority that authenticates the user, determines the user's subject identifier for each target RAS, and issues onward grants.

Pairwise subject:

A subject identifier specific to a RAS or group of RASes, allowing the same user to have different identifiers at different audiences.

Resource Authorization Server (RAS):

An Authorization Server that protects a particular API, trusts the IdP for subject resolution, and exchanges an ID-JAG for an API access token. [I-D.ietf-oauth-identity-assertion-authz-grant] abbreviates this role (AS).

Tenant:

The administrative boundary within which the chain and CAI trust are configured; its determination is deployment-defined, derived from authenticated material, never from requester-supplied input (Section 7.3).

Trust domain:

An administrative and authentication boundary within which workloads can be directly authenticated, comparable to Workload Identity in Multi System Environments (WIMSE) [I-D.ietf-wimse-arch]. Its identifier is deployment-defined.

Workload:

A service that received a request on a user's behalf and may continue it to a further service.

3. The Identity Continuation Assertion

A CAI issues the assertion (Section 5.4); the IdP validates it (Section 5.5.3).

3.1. Token Type and Media Type

The Identity Continuation Assertion has token type urn:ietf:params:oauth:token-type:identity-continuation and media type application/oauth-identity-continuation+jwt (Section 11). It is a JWT [RFC7519] in JWS Compact Serialization.

The CAI MUST set the JOSE typ header to oauth-identity-continuation+jwt. The CAI MUST sign the assertion with an asymmetric algorithm the IdP accepts (Section 9.7). The assertion MUST NOT be encrypted (JWE) or use nested signing.

3.2. Claims

The following is a non-normative example of the Identity Continuation Assertion claim set:

{
  "iss": "https://cai.expenses.example/",
  "aud": "https://idp.example/",
  "identity_continuation_handle": "kW4uJ8pTe2NxA6rQvD1zYs",

  "act": {
    "iss": "https://expenses.example/",
    "sub": "expense-service"
  },

  "cnf": {
    "jkt": "base64url-current-actor-key-thumbprint"
  },

  "iat": 1710000020,
  "exp": 1710000200,
  "jti": "b8Rn5Yx1Qe4Nk2Wf6zVc9d"
}

The claims have the following meanings and requirements:

iss:

REQUIRED. The CAI that issued the assertion; the IdP verifies its issuer trust per the issuer-trust rule of Section 5.5.3, and its signature per the well-formedness rule.

aud:

REQUIRED. A single string exactly matching the IdP issuer identifier: not its token endpoint URL, and not the requested target.

identity_continuation_handle:

REQUIRED. The hop being continued (Section 4).

act:

REQUIRED. The current actor presenting the Token Exchange request, encoded as a single-level act claim per [RFC8693]:

  • iss and sub are REQUIRED, non-empty strings: the actor's canonical actor identity as Section 5.5.2 defines it. Only iss and sub form the canonical actor identity under this document.

  • Additional members MAY carry further information about the actor but MUST NOT affect processing defined by this document unless another specification profiles their use.

  • A recipient MUST ignore members it does not understand.

  • exp, nbf, aud, scope, cnf, and a nested act MUST NOT be present; the IdP rejects an assertion whose act carries one (the well-formedness rule of Section 5.5.3).

  • The IdP compares both iss and sub with the canonical actor identity of the authenticated client (Section 5.5.2).

cnf:

REQUIRED. A confirmation claim [RFC7800] binding the assertion to a key the current actor proves. cnf MUST contain exactly one confirmation method: jkt, the JWK SHA-256 thumbprint [RFC7638] of the DPoP key [RFC9449] (Section 9.1).

iat, exp:

REQUIRED. exp MUST follow iat. The assertion is short-lived: a CAI SHOULD NOT issue a lifetime (exp - iat) longer than 300 seconds, and an IdP SHOULD accept lifetimes of up to 300 seconds. The IdP rejects a lifetime longer than the maximum it accepts (Section 5.5.3).

nbf:

OPTIONAL. If present, processed as [RFC7519] specifies.

jti:

REQUIRED. A replay-detection identifier that MUST be unique per iss during the assertion validity window, with negligible probability of collision. It SHOULD contain at least 128 bits of entropy.

The assertion MUST NOT contain:

  • a top-level sub, auth_time, acr, amr, or sid claim; or

  • the Token Exchange request parameters audience, resource, scope, authorization_details, or requested_token_type (these are supplied by the request).

The assertion occupies the subject_token role of Token Exchange [RFC8693]: it carries no user subject, and the IdP resolves the user from the referenced hop. It is not an [RFC7523] JWT-profile assertion.

Other top-level claims MAY appear but MUST be ignored for validation, authorization, and issuance.

4. Continuation Handles (identity_continuation_handle)

An identity_continuation_handle is an opaque, non-bearer reference to one IdP-held hop of a chain. The IdP generates a fresh handle for each hop and includes it in that hop's ID-JAG. Each continuation creates a child hop with its own handle and a reference to its parent. Every onward ID-JAG includes a handle because the IdP does not know whether the target will continue the chain. Section 10 describes the resulting correlation exposure.

A handle is non-secret but security-sensitive correlation state: it confers no authority by itself, yet a handle together with a CAI trust path and the actor's credential is a larger compromise than the actor's credential alone (Section 9.1); Section 5.3 limits where it travels.

The following rules apply:

  1. When it establishes or continues a chain (Section 5.1), the IdP MUST embed a fresh identity_continuation_handle claim in the issued ID-JAG, for that root or child hop, and MUST NOT reuse a handle across hops.

  2. identity_continuation_handle MUST provide at least 128 bits of unpredictability, MUST NOT contain user-identifying information, and MUST consist of characters drawn from the base64url alphabet (A-Z, a-z, 0-9, -, _); it SHOULD NOT exceed 256 characters.

  3. Across a trust boundary, the handle is accepted only inside an ID-JAG (by the RAS) or an Identity Continuation Assertion (by the IdP), never as a standalone value. Inside the accepting RAS's domain, the CAI obtains it from RAS state or a carrier (Section 5.3); afterward it travels in the assertion.

  4. A continuation-aware RAS binds the handle to the authorization state it establishes (Section 5.2), and a hop is continuable only after that acceptance and binding (Section 5.2.1). RASes, Resource Servers, and CAIs MUST NOT modify the value. The IdP MUST use the handle only to resolve hop state, subject, and policy, never as authority.

5. Multi-Hop Cross-Domain Access

This section specifies processing in protocol order: root exchange, RAS acceptance, handle propagation, assertion issuance, and continuation exchange (Section 1.1). The following table locates each role's requirements.

Table 1
Role Requirements
IdP Establishing a Chain (Section 5.1), Continuation Exchange (Section 5.5), Chain Lifetime and Revocation (Section 6), IdP metadata (Section 7.1), Issuer Trust Configuration (Section 7.3)
Continuation-aware RAS RAS Processing (Section 5.2), Handle Carriers (Section 5.3), RAS metadata (Section 7.2)
CAI the assertion it issues (Section 3.1, Section 3.2), Assertion Issuance and its subsections (Section 5.4), Handle Carriers (Section 5.3), Separate CAI (Section 5.4.6)
Continuing workload Assertion Issuance Request, Client Authentication, and Successful Response (Section 5.4.1, Section 5.4.2, Section 5.4.4); Continuation Request and Client Authentication (Section 5.5.1, Section 5.5.2); Successful Response (Section 5.5.4) and Error Response and Recovery (Section 5.5.6)

5.1. Establishing a Chain

A chain begins when the IdP issues a continuation-capable ID-JAG on a root exchange.

5.1.1. Root Exchange Request

The root exchange and its ID-JAG conform to the base ID-JAG profile ([I-D.ietf-oauth-identity-assertion-authz-grant]) except where this document extends it to issue a continuation-capable ID-JAG. The request presents a subject token supported by the base profile, such as an ID Token, refresh token, or SAML assertion:

POST /token HTTP/1.1
Host: idp.example
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&requested_token_type=urn:ietf:params:oauth:token-type:id-jag
&audience=https://ras.gateway.example/
&resource=https://gateway.example/
&scope=tools.invoke
&subject_token=<id_token | refresh_token | SAML assertion>
&subject_token_type=<normal-subject-token-type>
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=<JWT>

Processing an actor_token on the root exchange is outside the scope of both this document and the base profile ([I-D.ietf-oauth-identity-assertion-authz-grant], Section 4.3.3), and the root actor is the authenticated client (Section 5.1.3).

5.1.2. Chain Establishment

The IdP MUST establish a chain when tenant policy permits continuation for the root exchange and the root subject token resolves to a lifecycle anchor (Section 6.1). To establish a chain, the IdP MUST include the root handle in the ID-JAG. Absent permission to continue, the IdP MUST NOT establish a chain or include an identity_continuation_handle.

Tenant policy may also restrict establishment to particular clients, grants, or targets.

The lifecycle anchor is the user's active IdP session or, for a durable chain, a refresh token's OAuth grant. When the subject token resolves to no anchor, the IdP issues the ID-JAG without a handle, as under the base profile. No request parameter requests chain establishment. Advertised support (Section 7.1) indicates capability and does not authorize establishment.

For every hop it creates, root or child, the IdP MUST record the RAS audience placed in the ID-JAG; the issuers it trusts to attest that RAS's hops are read from current tenant configuration at each exchange (Section 7.3).

Establishment is at-least-once. Retrying a lost response MAY create a second chain, and the limits of Section 6.3 apply across every chain rooted in one chain authorization.

5.1.3. Root Actor

The root actor is the authenticated OAuth client, identified by the mapping in Section 5.5.2. The base profile's recommendation to use a confidential client applies to a root exchange that establishes a chain.

This document places no proof-of-possession requirement on the root exchange. The root client's obligations are those of the base profile, and sender constraint becomes a requirement for an actor that continues (Section 5.5.2).

5.1.4. Chain Authorization

The IdP MUST associate each chain with the chain authorization under which it was established. The IdP records:

  • the authenticated user and tenant;

  • the root actor;

  • the authentication context (auth_time, acr, amr);

  • the lifecycle anchor; and

  • restrictions on which actors may continue and what authority they may obtain.

The representation is implementation-specific. The association, root facts, and restrictions remain fixed for the chain's lifetime. Later requests or policy changes cannot replace the authorization, change those facts, or relax those restrictions.

The IdP authorizes each continuation under the recorded chain authorization and current policy (Section 5.5.3). Policy can restrict access but cannot exceed that authorization. Policy evaluation is outside the scope of this document.

The root request's audience and scope describe the root ID-JAG. They do not by themselves authorize or limit later targets. RAS-local permissions and CAI attestation do not independently authorize onward access.

5.2. Continuation-Aware RAS Processing

A continuation-aware RAS implements this extension and advertises the continuation grant profile (Section 7.2). A RAS that does not implement it processes an ordinary ID-JAG and ignores the handle. An ID-JAG that such a RAS accepts cannot become a continuation source.

On accepting a continuation-capable ID-JAG, a continuation-aware RAS MUST:

  1. accept the ID-JAG per [I-D.ietf-oauth-identity-assertion-authz-grant];

  2. bind identity_continuation_handle, the ID-JAG's issuer, the tenant where the deployment conveys one, and any confirmed key to the authorization state it establishes, and record whether the authorization is eligible for continuation under the RAS's own policy; and

  3. when the ID-JAG carries cnf, as every onward ID-JAG does (Section 5.5.5) and a root ID-JAG may, issue the access token bound to the confirmed key with token_type DPoP ([RFC9449], Section 5), never as a bearer token.

How the RAS receives or determines the tenant is deployment-specific; this document defines no tenant claim.

Under the base profile, the RAS validates the grant, authenticates the client, applies local authorization policy, and issues an access token. An ID-JAG carrying cnf uses the DPoP-bound JWT grant, which verifies its sender constraint (Section 5.5.5). When a root ID-JAG lacks cnf (Section 5.1), the RAS's own policy decides whether that access token is sender-constrained.

Three rules govern binding the handle:

  • The RAS MUST bind the handle and issue the access token as one outcome: no access token without its binding, and no binding without a token.

  • All successful redemptions of one continuation-capable ID-JAG, identified by its validated issuer and handle and qualified by the tenant binding where the RAS records one, MUST resolve to the same hop binding, so that no redemption creates a distinct continuation source. A matching handle under another issuer is a different grant, not a retry.

  • The RAS exposes the binding, its record linking the handle to authorization state, only within its trust domain; the handle itself travels in the access token or another carrier as Section 5.3 describes.

5.2.1. Hop Acceptance

Two parties hold facts about a hop, neither carried on the wire:

Table 2
Fact Held by Meaning
Issuance IdP The IdP issued the ID-JAG and recorded the hop.
Acceptance RAS The RAS accepted the ID-JAG and bound the handle to the resulting authorization.

The IdP learns of acceptance through a trusted CAI's attestation and maintains no synchronized acceptance state (Section 1.1). The CAI attests only hops the RAS has accepted. A RAS acting as CAI attests its own hops; a separate CAI confirms acceptance and activity according to the RAS's authorization semantics (Section 5.4).

An issued hop cannot be continued without a trusted CAI's attestation. Unless the CAI is compromised (Section 9.4), no trusted CAI attests an issued-but-rejected ID-JAG, so continuation fails closed.

A hop is continuable while a CAI trusted for its RAS can attest it as accepted and still active, and neither it nor any ancestor is revoked; whether a particular continuation from it succeeds is decided by the validation rules of the continuation exchange (Section 5.5.3).

RAS acceptance and recorded eligibility (Section 5.2) are prerequisites for CAI issuance. The IdP authorizes downstream access under the chain authorization and current policy (Section 5.5.3).

5.3. Handle Carriers Within the Domain

Each call includes a credential or context that identifies exactly one RAS-bound authorization. The CAI MUST use the handle bound to that authorization, whether it reads RAS state directly or receives a carrier derived from it. A requester chooses which credential to present, but cannot supply or override its handle separately. A session or subject alone is not enough to select the authorization: doing so could attach another user's handle to the call.

When the RAS also acts as CAI, it reads the handle from its authorization state. It may also include the handle in its access token (Appendix B.1). A separate CAI receives the handle through a carrier derived from the RAS binding (Section 5.2). A Transaction Token [I-D.ietf-oauth-transaction-tokens] is one such carrier, an optional intra-domain choice and not a dependency of this profile. The carrier is accepted only within that trust domain (Section 5.4).

The source of the authorization context depends on the type of call:

  • For an ingress call, the access token, after the resource verifies its proof of possession where the token is sender-constrained.

  • For a downstream call, a carrier forwarded from that ingress.

  • For a scheduled run, the task named by an authenticated actor, resolved to the task authorization for which that actor is designated. The CAI MUST derive a scheduled continuation from durable RAS task authorization, not from a scheduler-held handle (Section 9.2). The scheduler holds only a task identifier; each authenticated run re-derives the handle from active task state and still requires an assertion from a trusted CAI.

The CAI checks acceptance freshness for every carrier (Section 5.4.3).

A Resource Server has no obligations under this document. A carrier SHOULD NOT expose the handle to a party with no role in continuation. Deployments keep this non-secret but security-sensitive correlation state (Section 4) out of logs, traces, and responses.

5.4. Assertion Issuance

The CAI issues the Identity Continuation Assertion that a workload presents to continue a chain across a boundary. The CAI MUST set the assertion's aud to the IdP recorded in the hop's RAS binding (Section 5.2). The CAI MUST NOT accept an IdP audience supplied by the requester.

The CAI attests three facts about its own domain:

  • The RAS accepted the ID-JAG for the hop.

  • The authorization the RAS established from it is active and, by the RAS's own authorization semantics, eligible for continuation.

  • The authenticated workload is associated with that authorization context, in which it received, or was designated to process, the request that hop authorized.

Whether that actor may continue, and to what, is the IdP's decision under the chain authorization and current policy (Section 5.5.3).

5.4.1. Assertion Issuance Request

A CAI that is an OAuth authorization server, including a RAS acting as its own CAI, MAY issue assertions from its token endpoint using Token Exchange [RFC8693] as profiled in this and the following subsections. Such a RAS SHOULD support this method of issuance, so that a workload in its domain has one request to implement. Issuance by other means remains deployment-specific (Section 5.3).

A workload obtains assertions from the token endpoint of the CAI its deployment designates. For a RAS acting as its own CAI, this is the RAS's token endpoint, discoverable through the RAS's metadata (Section 7.2); a separate CAI is configured within the trust domain, which this document leaves to the deployment (Section 5.3).

The current actor acts as an OAuth client of the CAI. It makes a Token Exchange request to the CAI's token endpoint with the following parameters:

grant_type:

REQUIRED. The value urn:ietf:params:oauth:grant-type:token-exchange.

requested_token_type:

REQUIRED. The value urn:ietf:params:oauth:token-type:identity-continuation.

subject_token:

REQUIRED. Either the access token the client received on the call it is continuing, or the Transaction Token that carries the hop's handle for that call.

subject_token_type:

REQUIRED. urn:ietf:params:oauth:token-type:access_token or urn:ietf:params:oauth:token-type:txn_token [I-D.ietf-oauth-transaction-tokens], matching the subject_token.

The audience, resource, scope, actor_token, and actor_token_type parameters MUST NOT be included: targets and scope are chosen at the IdP exchange (Section 3.2), and the authenticated client is the actor named in act.

The following example carries the client's authentication and its DPoP proof (Section 5.4.2):

POST /token HTTP/1.1
Host: cai.example
Content-Type: application/x-www-form-urlencoded
DPoP: <proof of possession of the key to be placed in cnf>

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&requested_token_type=urn:ietf:params:oauth:token-type:identity-continuation
&subject_token=<access token presented to the client>
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=<JWT>

5.4.2. Client Authentication

The client MUST authenticate to the CAI's token endpoint ([RFC6749], Section 2.3). The client MUST include in the request a DPoP proof [RFC9449] of the client's own key. The CAI MUST verify that proof and bind the assertion to the proven key in cnf. The CAI's verification is defense in depth: the actor proves possession of that key again to the IdP at the continuation exchange, which is the security boundary for continuation (Section 5.5.2).

The CAI MUST issue only for an actor it is authoritative to associate with the RAS-accepted authorization, typically one in the RAS's trust domain; actor authentication is deployment-specific.

5.4.3. Request Validation

The CAI MUST verify that the subject_token is of the type its subject_token_type declares (Section 5.4.1) and is one of the following:

  • an access token the accepting RAS issued, that RAS being one whose hops the CAI attests, unexpired, and valid for a protected resource that the authenticated client operates, as determined from the CAI's registration or configuration of that client; or

  • a Transaction Token valid for the CAI's trust domain under [I-D.ietf-oauth-transaction-tokens], Section 12.2, carrying the typ header and issuer that specification defines, and carrying the hop's handle as chain context (Section 5.3, Section 5.4.6).

A token of another type presented as subject_token, such as an ID-JAG or an Identity Continuation Assertion, is unacceptable (Section 5.4.5).

With an access token, the client is a resource server exchanging a token it received, the scenario of the example in [RFC8693], Section 2.3. A RAS acting as CAI resolves its own token; a separate CAI resolves it as Section 5.4.6 describes. In this exchange the subject_token identifies the RAS authorization context from which continuation is requested; its subject is not copied into the resulting assertion.

Either subject_token type supplies the facts below. The CAI MUST authenticate the actor and issue only after establishing these facts:

  1. The handle came through an authenticated, confidential, integrity-protected channel or equivalent authenticated state.

  2. The current actor controls the key placed in cnf.

  3. act names that actor. If offline attenuation reached the actor, the attenuated credential it received, the subject_token or the carrier that conveyed it, is valid (Appendix A.1).

  4. The handle is the one bound to the authorization context the actor presents, its access token or carrier, and the actor is a party that context was issued or forwarded to (Section 5.3, Section 5.2.1). Selecting another intact context is the actor's choice; substituting a handle within a context is not. The handle is input to verify, never authority in itself (Section 4).

  5. Evidence that is authoritative by the RAS's own authorization semantics, whatever the carrier, confirms that the authorization remains active and that its binding still records it as eligible for continuation. That evidence is either a recheck of RAS authorization state or, where the RAS's authorization is a self-contained short-lived token the RAS itself issued, that token's validity (Section 5.4.6).

The subject token's integrity protection and the authenticated request establish fact 1; the DPoP proof, fact 2; client authentication, fact 3, whose attenuation condition the CAI establishes by validating the attenuated credential it received; and the bound handle and the RAS's acceptance evidence, facts 4 and 5.

Section 9.1 traces the binding chain these facts form from ID-JAG to assertion.

A live recheck SHOULD be used where the tenant requires withdrawal of a hop's authorization to stop fresh assertions before the RAS's token would expire. With self-contained evidence, the CAI stops issuing when that token expires, as for any OAuth access token. Where the evidence is a self-contained token, the assertion's exp SHOULD NOT exceed that token's expiry, so that an assertion is not presentable after the evidence that supported it has lapsed (Section 6.2).

A domain may add its own conditions for issuing, for example limiting which of its workloads may obtain assertions, but such conditions narrow issuance only. Target or purpose hints can narrow CAI issuance, but neither they nor propagated context expand the authority the IdP may issue (Section 5.5.3).

5.4.4. Successful Response

A successful response is a Token Exchange response ([RFC8693], Section 2.2.1) in which access_token carries the Identity Continuation Assertion, issued_token_type is urn:ietf:params:oauth:token-type:identity-continuation, token_type is N_A (not applicable), and expires_in reflects the assertion's lifetime. The access_token member is the [RFC8693] response container; the assertion is not an OAuth access token, which token_type N_A signals. This document adds one parameter:

identity_continuation_authorization_server:

REQUIRED. A JSON string containing the issuer identifier ([RFC8414]) of the authorization server at which the client exchanges the assertion for an ID-JAG. The CAI MUST set its value to the assertion's aud claim. The client uses this parameter to identify the IdP without decoding the assertion.

The client obtains that IdP's token_endpoint from its authorization server metadata ([RFC8414]), retrieved with the oauth-authorization-server well-known URI suffix under the issuer identifier. Before sending the assertion or its own credentials there, the client MUST confirm that the returned issuer exactly matches identity_continuation_authorization_server. Where the IdP publishes no metadata, the client uses configuration bound to that issuer identifier (Section 7).

The client SHOULD present the assertion only to an IdP it is configured to trust; this parameter identifies the destination but does not establish trust.

The CAI MUST NOT include a refresh_token in the response, which would let a client obtain further assertions without presenting a token or passing the acceptance check.

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
  "issued_token_type": "urn:ietf:params:oauth:token-type:identity-continuation",
  "access_token": "<Identity Continuation Assertion, compact JWS>",
  "token_type": "N_A",
  "identity_continuation_authorization_server": "https://idp.example/",
  "expires_in": 180
}

5.4.5. Error Response

On failure, the CAI returns an error response according to [RFC6749], Section 5.2, and [RFC8693], Section 2.2.2. This document specifies the following error mappings:

  • invalid_request when the subject_token is invalid or unacceptable under policy, including when it is unknown, expired, revoked, not of the type its subject_token_type declares, not valid for a resource the client operates, has no bound handle, or names an authorization whose binding does not record it as eligible for continuation, or when the request includes a parameter this document prohibits (Section 5.4.1);

  • unauthorized_client when the client is not permitted to use this grant type; and

  • invalid_dpop_proof ([RFC9449]) for a failed proof.

DPoP nonce processing and the use_dpop_nonce error apply unchanged from [RFC9449].

5.4.6. Separate CAI

A separate CAI MUST obtain the handle and evidence of RAS acceptance and continued eligibility from a source authoritative for that RAS within its domain (Section 8.1):

  • the RAS's authorization state;

  • its introspection response [RFC7662]; or

  • a self-contained short-lived token issued by the RAS.

For an access-token subject_token (Section 5.4.1), the CAI uses introspection or validates a self-contained token.

The handle alone does not convey the originating IdP, tenant, or eligibility for continuation. The introspection response's active member reports token activity, not continuation eligibility ([RFC7662], Section 2.2). A separate CAI relying on introspection therefore obtains the eligibility and the originating IdP and tenant from deployment-defined evidence or configuration, as the requirement above already demands.

With a Transaction Token, the handle arrives through the carrier of Section 5.3. Validating that token alone does not establish RAS acceptance or eligibility for continuation.

The IdP accepts a separate CAI's attestation only where it trusts that CAI to attest the accepting RAS's hops, from tenant configuration (Section 7.3, the issuer-trust rule of Section 5.5.3).

5.5. Continuation Exchange

A continuation exchange is an OAuth 2.0 Token Exchange request [RFC8693] whose subject_token is an Identity Continuation Assertion. It uses the same Token Exchange framework as the root exchange (Section 5.1), substituting the assertion for the root credential and adding the actor authentication and DPoP proof described below.

Before a chain can continue to a target, the current actor needs a client registration or resolvable client identity at that target's RAS (Section 5.5.5).

5.5.1. Continuation Request

A continuation exchange presents an Identity Continuation Assertion, a DPoP proof of the cnf key, and the actor's client authentication (Section 5.5.2):

POST /token HTTP/1.1
Host: idp.example
Content-Type: application/x-www-form-urlencoded
DPoP: <proof of possession of the cnf key>

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&requested_token_type=urn:ietf:params:oauth:token-type:id-jag
&audience=https://ras.travel.example/
&resource=https://api.travel.example/
&scope=trips.read
&subject_token=<identity-continuation-assertion>
&subject_token_type=urn:ietf:params:oauth:token-type:identity-continuation
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=<JWT>

The request carries no actor_token or actor_token_type: the actor named in act is the authenticated client (Section 5.5.2), and the IdP rejects a request carrying either (Section 5.5.3, Section 5.5.6).

The continuation request, never the assertion, supplies the requested audience, resource, scope, requested_token_type, and any authorization_details [RFC9396] (Section 3.2). A request can carry multiple resource indicators [RFC8707]. The authorization rule (Section 5.5.3) applies to authorization_details and to scope alike.

5.5.2. Client Authentication

The current actor MUST authenticate as an OAuth client with a credential that resolves to its canonical actor identity. The canonical actor identity is the (iss, sub) pair the IdP holds for that client.

The iss member identifies the actor's identity authority, which determines issuer pairing (Section 5.5.3, Section 9.4) independently of the credential parameter. If the client registration specifies no other canonical actor identity, iss is the IdP's issuer identifier and sub is the client_id. This applies, for example, to a client registered without a workload identity that authenticates with a client secret or mutual-TLS certificate.

The IdP MUST derive that pair from its registration of the client or its configuration of the client's credential issuer, not from the client authentication method, and MUST NOT accept a self-asserted mapping.

For [RFC7523] client authentication, the IdP MUST authorize the assertion's issuer for the authenticated client. The canonical actor identity remains the pair derived from the IdP's configuration (Appendix A.4).

This mapping applies to every exchange. Client authentication identifies the root actor; this profile adds no proof-of-possession requirement to the root exchange (Section 5.1). On a continuation exchange (Section 5.5.1), the IdP MUST also match the canonical actor identity to the assertion's act.

The comparison runs between actor identities, never between a raw OAuth client identifier and an act value:

authenticated OAuth client
        |  authoritative mapping (IdP registration)
        v
canonical actor identity (iss, sub)
        ^
        |  equal
       act

The IdP MUST compare the actor iss and sub as case-sensitive strings with no transformation or canonicalization ([RFC7519]): the assertion's act is compared with the canonical actor identity, and identities in different tenants never compare equal.

The actor MUST prove possession of the key in cnf; for the jkt method, that proof is a DPoP proof [RFC9449]. The IdP MUST bind the onward ID-JAG to a key the actor proves in the request. This version defines only DPoP confirmation; the target validates it using [RFC9449]. Support for mutual-TLS confirmation [RFC8705] remains an open question (Appendix C).

A request contains one DPoP proof, so the assertion and resulting ID-JAG are bound to the same key. Client authentication may use an independent credential. Other confirmation methods could support different keys (Appendix C). Key rotation takes effect when the actor obtains an assertion bound to the new key.

5.5.3. Request Validation

Where the IdP offers idempotent retry, a presentation whose (iss, jti) matches an ISSUED reservation, as Section 5.5.7.1 defines, is processed under that section; an IdP that does not offer retry rejects every second presentation (Section 5.5.7). For a first presentation, the IdP MUST reject the request unless every rule below holds. Section 5.5.6 specifies error precedence when multiple rules fail.

  1. Request parameters.

    • exactly one each of grant_type, subject_token, subject_token_type, requested_token_type, and audience, and no actor_token or actor_token_type ([RFC8693], Section 2.1);

    • zero or more resource, treated as an order-independent set, and at most one each of scope and authorization_details, all OPTIONAL and, when present, evaluated by the authorization rule; and

    • grant_type is urn:ietf:params:oauth:grant-type:token-exchange, subject_token_type is urn:ietf:params:oauth:token-type:identity-continuation, and requested_token_type is urn:ietf:params:oauth:token-type:id-jag;

  2. Assertion well-formedness.

    • the assertion is a JWT whose JOSE typ header is oauth-identity-continuation+jwt;

    • it is a JWS in Compact Serialization, and is neither a JWE nor a nested JWT (Section 3.1);

    • it carries exactly one value for each claim required by Section 3.2 and none of the claims that section forbids;

    • iss, aud, identity_continuation_handle, and jti are non-empty strings, act and cnf are JSON objects with cnf naming exactly one confirmation method, and iat, exp, and any nbf are NumericDate numbers;

    • act carries none of the members Section 3.2 forbids (exp, nbf, aud, scope, cnf, and a nested act);

    • aud exactly matches the IdP's issuer identifier;

    • the signature validates with the issuer's resolved signing keys (Section 7);

    • alg is neither none nor a symmetric algorithm and is on the IdP's allowlist (Section 9.7, [RFC8725]); and

    • the signing key comes from trusted issuer configuration, not from a jku, x5u, or embedded jwk header, though kid MAY select among the configured keys;

  3. Issuer trust.

    • the assertion iss is either the accepting RAS itself, identified by the ID-JAG aud recorded for the hop as a string or one-element array, or another issuer the IdP trusts to attest that RAS's hops, recorded from tenant configuration (Section 7.3); and

    • in either case, that issuer is trusted for the chain's tenant, recorded at establishment, and authorized to pair, for that tenant, with the actor's identity authority (Section 5.5.2);

  4. Chain state.

    • the handle identifies a hop the IdP issued, on an active chain, that the assertion attests as accepted: a valid assertion from a CAI the IdP trusts for that hop's RAS is itself that attestation; no claim in the assertion carries it (Section 5.2.1);

    • neither the presented hop nor any ancestor is revoked;

    • the actor lineage that results from merging consecutive same-actor entries, as the onward act will (Section 5.5.5), is within its actor-lineage depth bound, which counts lineage entries, not hops; and

    • the continuation is within the fan-out, rate, and hop-count limits of the chain authorization (Section 6.3);

  5. Current actor and binding.

    • act is present, conforms to the schema of Section 3.2, and identifies the current actor, the canonical actor identity of the authenticated client (Section 5.5.2);

    • the request proves possession of the cnf key with a matching DPoP proof (Section 5.5.2, [RFC9449]); the assertion is never accepted as a bearer token ([RFC7800]); and

    • the IdP can resolve, for the requested audience, both the user's subject identifier and the actor's client identifier (Section 5.5.5);

  6. Freshness and replay.

    • iat is within the IdP's permitted clock skew, exp follows iat, the assertion is unexpired within that same skew, and any nbf has passed within it ([RFC7519], Section 4.1.5). One skew value applies to iat as future skew, to exp as past skew, and to reservation retention (Section 5.5.7); it SHOULD NOT exceed 60 seconds;

    • the assertion's lifetime does not exceed the maximum the IdP accepts (Section 3.2); and

    • jti is not yet reserved for the assertion issuer (Section 5.5.7); where the IdP offers idempotent retry, a presentation matching an ISSUED reservation is recovery (Section 5.5.7.1), not a continuation exchange, and any other reserved jti is rejected;

  7. Authorization. The IdP MUST issue an ID-JAG only if the chain authorization associated with the referenced hop (Section 5.1.4) and current policy permit the authenticated actor to continue from that hop and permit the authority represented by the resulting ID-JAG. This evaluation includes the audience, resources, scopes, and authorization details, including any default scope or other defaults the IdP applies under its policy. An omitted scope uses a policy default or results in invalid_scope ([RFC6749], Section 3.3). An omitted resource does not by itself require a default. The IdP MUST reject the request if it cannot establish that authorization.

    The issued ID-JAG carries the scope, resource, and authorization_details values that express the granted authority. Target or purpose hints reaching the CAI (Section 5.4.3) MUST NOT control the IdP's target decision, and propagated context MUST NOT expand the authority permitted by the chain authorization and current policy. The IdP evaluates each authorization detail according to its type ([RFC9396]) and rejects a type whose authorization semantics it does not implement.

5.5.4. Successful Response

The response to a continuation exchange follows the base ID-JAG profile: the IdP returns the ID-JAG in access_token, with token_type N_A (not applicable; [RFC8693], Section 2.2.1). The IdP MUST NOT include a refresh_token: a renewable credential would let the workload obtain further grants without fresh CAI attestation, or root a new chain through the refresh-token anchor, outside the hop's revocation dependencies.

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
  "issued_token_type": "urn:ietf:params:oauth:token-type:id-jag",
  "access_token": "<continuation-capable ID-JAG, compact JWS>",
  "token_type": "N_A",
  "expires_in": 300
}

On success, the IdP MUST record a child hop (Section 5.2.1) of the presented hop before returning an ID-JAG carrying the resolved target sub and the child hop's fresh handle. An idempotent retry (the freshness rule; Section 5.5.7.1) instead returns the previously issued grant unchanged, creating no new hop or handle.

The hop reference is delivered as the ID-JAG's identity_continuation_handle claim (Section 4), a claim inside access_token and not a separate Token Exchange response parameter; the accepting RAS binds it (Section 5.2), and the CAI reaches it through RAS state or intra-domain context (Section 5.3).

There is no chain-expiry response parameter: chain lifetime is authoritative at the IdP (Section 6), and a deployment needing advance warning conveys it through task or authorization state, an optional ID-JAG claim, or a management API.

5.5.5. Onward ID-JAG Construction

The onward ID-JAG conforms to the base ID-JAG profile ([I-D.ietf-oauth-identity-assertion-authz-grant]) except where this document extends it: its sub is the IdP-issued subject identifier for the target audience, and aud_sub remains available under the base profile where the target's native subject namespace differs.

Because the onward ID-JAG carries cnf, the actor redeems it with the DPoP-bound JWT grant, urn:ietf:params:oauth:grant-type:jwt-dpop ([I-D.parecki-oauth-jwt-dpop-grant]), and a DPoP proof of the bound key, as the base profile specifies for a key-bound ID-JAG ([I-D.ietf-oauth-identity-assertion-authz-grant], Section 9.8.1.2.1). The target RAS needs no continuation support to redeem this grant. A RAS that does not implement this profile may issue a bearer access token under the base profile. A continuation-aware RAS follows the binding requirements of Section 5.2, even if no further continuation occurs.

Where the recorded root authentication context contains auth_time, acr, or amr, the IdP MUST include them in the onward ID-JAG unchanged. Continuation MUST NOT extend or strengthen the authentication context, for example by raising acr or adding amr beyond the user's root authentication.

The IdP constructs act as follows:

  • It places the authenticated current actor atop the presented hop's lineage, whose origin is the authenticated client of the root exchange even if the root ID-JAG carries no act (Section 5.1.3); it never copies lineage from the assertion, and siblings do not contribute.

  • A hop's parent reference is immutable. The IdP MUST derive lineage from that hop's ancestry to the root, excluding sibling branches. Storage and traversal methods are implementation-specific.

  • Consecutive identical actors, those whose canonical actor identities are equal under the comparison rules of Section 5.5.2, both iss and sub, merge into one entry, though the hop record remains; policy MAY limit disclosed depth, narrowing what a target sees without changing the actor-lineage depth bound the IdP enforces (the chain-state rule of Section 5.5.3).

  • A RAS MUST NOT read the absence of a further nested act as proof that no earlier actor exists, because policy may narrow what is disclosed: act is the disclosed actor lineage, not the authoritative history, which only the IdP's hop records hold.

The onward ID-JAG's client_id identifies the current actor's OAuth client at the target RAS and may differ from its client identifier at the IdP. If the IdP cannot resolve that target client identity, the request fails with invalid_target (Section 5.5.6).

The following is a non-normative example of the onward ID-JAG issued by the IdP:

{
  "iss": "https://idp.example/",
  "aud": "https://ras.travel.example/",
  "sub": "travel-pairwise-subject",

  "client_id": "expense-service",
  "resource": "https://api.travel.example/",
  "scope": "trips.read",

  "identity_continuation_handle": "Uc9fB3mHs5LdK7gEnX2wRj",

  "auth_time": 1710000000,
  "acr": "urn:example:loa:2",
  "amr": ["pwd", "mfa"],

  "act": {
    "iss": "https://expenses.example/",
    "sub": "expense-service",
    "act": {
      "iss": "https://expenses.example/",
      "sub": "expense-app"
    }
  },

  "cnf": {
    "jkt": "base64url-current-actor-key-thumbprint"
  },

  "iat": 1710000025,
  "exp": 1710000325,
  "jti": "idjag-travel-01"
}

5.5.6. Error Response and Recovery

On failure, the IdP returns an error response ([RFC6749], Section 5.2; [RFC8693], Section 2.2.2). On a first presentation, when more than one rule of Section 5.5.3 fails, the IdP MUST return the code for the earliest failure. Request-parameter and well-formedness failures (including signature verification) come first. No chain-state code is returned before issuer trust for the hop's RAS is established, nor before the client authentication and key proof of the current-actor rule succeed, so no chain-state code reaches a caller that has not authenticated as the current actor and proved the cnf key. Among chain-state failures a permanently unusable hop precedes a limit. The contents of an unverified assertion never determine the response, and a missing hop is invalid_request, so a caller learns nothing about which handles exist.

For recovery, client authentication, key proof, and fingerprint matching precede chain-state checks (Section 5.5.7.1).

On a first presentation or matching ISSUED recovery, the IdP MUST return invalid_continuation (Section 11) when the handle identifies an issued hop that is permanently unusable: its chain has expired or ended, the hop or an ancestor is revoked, or the tenant has withdrawn the chain's permission to continue (Section 6.2). The IdP MUST NOT return invalid_continuation in any other case.

For other failures, the IdP MUST use the following error codes:

  • invalid_request: a malformed, inconsistent, or unacceptable token, including an assertion that fails the well-formedness rule of Section 5.5.3 (which covers signature verification) or the issuer-trust rule; an act that does not equal the authenticated client's canonical actor identity (Section 5.5.2); an unknown handle; a lifetime above the accepted maximum; prohibited actor_token or actor_token_type parameters; or a reserved assertion that cannot be processed as idempotent recovery (Section 5.5.7.1), other than a matching ISSUED recovery whose hop is permanently unusable, which is invalid_continuation.

  • invalid_dpop_proof: a DPoP failure.

  • unauthorized_client: the chain authorization or current policy does not permit this actor to continue from the hop. Other actors may still continue; withdrawal of the chain's permission is invalid_continuation.

  • invalid_grant: continuation would exceed actor-lineage depth, fan-out, hop-count, or rate limits (Section 6.3). A rate-limited request can be retried after the policy-defined window; other limit failures require a different request.

  • invalid_target: the requested audience or a requested resource is not permitted by the chain authorization or current policy, or the IdP cannot resolve the user's subject identifier or the actor's client identifier at the target.

  • invalid_scope: a requested scope is not permitted by the chain authorization or current policy, or scope is omitted and no policy default exists ([RFC6749], Section 3.3).

  • invalid_authorization_details: a requested authorization detail is not permitted by the chain authorization or current policy, or its type is one the IdP does not implement.

DPoP nonce processing and the use_dpop_nonce error apply unchanged from [RFC9449].

Recovery from invalid_continuation requires a new root exchange, authorized under current policy and resolving to an active anchor (Section 5.1). Establishing a new chain does not reactivate the old chain's handles.

Other errors apply to the request and do not establish that the chain is permanently unusable. An actor-lineage depth rejection concerns the particular continuation whose resulting lineage would exceed the bound, not the hop itself; a continuation that merges into an existing lineage entry, or a later policy raising the bound, may still succeed.

After a lost response, the client MAY retry the same assertion where the IdP offers idempotent retry (Section 5.5.7.1), or obtain a fresh assertion. Expired acceptance evidence can prevent fresh assertion issuance; shared fan-out or hop-count limits can prevent a subsequent exchange (Section 6.3). A fresh assertion may create an equivalent grant and sibling hop but no additional authority.

A client cannot distinguish on the wire a presentation whose request does not match its reservation's fingerprint from one whose reservation is RESERVED or FAILED: all three return invalid_request (Section 5.5.7.1). The client can retry the original request within the retry window, since pending issuance may complete, or obtain a fresh assertion. Other invalid_request failures, such as malformed requests or prohibited parameters, require correcting or abandoning the request.

5.5.7. Replay Reservation and Retry

The IdP MUST issue at most one grant per assertion, including under concurrent presentations: it reserves the assertion's (iss, jti) as an atomic first-writer decision once validation succeeds and before it issues the grant, and MUST retain the reservation through exp plus the permitted clock skew (one value, per the freshness rule of Section 5.5.3). Uniqueness is keyed on (iss, jti), since partitioning by tenant alone would let two assertion issuers in one tenant collide on a reused jti. The reservation MUST be visible to every IdP instance that accepts assertions for that issuer, and an instance that cannot reach that shared state MUST reject the request rather than issue. Without idempotent retry this needs only the set of (iss, jti) values presented within that window.

A request that fails validation creates no reservation and does not modify any existing reservation.

The IdP MUST reject a second presentation of a reserved assertion unless it offers idempotent retry.

A consumed assertion is not equivalent to a fresh one. With live acceptance evidence, the CAI refuses a fresh assertion once the hop's authorization has lapsed (Section 5.4.3); with self-contained evidence, issuance continues until the RAS token expires, and single-use still keeps each consumed assertion from authorizing more than its one grant within that tail (Section 9.1). Single-use therefore bounds staleness and multiplicity; it does not itself establish that the hop was accepted.

5.5.7.1. Idempotent Retry

An IdP MAY offer idempotent retry by binding the reservation to a fingerprint of the request first authorized and recording the reservation as RESERVED, ISSUED, or FAILED (distinct from the hop facts of Section 5.2.1). These names describe the states an IdP distinguishes, not a required representation. The IdP MUST reject a presentation whose (iss, jti) matches a reservation but whose request does not match that reservation's fingerprint. A presentation matching the fingerprint of an ISSUED reservation within the IdP's retry window is processed as recovery, defined below. The fingerprint MUST cover:

  • audience as an exact string;

  • the resource values as an order-independent set;

  • scope as an order-independent set;

  • the exact authorization_details JSON after form decoding (a different serialization is a different request);

  • the actor's iss and sub;

  • the confirmation key in cnf (its jkt thumbprint in this version); and

  • a SHA-256 hash of the exact subject_token after form decoding, which binds the fingerprint to the specific assertion and its handle.

An IdP that offers idempotent retry MUST retain the ISSUED reservation, its fingerprint, and its result for a retry window it defines, alongside the reservation retention of Section 5.5.7; recovery is available only within that window and only while the issued grant is unexpired. The window is a deployment choice and MAY be advertised or documented.

For recovery, the IdP MUST verify:

  • the requester's client authentication and canonical actor identity;

  • the DPoP proof of the cnf key;

  • the request fingerprint; and

  • that the presented hop and every ancestor remain unrevoked and the chain has not ended, including through anchor expiry or withdrawal of the chain's permission to continue (Section 6.2).

If these checks succeed and the issued grant is unexpired, the IdP MUST return that grant unchanged. Otherwise, it MUST reject the request under Section 5.5.6. The IdP never extends or reissues the grant; after its exp, the client obtains a fresh assertion.

Recovery applies no other validation or policy checks. Changes to actor or target authorization, or to issuer trust, do not prevent recovery of an already-issued grant. Recovery creates no hop and consumes no fan-out, hop-count, or rate budget. Throttling repeated requests is a deployment choice.

A presentation matching a RESERVED reservation, whose first presentation has not completed, MUST be rejected with invalid_request; the client can retry it once that first presentation completes (Section 5.5.6). A reservation that does not reach ISSUED before exp plus the permitted clock skew becomes FAILED, which is final: a presentation matching a FAILED reservation MUST be rejected with invalid_request, and the client obtains a fresh assertion.

Application idempotency is outside the scope of this document. Section 8 provides implementation guidance; discovery of optional recovery support remains an open question (Appendix C).

6. Chain Lifetime and Revocation

This profile supports session-anchored chains and, optionally, durable chains anchored to a refresh token's grant. A session-anchored chain ends with the session; a grant-anchored chain can support an unattended agent after logout (Appendix B.3). The ending rules and limits apply to both forms. A reader implementing session anchors only can skip the grant-specific processing and background example.

A chain is continuable only while active at the IdP. Each continuation is a fresh policy check, and revoking a hop stops its descendants at the next continuation, fail-closed; an offline-attenuated token, by contrast, stays usable for its lifetime without contacting an authority.

Revocation does not invalidate an already-issued ID-JAG, so the revocation window is the ID-JAG's remaining redemption window plus the lifetime of the access token a late redemption obtains; any refresh token the RAS issues, which the base profile recommends against, extends it further.

Three independent lifetimes govern a continuation:

Revoking the chain does not shorten an already-issued access token, and an access token outliving the chain does not extend it.

ID-JAG redeem   |==|
access token    |===========|              RAS-set, independent
IdP-held chain  |=========================| IdP-held, spans hops

6.1. Anchors

The root subject token resolves to one of these anchors (Section 5.1):

  • an ID Token sid [OIDC.FrontChannelLogout] resolving to an active IdP session for that user and client;

  • a SAML SessionIndex [SAML2.Core] resolving to an active IdP session for that user and client; or

  • for a durable chain, a refresh token's OAuth grant.

The IdP MUST NOT root a chain from an unresolved anchor or an access token; non-user-rooted authority is out of scope. sid and SessionIndex are used only for resolution and MUST NOT enter assertions or chain context.

Support for grant anchors is OPTIONAL; a session-anchored implementation is complete. Without it, base processing of a refresh-token subject is unchanged; any otherwise-authorized ID-JAG omits the continuation handle (Section 5.1.2). Rotation of a refresh token does not affect the grant anchor.

6.2. Ending a Chain

A chain ends when:

  • the session it is anchored to terminates;

  • the grant it is anchored to expires or is revoked; or

  • tenant policy withdraws permission to continue it.

A chain MUST NOT outlive its anchor (Section 6.1): a session-anchored chain ends with the session, and only a grant-anchored chain may outlive logout. An authorization that a session produced but that has its own lifecycle, such as a refresh token's grant, is a grant anchor, so logout ends a chain only when the session itself is the anchor. Ending a chain this way bounds only new continuations; an ID-JAG already issued remains redeemable for its own lifetime, since redemption is not a continuation.

The IdP has these duties over chain lifetime:

  • it MUST bound chain lifetime by the chain authorization;

  • it MUST support administrative revocation of an entire chain and MAY revoke an individual hop's subtree; and

  • it MUST reject continuation on a revoked, expired, or ended chain.

The IdP ends a chain when it observes the withdrawal, whether through a policy event or at the next continuation attempt, and an ended chain stays ended: restoring the policy that withdrew permission does not revive it, its handles remain permanently unusable (Section 5.5.6), and a new chain is needed.

RAS-local withdrawal stops fresh assertions once the CAI observes it; self-contained acceptance evidence may remain usable until its expiry (Section 5.4.3). Previously issued assertions remain subject to the IdP's current chain, trust, and authorization checks (Section 5.5.3). RAS-local withdrawal does not revoke descendants accepted at other RASes; stopping their continuation requires IdP revocation of the chain or affected subtree.

How an IdP surfaces chains to users and administrators for review and revocation is deployment-specific; [GRANT-MGMT] describes OAuth grant management for that purpose.

6.3. Limits

Fan-out is the number of child hops continued from one hop and is counted per hop. Hop count is the total number of hops in a chain across all branches. Rate is the number of newly issued continuations, not attempts, within a window tenant policy defines. Hop count and rate are counted per chain and, where the tenant configures one budget for a chain authorization, aggregated across every chain rooted in it, so sibling chains share that budget; a retried establishment (Section 5.1) MUST NOT evade it. Revocation of the chain authorization applies to every chain rooted in it. The actor-lineage depth bound, set by tenant policy, is enforced per branch.

The IdP MUST enforce a finite hop-count limit on every chain, either the tenant's configured value or the IdP's default, so that a workload continuing as itself cannot extend a chain without bound. Fan-out and rate limits remain optional tenant controls. Whether the profile should fix a default is open (Appendix C).

7. Authorization Server Metadata and Trust Configuration

An IdP and a Resource Authorization Server advertise support in their metadata; the IdP configures the CAIs and actor identity authorities it trusts.

7.1. IdP Authorization Server Metadata

An IdP that supports this profile SHOULD signal it in its authorization server metadata [RFC8414] with the following parameter:

identity_continuation_supported:

OPTIONAL. Boolean, default false, indicating that the IdP accepts the urn:ietf:params:oauth:token-type:identity-continuation subject token type and issues continuation-capable ID-JAGs. Such an ID-JAG is still the urn:ietf:params:oauth:token-type:id-jag type; an IdP that sets this flag also lists that type in identity_chaining_requested_token_types_supported ([I-D.ietf-oauth-identity-chaining]). This flag adds only the continuation capability.

7.2. Resource Authorization Server Metadata

A Resource Authorization Server that binds the identity_continuation_handle claim to authorization state MUST advertise support by listing the grant profile urn:ietf:params:oauth:grant-profile:id-jag-continuation in its authorization_grant_profiles_supported [I-D.ietf-oauth-identity-assertion-authz-grant]. This value indicates that the server recognizes continuation-capable ID-JAGs and performs that binding (Section 5.2). The base ID-JAG grant profile indicates ordinary grant processing without handle binding.

A Resource Authorization Server that advertises urn:ietf:params:oauth:grant-profile:id-jag-continuation MUST also advertise the base urn:ietf:params:oauth:grant-profile:id-jag profile and the urn:ietf:params:oauth:grant-type:jwt-bearer grant type on which ID-JAG depends ([I-D.ietf-oauth-identity-assertion-authz-grant]). It MUST also advertise urn:ietf:params:oauth:grant-type:jwt-dpop, since every onward ID-JAG it redeems carries cnf (Section 5.5.5).

7.3. Issuer Trust Configuration

The IdP MUST authorize CAI and actor identity authority pairings per tenant; separate trust in each is insufficient (Section 9.4). The IdP MUST scope CAI trust by issuer, keys, tenant, and the RAS it attests for. Tenant determination MUST derive from authenticated material, not requester-supplied input.

When a CAI's issuer identifier is that of an OAuth authorization server, the IdP obtains its signing keys from the jwks_uri in that server's metadata ([RFC8414]); a CAI without such a jwks_uri, like any other CAI, uses authenticated configuration. The IdP MUST refresh remotely obtained keys under a bounded cache policy, so a key removed from the JWK Set stops validating once the refresh takes effect.

The IdP evaluates issuer trust and keys against its current trusted issuer and key state, so removing an issuer or revoking its keys de-authorizes it for existing chains: continuation from such a CAI's assertions is refused at the next continuation exchange (the issuer-trust rule of Section 5.5.3).

CAI trust is provisioned and withdrawn through deployment-specific configuration at the IdP.

8. Implementation Considerations

This non-normative section provides implementation guidance for IdPs, RASes, and CAIs. Conformance depends on the normative sections.

Continuation is per authorization context, not per call: a workload continues once to obtain an ID-JAG for a target and then reuses the access token it redeems there while that token remains valid and covers the requested access. Reuse requires the same user, tenant, actor, and key as the call that obtained the token. Each source hop needs its own continuation: reusing a sibling branch's token would associate subsequent continuation with that branch's lineage and revocation dependencies.

The first call requires assertion issuance, continuation exchange, and ID-JAG redemption. Later calls using the same valid token require no further exchanges.

Renewal is another continuation with a fresh assertion, which succeeds only if the CAI's preconditions still hold (Section 5.4.3); an expired access token does not by itself entitle the workload to another.

Every continuation depends on IdP availability. A separate CAI also needs access to the RAS's acceptance evidence. Offline attenuation can avoid these dependencies where the subject and issuer trust remain usable across the boundary (Appendix A.1); it cannot replace IdP subject resolution.

The IdP retains hop records for the chain's lifetime and prunes hop state for ended chains and revoked hops. It retains each assertion's (iss, jti) reservation as Section 5.5.7 requires, expiring it by the same clock it uses to evaluate exp.

An IdP that offers idempotent retry also holds the ISSUED reservation, its fingerprint, and its result for the retry window it defines, with recovery governed by Section 5.5.7.1; an IdP that does not offer retry needs no more than the reservation itself. Ancestry caches and audit indexes can supplement immutable parent records, provided lineage and ancestor revocation checks remain correct for each branch (Section 5.5.5).

An IdP can derive handles from an internal delegation identifier using a keyed one-way function, provided the derived handles still satisfy rules 1 and 2 of Section 4 and remain unlinkable.

A RAS can make the handle binding and token issuance of Section 5.2 one outcome with a local transaction, or with a compensating action that revokes a token whose binding did not commit.

The CAI accounts for retries separately from fan-out and keeps audit records of its issuance and limit enforcement. The IdP performs end-to-end audit correlation across a chain, while each RAS logs only its local subject.

Consecutive continuations by the same actor do not increase actor-lineage depth. The fan-out, rate, and hop-count limits of Section 6.3 bound this growth.

Failure paths worth testing before deployment:

An IdP can defer materializing chain state until the first continuation, provided the handle still resolves to the same root and chain authorization; deferral does not relax the replay rules of Section 5.5.7. Whether the hop tree could be replaced by self-verifying handles is an open question (Appendix C), not a realization this document describes.

8.1. Deployment Topologies

The two topologies differ in which party performs the CAI role and how it obtains hop state:

Table 3
Topology CAI role held by Source Fits when
Co-located the accepting RAS RAS state one operator runs the domain
Separate a separate CAI the IdP trusts for the RAS domain carrier the RAS is shared infrastructure, the gateway is only a Resource Server, or keys and audit need isolation

In the baseline co-located deployment, the IdP configures the RAS's issuer trust (Section 7.3), including keys, tenant, and issuer pairings (Section 9.4). The RAS advertises the continuation profile (Section 7.2).

Both topologies produce the same Identity Continuation Assertion and apply the same CAI requirements. Either CAI can issue the assertion from its token endpoint (Section 5.4.1): a co-located RAS takes the access token it issued as the subject_token, and a separate CAI takes the token that carries the handle. Both require the same number of exchanges. Co-location reduces configuration and trust relationships; a separate CAI also requires a carrier and access to acceptance evidence.

Carrier selection is deployment-specific, subject to Section 5.3. The gateway example uses the RAS's access token (Appendix B.1). Common carriers include:

  • A Transaction Token [I-D.ietf-oauth-transaction-tokens] can carry the handle as request context (Section 5.3).

  • A signed JWT access token [RFC9068] issued by the accepting RAS can carry the handle as a claim. The claim records issuance-time state and therefore cannot reflect a later revocation; the CAI's acceptance check (Section 5.4.3) covers that.

  • For an opaque access token issued by the accepting RAS, its introspection response [RFC7662] can carry the handle as a member, generated when introspection occurs and present only when active is true.

9. Security Considerations

This profile assumes TLS, correct IdP subject mapping and authorization evaluation, and the OAuth guidance of [RFC9700]. The adversaries considered are a party that captures an assertion or access token, a compromised or misdirected workload, a party holding a handle and nothing else, a rogue or over-scoped actor identity authority, a compromised RAS or CAI, an actor that forges lineage, and an attacker that substitutes token types, algorithms, or keys.

Section 10 addresses correlation and disclosure risks.

9.1. Sender Constraint and Proof of Possession

An Identity Continuation Assertion identifies the current actor. The IdP matches its act claim to the authenticated client's canonical actor identity (Section 5.5.2). An attacker cannot use a captured assertion without also authenticating as that actor.

Sender constraint additionally requires possession of the cnf key, verified with DPoP [RFC9449] (Section 5.5.3, Section 5.5.2). Possession of the actor's client credential alone is insufficient without that key. The onward ID-JAG and the continuation-aware RAS's access token are bound to the same key (Section 5.5.2, Section 5.2). Sender constraint is maintained across continuation-capable hops rather than demonstrated once at issuance, with an authenticated transition to the next actor's key at each workload boundary. Where the chain ends at a RAS that does not implement this profile, that RAS's token binding is its own policy under the base profile (Section 5.5.5).

The facts the CAI establishes before issuing (Section 5.4.3) form the binding chain from ID-JAG to assertion. In the synchronous flow, the redeemer proved the ID-JAG's cnf key at the RAS, which bound the handle to its authorization state and the access token to that key (Section 5.2); the caller proved that key on its call to the workload, which verified it as an [RFC9449] resource server; the workload authenticates to the CAI and proves its own key (facts 2 and 3); and the CAI places that key in cnf. Where the context was forwarded within the domain, carried in a Transaction Token, or derived from durable task state for a scheduled run (Section 5.3), fact 4 substitutes for the call-boundary check.

The root hop is different. A root ID-JAG need not carry cnf, and its RAS sender-constrains the access token by its own policy, so a root hop may issue a bearer token. A party that captures such a token can call the workload and so induce that honest workload's continuation under the workload's own key; the workload's proof of possession does not prevent this, because the workload is the legitimate presenter. Such a token weakens only the caller's link in the binding chain; facts 2 and 3 apply unchanged.

Because acceptance does not bound downstream authority (Section 5.2.1), a captured root token can induce continuation to any target permitted by the chain authorization and current policy, not only the resource the token was issued for. Token theft is the inherited bearer-token risk; continuation can extend its consequences to the downstream authority available under that authorization. Sender constraint at ingress prevents use of the token without its bound key.

This profile adds no proof requirement at the root (Section 5.1); continuation rests on the continuing actor's key, the RAS binding, and the CAI's attestation, not on the root client's key. At assertion issuance the actor proves only its own key, not any key the incoming subject token is bound to (Section 5.4.1): the chain changes key at the call boundary by design, because the access token is the caller's credential and the assertion is the callee's, so the CAI does not compare the requester's proof with the access token's key.

Replay of a captured assertion is confined to the IdP continuation exchange and requires the actor's key. The freshness rule bounds the window, and single-use (Section 5.5.7) confines a consumed assertion to the one grant it first obtained: without it, an actor whose RAS-local authorization had lapsed, and whom the CAI would therefore refuse a fresh assertion, could keep continuing from a consumed one, to any target the chain authorization and current policy permit, until it expired. Idempotent recovery after a lost response is optional and does not reopen replay (Section 5.5.7).

9.2. Authorization Enforcement

The IdP checks the chain authorization associated with the chain (Section 5.1.4), not merely whether the user or actor could obtain access under another authorization. The CAI's attestation and RAS acceptance do not grant onward authority (Section 5.5.3, Section 5.2.1). The CAI, not the IdP, checks any offline attenuation segment (Section 5.4.3).

A compromised or misdirected workload can request any target, so broad continuation permissions increase the damage it can cause. Policy changes may affect active chains, but current policy cannot override a restriction of the chain authorization:

  • Deployments requiring a fixed set of targets retain that restriction in the chain authorization; adding a service to general tenant policy alone does not authorize it for such a chain.

  • Where that authorization leaves targets to current policy, adding a permitted target widens access for every active chain it governs.

  • Likewise, adding a permitted continuer admits a new actor to each such chain, subject to any actor restrictions in the chain authorization and the binding checks in Section 5.5.3.

Wrong-handle association can continue the wrong user's bounded chain. The RAS-bound state, read directly or through a carrier derived from it, is what associates a request with a handle, and the CAI rejects a substituted one (Section 5.3, Section 5.4.3).

Because the CAI issues only for an actor it is authoritative to associate with the accepted authorization (Section 5.4), a party that merely holds a handle cannot bypass the RAS-acceptance path.

A scheduler-held handle would become a durable bearer-like credential outside the per-call key proof and RAS binding that gate every other use, so a scheduled continuation derives from durable RAS task authorization (Section 5.3).

Downstream resources may gate access on authentication strength (acr) or methods (amr); if continuation could raise those claims, an actor could reach a step-up-gated resource the user never authenticated strongly enough for. Authentication context therefore comes only from the recorded root authentication, copied unchanged into onward ID-JAGs (Section 5.5.5). A target that gates on acr or amr should evaluate auth_time as well, since on a grant-anchored chain (Section 6.1) the user may be absent and that context may be old.

9.3. Trust in Actor Identity Authorities

A rogue or over-scoped actor identity authority is an impersonation vector: a party controlling one could name an actor in another domain or tenant and continue that actor's chains. The IdP therefore takes that authority from its own registration of the client or its configuration of the client's credential issuer, never from the request, and accepts it only where it is paired with the CAI for the chain's tenant (Section 5.5.2, Section 5.5.3).

An accompanying CAI assertion does not relax that. CAI attestation of the hop and authentication of the actor are independent checks, and neither substitutes for the other (Section 9.4).

9.4. Conjunctive Trust and Issuer Pairing

A continuation requires all of these, and no one of them suffices alone:

  • a CAI the IdP trusts for the presented hop's accepting Resource Authorization Server, which attests the chain-to-actor transition (the issuer-trust rule of Section 5.5.3);

  • the actor's identity authority, trusted for the current actor's domain and tenant, which vouches for the actor through the mapping of its client credential (the current-actor rule of Section 5.5.3);

  • live proof of possession of the confirmed key (the current-actor rule of Section 5.5.3); and

  • the chain authorization and current policy enforced by the IdP (the authorization rule of Section 5.5.3).

The IdP's trust configuration records these pairings (Section 7.3).

9.5. Topology and Trust

Accepting the RAS's own identifier under the issuer-trust rule establishes no issuer, key, tenant, or issuer-pairing trust (Section 5.5.3, Section 9.4). Separating the CAI isolates keys and components but creates no protocol-level quorum: the IdP still sees one signed attestation (Section 8.1).

A workload that obtains the assertion by exchanging the access token or Transaction Token it holds for the call (Section 5.4.1) presents nothing it did not already hold; what it gains is the CAI's attestation, gated by policy and the acceptance check.

A compromised RAS can fabricate acceptance state in either topology, since a separate CAI reads that state as authoritative. A compromised separate CAI can additionally attest a hop the RAS refused. Section 6.2 describes the effects of RAS-local withdrawal, including delayed observation by a separate CAI. The chain authorization and current policy still bound the result.

9.6. Actor Chain Integrity

The nested act claim is the disclosed actor lineage, a possibly minimized representation of the IdP's hop lineage, which is the authoritative actor history. A compromised actor could try to forge it, to hide its own identity, impersonate a more privileged prior actor, or fabricate a delegation that never happened. This profile denies that by construction: an assertion names only the current actor, and the IdP derives the onward lineage from its own hop records (Section 5.5.5), and it rejects any mismatch between the current actor and the assertion's act (the current-actor rule of Section 5.5.3).

A party therefore cannot rewrite history it does not control, and offline-attenuation segments, which the IdP does not observe, do not enter lineage. Lineage is disclosed, not exhaustive: policy may narrow it (Section 5.5.5), so a rule such as "deny if a given actor ever participated" cannot be enforced from act alone.

9.7. Token, Type, and Algorithm Confusion

An attacker may try to pass one token type off as another, downgrade the signature algorithm, or steer verification to a key it controls. The JOSE verification rules that deny this are stated in the well-formedness rule of Section 5.5.3.

10. Privacy Considerations

A hop's identity_continuation_handle is visible to its ID-JAG client, the accepting Resource Authorization Server, the CAI, the workload that receives the assertion, and the IdP. Where a deployment propagates it, the carrier and its recipients, including any audience of an access token that carries it, see it as well (Section 5.3).

Handles are opaque, high-entropy, and hop-specific (Section 4), so they do not provide a common cross-RAS identifier for a user.

The chain is not unlinkable: the IdP correlates it, participants sharing a handle can correlate that hop, and actor lineage and timing may correlate transactions across audiences. For example, an observer comparing ID-JAGs issued to two audiences within one short window and carrying the same actor-chain shape may infer they belong to one user's transaction, even without a shared handle.

The onward ID-JAG's act, the disclosed actor lineage, also names the prior actors to the accepting RAS outright, with no correlation needed; policy may limit the depth disclosed to each audience (Section 5.5.5).

11. IANA Considerations

Note: The token type URI urn:ietf:params:oauth:token-type:id-jag referenced by this document is registered by [I-D.ietf-oauth-identity-assertion-authz-grant] and is not registered here.

Note: The authorization_grant_profiles_supported metadata parameter and the base urn:ietf:params:oauth:grant-profile:id-jag value referenced by this document are defined and registered by [I-D.ietf-oauth-identity-assertion-authz-grant] and are not registered here; this document registers only the urn:ietf:params:oauth:grant-profile:id-jag-continuation value.

11.1. OAuth Extensions Error Registration

IANA is requested to register the following error in the "OAuth Extensions Error Registry" established by [RFC6749].

Error Name:

invalid_continuation

Error Usage Location:

token endpoint response

Related Protocol Extension:

Identity Continuation Assertion for OAuth 2.0 Token Exchange

Change Controller:

IETF

Specification Document(s):

This document, Section 5.5.6

11.2. OAuth Parameters Registration

IANA is requested to register the following parameter in the "OAuth Parameters" registry established by [RFC6749].

Parameter name:

identity_continuation_authorization_server

Parameter usage location:

token response

Change controller:

IETF

Specification Document(s):

This document, Section 5.4.4

11.3. OAuth URI Registration

IANA is requested to register the following value in the "OAuth URI" registry established by [RFC6755] and used for token type identifiers by [RFC8693].

URN:

urn:ietf:params:oauth:token-type:identity-continuation

Common Name:

Token type URI for the Identity Continuation Assertion

Change Controller:

IETF

Specification Document(s):

This document, Section 3.1

IANA is also requested to register the following grant-profile value in the same registry.

URN:

urn:ietf:params:oauth:grant-profile:id-jag-continuation

Common Name:

Grant profile identifier for a continuation-capable ID-JAG, whose accepting Resource Authorization Server binds the identity_continuation_handle claim to authorization state

Change Controller:

IETF

Specification Document(s):

This document, Section 7, Section 5.2

11.4. Media Type Registration

IANA is requested to register the following media type in the "Media Types" registry, in the manner described in [RFC6838], corresponding to the JOSE typ header value oauth-identity-continuation+jwt.

Type name:

application

Subtype name:

oauth-identity-continuation+jwt

Required parameters:

N/A

Optional parameters:

N/A

Encoding considerations:

binary; the +jwt structured syntax suffix [RFC8417] registers this encoding. An Identity Continuation Assertion is a JWT [RFC7519], a series of base64url-encoded values (some of which may be empty) separated by period ('.') characters.

Security considerations:

See Section 9 of this document.

Interoperability considerations:

N/A

Published specification:

This document, Section 3.1

Applications that use this media type:

Applications using OAuth 2.0 Token Exchange [RFC8693] to perform identity continuation across SaaS boundaries.

Fragment identifier considerations:

N/A

Additional information:


Deprecated alias names for this type: N/A
Magic number(s): N/A
File extension(s): N/A
Macintosh file type code(s): N/A

Person & email address to contact for further information:

Karl McGuinness (public@karlmcguinness.com)

Intended usage:

COMMON

Restrictions on usage:

N/A

Author:

Karl McGuinness, Aaron Parecki

Change controller:

IETF

11.5. JSON Web Token Claims Registration

IANA is requested to register the following claim in the "JSON Web Token Claims" registry established by [RFC7519].

Claim Name:

identity_continuation_handle

Claim Description:

An opaque, IdP-generated reference to one hop of a continuation chain, used to resolve the referenced hop and its chain state. This claim appears in an Identity Continuation Assertion and in a continuation-capable ID-JAG, and its value may also travel in intra-domain chain context, including an access token the accepting Resource Authorization Server issues (Section 5.3).

Change Controller:

IETF

Specification Document(s):

This document, Section 4

11.6. OAuth Token Introspection Response Registration

IANA is requested to register the following value in the "OAuth Token Introspection Response" registry established by [RFC7662].

Name:

identity_continuation_handle

Description:

The continuation handle bound to the introspected token's authorization, present only when active is true; Section 5.3 constrains its exposure within the issuing server's trust domain

Change Controller:

IETF

Specification Document(s):

This document, Section 5.3

11.7. OAuth Authorization Server Metadata Registration

IANA is requested to register the following value in the "OAuth Authorization Server Metadata" registry established by [RFC8414].

Metadata Name:

identity_continuation_supported

Metadata Description:

Boolean value indicating support for the Identity Continuation Assertion profile

Change Controller:

IETF

Specification Document(s):

This document, Section 7

12. References

12.1. Normative References

[I-D.ietf-oauth-identity-assertion-authz-grant]
Parecki, A., McGuinness, K., and B. Campbell, "Identity Assertion JWT Authorization Grant", Work in Progress, Internet-Draft, draft-ietf-oauth-identity-assertion-authz-grant-04, , <https://datatracker.ietf.org/doc/html/draft-ietf-oauth-identity-assertion-authz-grant-04>.
[I-D.ietf-oauth-transaction-tokens]
Tulshibagwale, A., Fletcher, G., and P. Kasselman, "Transaction Tokens", Work in Progress, Internet-Draft, draft-ietf-oauth-transaction-tokens-11, , <https://datatracker.ietf.org/doc/html/draft-ietf-oauth-transaction-tokens-11>.
[I-D.parecki-oauth-jwt-dpop-grant]
Parecki, A., "OAuth 2.0 JWT Authorization Grant with DPoP Binding", Work in Progress, Internet-Draft, draft-parecki-oauth-jwt-dpop-grant-01, , <https://datatracker.ietf.org/doc/html/draft-parecki-oauth-jwt-dpop-grant-01>.
[OIDC.FrontChannelLogout]
OpenID Foundation, "OpenID Connect Front-Channel Logout 1.0", <https://openid.net/specs/openid-connect-frontchannel-1_0.html>.
[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/rfc/rfc2119>.
[RFC6749]
Hardt, D., Ed., "The OAuth 2.0 Authorization Framework", RFC 6749, DOI 10.17487/RFC6749, , <https://www.rfc-editor.org/rfc/rfc6749>.
[RFC7519]
Jones, M., Bradley, J., and N. Sakimura, "JSON Web Token (JWT)", RFC 7519, DOI 10.17487/RFC7519, , <https://www.rfc-editor.org/rfc/rfc7519>.
[RFC7523]
Jones, M., Campbell, B., and C. Mortimore, "JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants", RFC 7523, DOI 10.17487/RFC7523, , <https://www.rfc-editor.org/rfc/rfc7523>.
[RFC7638]
Jones, M. and N. Sakimura, "JSON Web Key (JWK) Thumbprint", RFC 7638, DOI 10.17487/RFC7638, , <https://www.rfc-editor.org/rfc/rfc7638>.
[RFC7662]
Richer, J., Ed., "OAuth 2.0 Token Introspection", RFC 7662, DOI 10.17487/RFC7662, , <https://www.rfc-editor.org/rfc/rfc7662>.
[RFC7800]
Jones, M., Bradley, J., and H. Tschofenig, "Proof-of-Possession Key Semantics for JSON Web Tokens (JWTs)", RFC 7800, DOI 10.17487/RFC7800, , <https://www.rfc-editor.org/rfc/rfc7800>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/rfc/rfc8174>.
[RFC8414]
Jones, M., Sakimura, N., and J. Bradley, "OAuth 2.0 Authorization Server Metadata", RFC 8414, DOI 10.17487/RFC8414, , <https://www.rfc-editor.org/rfc/rfc8414>.
[RFC8693]
Jones, M., Nadalin, A., Campbell, B., Ed., Bradley, J., and C. Mortimore, "OAuth 2.0 Token Exchange", RFC 8693, DOI 10.17487/RFC8693, , <https://www.rfc-editor.org/rfc/rfc8693>.
[RFC8707]
Campbell, B., Bradley, J., and H. Tschofenig, "Resource Indicators for OAuth 2.0", RFC 8707, DOI 10.17487/RFC8707, , <https://www.rfc-editor.org/rfc/rfc8707>.
[RFC8725]
Sheffer, Y., Hardt, D., and M. Jones, "JSON Web Token Best Current Practices", BCP 225, RFC 8725, DOI 10.17487/RFC8725, , <https://www.rfc-editor.org/rfc/rfc8725>.
[RFC9396]
Lodderstedt, T., Richer, J., and B. Campbell, "OAuth 2.0 Rich Authorization Requests", RFC 9396, DOI 10.17487/RFC9396, , <https://www.rfc-editor.org/rfc/rfc9396>.
[RFC9449]
Fett, D., Campbell, B., Bradley, J., Lodderstedt, T., Jones, M., and D. Waite, "OAuth 2.0 Demonstrating Proof of Possession (DPoP)", RFC 9449, DOI 10.17487/RFC9449, , <https://www.rfc-editor.org/rfc/rfc9449>.
[SAML2.Core]
OASIS, "Assertions and Protocols for the OASIS Security Assertion Markup Language (SAML) V2.0", , <https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf>.

12.2. Informative References

[GRANT-MGMT]
OpenID Foundation, "Grant Management for OAuth 2.0", <https://openid.net/specs/oauth-v2-grant-management.html>.
[I-D.fletcher-transaction-token-chaining-profile]
Fletcher, G., Kasselman, P., and S. O'Dell, "Transaction Token Authorization Grant Profile for OAuth Identity and Authorization Chaining", Work in Progress, Internet-Draft, draft-fletcher-transaction-token-chaining-profile-02, , <https://datatracker.ietf.org/doc/html/draft-fletcher-transaction-token-chaining-profile-02>.
[I-D.ietf-oauth-identity-chaining]
Schwenkschuster, A., Kasselman, P., Burgin, K., Jenkins, M. J., Campbell, B., and A. Parecki, "OAuth Identity and Authorization Chaining Across Domains", Work in Progress, Internet-Draft, draft-ietf-oauth-identity-chaining-17, , <https://datatracker.ietf.org/doc/html/draft-ietf-oauth-identity-chaining-17>.
[I-D.ietf-wimse-arch]
Salowey, J. A., Rosomakho, Y., and H. Tschofenig, "Workload Identity in a Multi System Environment (WIMSE) Architecture", Work in Progress, Internet-Draft, draft-ietf-wimse-arch-08, , <https://datatracker.ietf.org/doc/html/draft-ietf-wimse-arch-08>.
[I-D.li-oauth-delegated-authorization]
Ruochen, L., Wang, W., Liu, P. C., and T. Li, "OAuth 2.0 Delegated Authorization", Work in Progress, Internet-Draft, draft-li-oauth-delegated-authorization-03, , <https://datatracker.ietf.org/doc/html/draft-li-oauth-delegated-authorization-03>.
[I-D.mcguinness-oauth-actor-proofs]
McGuinness, K., "OAuth Actor-Signed Hop Proofs", Work in Progress, Internet-Draft, draft-mcguinness-oauth-actor-proofs-00, , <https://datatracker.ietf.org/doc/html/draft-mcguinness-oauth-actor-proofs-00>.
[I-D.mcguinness-oauth-actor-receipts]
McGuinness, K., "OAuth Actor Receipts for Delegation Provenance", Work in Progress, Internet-Draft, draft-mcguinness-oauth-actor-receipts-00, , <https://datatracker.ietf.org/doc/html/draft-mcguinness-oauth-actor-receipts-00>.
[RFC6755]
Campbell, B. and H. Tschofenig, "An IETF URN Sub-Namespace for OAuth", RFC 6755, DOI 10.17487/RFC6755, , <https://www.rfc-editor.org/rfc/rfc6755>.
[RFC6838]
Freed, N., Klensin, J., and T. Hansen, "Media Type Specifications and Registration Procedures", BCP 13, RFC 6838, DOI 10.17487/RFC6838, , <https://www.rfc-editor.org/rfc/rfc6838>.
[RFC8417]
Hunt, P., Ed., Jones, M., Denniss, W., and M. Ansari, "Security Event Token (SET)", RFC 8417, DOI 10.17487/RFC8417, , <https://www.rfc-editor.org/rfc/rfc8417>.
[RFC8705]
Campbell, B., Bradley, J., Sakimura, N., and T. Lodderstedt, "OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens", RFC 8705, DOI 10.17487/RFC8705, , <https://www.rfc-editor.org/rfc/rfc8705>.
[RFC9068]
Bertocci, V., "JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens", RFC 9068, DOI 10.17487/RFC9068, , <https://www.rfc-editor.org/rfc/rfc9068>.
[RFC9700]
Lodderstedt, T., Bradley, J., Labunets, A., and D. Fett, "Best Current Practice for OAuth 2.0 Security", BCP 240, RFC 9700, DOI 10.17487/RFC9700, , <https://www.rfc-editor.org/rfc/rfc9700>.

Appendix A. Design Rationale

This non-normative appendix records the principal design choices.

A.1. IdP-Mediated Continuation

This profile serves deployments where the target trusts a common IdP to resolve the user's subject identifier. Each continuation returns to that IdP for subject resolution and checks of current authorization and chain state (Section 5.5.3). RAS-local withdrawal remains subject to the freshness of acceptance evidence (Section 6.2).

Offline attenuation, in which a party narrows and forwards a credential without contacting the IdP, such as [I-D.li-oauth-delegated-authorization], suits boundaries where existing subject and issuer trust remain usable and offline delegation is acceptable. A deployment can attenuate within a trust domain and continue across boundaries requiring IdP resolution. Crossing to a target that does not trust the common IdP requires a separate trust agreement and profile, such as [I-D.fletcher-transaction-token-chaining-profile].

A.2. CAI Attestation and ID-JAG Redemption

An ID-JAG authorizes the client named in client_id to redeem the grant at the RAS named in aud. When sender-constrained, it also binds that use to the client's key. The RAS receives the grant as its audience; receipt does not authorize the RAS to present it as a different client or replace its key binding ([I-D.ietf-oauth-identity-assertion-authz-grant]).

Similarly, a workload receives an access token as the protected resource. The token authorizes the incoming caller's access and, when sender-constrained, is bound to that caller's key. Validating the caller's proof does not give the workload possession of the key or establish a credential for the workload to present at the IdP (Section 9.1).

The Identity Continuation Assertion makes this transition explicit. The CAI attests that the receiving workload is associated with an accepted, active authorization eligible for continuation, and issues an assertion addressed to the IdP and bound to that workload's key (Section 5.4.3). The IdP can then authenticate and authorize the continuing workload using its own identity and key (Section 5.5.3).

Direct exchange of either token under [RFC8693] would require additional rules establishing the receiving party's authority to continue and binding the exchange to its identity and key (Appendix C).

Assertion issuance reuses the Token Exchange [RFC8693] request and response framework at the CAI's token endpoint (Section 5.4.1).

A Transaction Token [I-D.ietf-oauth-transaction-tokens] may carry the context from which the CAI issues its assertion; its validity alone is not RAS acceptance evidence (Section 5.4.3).

The assertion carries no top-level user subject. The resulting ID-JAG carries the IdP-resolved subject and a fresh child handle, including for a terminal target. Issuing an onward ID-JAG preserves the target's grant redemption interface. Target-side resolution of a reference would require additional target processing; it and a direct recipient-bound credential remain open alternatives (Appendix C).

Asymmetric signing avoids distributing signing secrets between CAIs and IdPs. One compact JWS representation reduces implementation choices (Section 3.1). TLS protects transport; the profile does not conceal assertion contents from the carrying workload. Encryption and nested JWTs are outside this profile.

A.3. Per-Hop Handles

A handle identifies the hop being continued, so the IdP can derive the correct ancestry and apply revocation to the appropriate subtree. A chain-wide identifier alone would not distinguish sibling branches. The handle references IdP-held state without carrying user identity or the ancestry itself (Section 4, Section 5.5.5); its visibility still has correlation implications (Section 10).

Keeping authorization and lifecycle state at the IdP supports current checks at each continuation. The cost is state retained for the chain's lifetime and IdP availability for each exchange. Stateless hop commitments remain an open question (Appendix C).

A.4. Actor Identity and Target Client Identity

In [RFC8693], act normally records a delegation relationship, the party acting for the subject of the token that carries it. In an Identity Continuation Assertion it instead identifies the authenticated actor associated with the accepted authorization context, whose continuation request the IdP evaluates (Section 3.2, Section 5.5.3); it asserts no downstream authority.

The current actor's canonical identity in act records who acted, independently of the credential used to authenticate it (Section 5.5.2). The onward ID-JAG's client_id identifies that actor's OAuth client at the target RAS. Keeping these identities distinct preserves lineage across target-specific client registrations while retaining ID-JAG redemption compatibility. The actor therefore needs a client identity resolvable at the target (Section 5.5).

The may_act claim ([RFC8693], Section 4.4) can inform actor authorization; it supplies neither RAS acceptance evidence nor target subject resolution.

A.5. Authorization Boundary

Each continuation is authorized under the recorded chain authorization and current policy (Section 5.1.4). RAS acceptance establishes the context from which the actor continues, and no more (Section 9.2): scopes at different audiences have independent semantics, so cross-target restrictions belong in the chain authorization and IdP policy rather than in a RAS's local scopes.

This profile carries identity and lineage and binds continuation to an accepted authorization. Whether a requested action serves the work the user or tenant authorized remains a deployment policy decision. The profile defines neither a purpose claim nor an agent authorization model.

Single-use limits each assertion to one issued grant. The lifetime bound limits how long the assertion can authorize a new continuation (Section 5.5.7).

Appendix B. Examples

This non-normative appendix illustrates three deployments: a tool gateway that selects its upstream at request time (Appendix B.1), a SaaS chain across three domains with separate CAIs (Appendix B.2), and an unattended background agent (Appendix B.3). The gateway example is the baseline. Authorization outcomes illustrate deployment policy rather than conformance requirements.

Message sequences are vertical lifelines with time flowing downward. Each example identifies its deployment topology before describing the flow.

B.1. Gateway Example (Co-located RAS and CAI)

AgentApp calls a tool gateway on Alice's behalf. The gateway selects the upstream API, here a wiki, at request time. AgentApp knows only the gateway's audience. The gateway obtains an ID-JAG for the wiki without receiving Alice's identity assertion.

Topology: co-located. GatewayRAS accepts ID-JAGs and acts as CAI for those hops. It includes the handle in its access tokens.

All parties trust one enterprise IdP at https://idp.example/, tenant tenant-123. Alice has pairwise subjects at GatewayRAS and WikiRAS, which only the IdP can map.

  • Agent domain (agent.example): client agent-app, the confidential runtime that holds Alice's session and roots the chain.

  • Gateway domain (gateway.example): GatewayRAS, the gateway's authorization server at https://ras.gateway.example/, and the workload tool-gateway, the Resource Server at https://gateway.example/ that AgentApp calls.

  • Wiki domain (wiki.example): WikiRAS at https://ras.wiki.example/, an ordinary ID-JAG authorization server in front of WikiAPI at https://api.wiki.example/. It is terminal in this chain.

H0 is the root hop, bound at GatewayRAS; H1 is the wiki hop, which nobody continues.

AgentApp        IdP       GatewayRAS/CAI     ToolGateway     WikiRAS/API
    |            |               |                |               |
    |-ID Token-->|               |                |               |
    |<-ID-JAG H0-|               |                |               |
    |-jwt-bearer: ID-JAG-------->| bind H0        |               |
    |<--access token, H0 claim---|                |               |
    |----------tool call with AT----------------->|               |
    |            |               |<--exchange AT--|               |
    |            |               |-assertion H0-->|               |
    |            |<--assertion + DPoP-------------|               |
    |            |-----------ID-JAG H1----------->|               |
    |            |               |                |-ID-JAG, DPoP->|
    |            |               |                |   (no binding)|
    |            |               |                |<---wiki AT----|
    |            |               |                |-call WikiAPI->|
    |<-------------------result-------------------|               |

B.1.1. Provisioning

The exchanges below presuppose the following configuration. Every item is an ordinary OAuth or ID-JAG registration except the four the profile adds: the IdP's continuation policy, its trust in GatewayRAS as an assertion issuer, its advertisement of identity_continuation_supported, and GatewayRAS's advertisement of the continuation profile.

IdP (Section 5.5.2, Section 9.4, Section 5.1, Section 7.1):

  • Register agent-app and tool-gateway as confidential clients in tenant-123, with canonical actor identities (https://agent.example/, agent-app) and (https://gateway.example/, tool-gateway).

  • Authorize https://gateway.example/ to issue tool-gateway's client credential.

  • Trust GatewayRAS's issuer, https://ras.gateway.example/, and its signing keys to attest its hops. Authorize GatewayRAS and https://gateway.example/ as a CAI and actor identity authority pair for tenant-123.

  • Configure tenant policy to grant agents read access to productivity tools and permit tool-gateway to continue.

  • Advertise identity_continuation_supported and hold tool-gateway's client identifier at WikiRAS, placed in the onward ID-JAG's client_id.

GatewayRAS (Section 7.2, Section 5.4.3):

  • Advertise the continuation grant profile and trust the IdP as ID-JAG issuer.

  • Register tool-gateway as an OAuth client associated with the resource it operates, https://gateway.example/. The CAI uses this association when checking whether it can issue an assertion for a token presented to that resource.

ToolGateway (Section 5.5.2): provision a DPoP key pair and a client-authentication credential issued by https://gateway.example/.

WikiRAS (base profile): register tool-gateway as a client, trust the IdP as ID-JAG issuer, and support the DPoP-bound JWT grant.

ToolGateway authenticates to the IdP with the following [RFC7523] client assertion issued by the gateway domain (Appendix B.1.5). Its earlier exchange at GatewayRAS uses a separate client assertion addressed to GatewayRAS (Appendix B.1.4).

{
  "iss": "https://gateway.example/",
  "sub": "tool-gateway",
  "aud": "https://idp.example/",
  "iat": 1710000230,
  "exp": 1710000290,
  "jti": "tg-cred-01"
}

In this example, iss and sub match ToolGateway's configured canonical actor identity, used in the assertion's act and onward lineage (Section 5.5.2, Section 3.2).

B.1.2. Root Exchange

AgentApp exchanges Alice's ID Token, whose sid anchors the chain to her IdP session (Section 5.1), for an ID-JAG addressed to GatewayRAS, the one audience it knows:

POST /token HTTP/1.1
Host: idp.example
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&requested_token_type=urn:ietf:params:oauth:token-type:id-jag
&audience=https://ras.gateway.example/
&resource=https://gateway.example/
&scope=tools.invoke
&subject_token=<id_token>
&subject_token_type=urn:ietf:params:oauth:token-type:id_token
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=<agent-app JWT>

In this deployment, the chain authorization permits tool-gateway to continue on Alice's behalf with read access to productivity services. The IdP establishes a chain and embeds H0 (Section 5.1).

The authorization uses the tenant's current classification of productivity services. A wiki added to that class can therefore be reached without a new chain, while removing it prevents further continuation to it. That is deployment policy, not a requirement of this profile (Section 5.1.4, Section 9.2).

On the wire (decoded ID-JAG for GatewayRAS):

{
  "iss": "https://idp.example/",
  "aud": "https://ras.gateway.example/",
  "sub": "gateway-pairwise-subject",

  "client_id": "agent-app",
  "resource": "https://gateway.example/",
  "scope": "tools.invoke",

  "auth_time": 1710000200,
  "acr": "urn:example:loa:2",
  "amr": ["pwd", "mfa"],

  "identity_continuation_handle": "Qm7zXu2VtL9pKe4RaW1nHc",

  "iat": 1710000205,
  "exp": 1710000505,
  "jti": "idjag-gateway-01"
}

B.1.3. GatewayRAS Binds H0 and Issues the Access Token

AgentApp redeems the ID-JAG at GatewayRAS with the jwt-bearer grant, exactly as for any ID-JAG, and nothing in this profile asks it to sender-constrain the exchange; GatewayRAS issues a bearer access token here, its own policy choice (Section 5.2):

POST /token HTTP/1.1
Host: ras.gateway.example
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&assertion=<the ID-JAG above>
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=<agent-app JWT>

GatewayRAS advertises the continuation grant profile (Section 7.2) and so recognizes the handle. It binds H0, the issuing IdP, and the tenant it associates with that IdP to the authorization state behind the access token, in the same outcome that issues the token (Section 5.2); the ID-JAG carried no cnf, so there is no key to record.

Server-side state at GatewayRAS:

{
  "identity_continuation_handle": "Qm7zXu2VtL9pKe4RaW1nHc",
  "status": "ACCEPTED",
  "continuation_eligible": true,
  "authorization_state": "gw-authz-7a1e",
  "idp": "https://idp.example/",
  "tenant": "tenant-123",
  "client_id": "agent-app",
  "bound_at": 1710000210
}

GatewayRAS issues the access token as a signed JWT that carries H0 as a claim, the access-token carrier of Section 8.1.

On the wire (decoded access token):

{
  "iss": "https://ras.gateway.example/",
  "aud": "https://gateway.example/",
  "sub": "gateway-pairwise-subject",
  "client_id": "agent-app",
  "scope": "tools.invoke",
  "identity_continuation_handle": "Qm7zXu2VtL9pKe4RaW1nHc",
  "iat": 1710000210,
  "exp": 1710000810,
  "jti": "at-gw-0001"
}

AgentApp calls the gateway with this token. It chooses which token to present, and with it which authorization, but cannot alter the handle inside the token. A RAS that sender-constrains its tokens closes the bearer-ingress exposure of Section 9.1; Appendix B.2 shows that variant.

B.1.4. ToolGateway Obtains the Assertion

ToolGateway validates the access token as any resource server would. Resolving the tool call, it selects the wiki as the upstream. To continue Alice's chain there it needs an Identity Continuation Assertion, which it obtains by exchanging the access token it just received at GatewayRAS's token endpoint, authenticating as the OAuth client tool-gateway and proving its own key (Section 5.4.1):

POST /token HTTP/1.1
Host: ras.gateway.example
Content-Type: application/x-www-form-urlencoded
DPoP: <proof signed by the tool-gateway key>

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&requested_token_type=urn:ietf:params:oauth:token-type:identity-continuation
&subject_token=<the access token above>
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=<tool-gateway JWT>

The DPoP proof on this request proves the tool-gateway key, which GatewayRAS places in the assertion's cnf; had the access token been sender-constrained, its own cnf would not be matched against this proof (Section 9.1).

GatewayRAS confirms the token is its own, unexpired, and addressed to https://gateway.example/, the resource tool-gateway is registered to operate. It reads H0 from the token, rechecks that the authorization remains active and that its binding still records it as eligible for continuation, then issues the assertion bound to the proven key (Section 5.4.3).

On the wire (issuance response):

{
  "issued_token_type": "urn:ietf:params:oauth:token-type:identity-continuation",
  "access_token": "<the assertion below, compact JWS>",
  "token_type": "N_A",
  "identity_continuation_authorization_server": "https://idp.example/",
  "expires_in": 120
}

The identity_continuation_authorization_server identifies the IdP from which ToolGateway obtains the next ID-JAG.

On the wire (decoded assertion):

{
  "iss": "https://ras.gateway.example/",
  "aud": "https://idp.example/",
  "identity_continuation_handle": "Qm7zXu2VtL9pKe4RaW1nHc",

  "act": {
    "iss": "https://gateway.example/",
    "sub": "tool-gateway"
  },

  "cnf": {
    "jkt": "base64url-tool-gateway-key-thumbprint"
  },

  "iat": 1710000230,
  "exp": 1710000350,
  "jti": "n3Vt7Jq2Xd5PbR9wLc1eKs"
}

B.1.5. ToolGateway Continues to WikiRAS

ToolGateway resolves the token endpoint of https://idp.example/, the identity_continuation_authorization_server it was given, using Section 5.4.4, and presents the assertion there as the subject_token of a continuation exchange, with client authentication and a DPoP proof of the assertion's cnf key, requesting an ID-JAG for WikiRAS. The IdP maps the registered client tool-gateway to its canonical actor identity (Section 5.5.2):

POST /token HTTP/1.1
Host: idp.example
Content-Type: application/x-www-form-urlencoded
DPoP: <proof signed by the tool-gateway key>

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&requested_token_type=urn:ietf:params:oauth:token-type:id-jag
&audience=https://ras.wiki.example/
&resource=https://api.wiki.example/
&scope=wiki.read
&subject_token=<identity-continuation-assertion>
&subject_token_type=urn:ietf:params:oauth:token-type:identity-continuation
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=<tool-gateway client assertion>

The IdP validates the exchange (Section 5.5.3):

  • Issuer trust: the assertion is signed by GatewayRAS, the RAS recorded for H0's hop, which that rule accepts directly.

  • Chain state: H0 names an accepted hop on an active chain.

  • Current actor and binding: the act claim names tool-gateway, the authenticated client, and the DPoP proof matches cnf.

  • Authorization: the chain authorization permits tool-gateway to obtain wiki.read for Alice, and current policy classifies the wiki as an eligible productivity service. The root tools.invoke scope does not independently authorize this access.

The IdP resolves Alice's wiki subject and issues the ID-JAG with H1 and tool-gateway atop agent-app in the lineage.

On the wire (decoded ID-JAG for WikiRAS):

{
  "iss": "https://idp.example/",
  "aud": "https://ras.wiki.example/",
  "sub": "wiki-pairwise-subject",

  "client_id": "tool-gateway",
  "resource": "https://api.wiki.example/",
  "scope": "wiki.read",

  "auth_time": 1710000200,
  "acr": "urn:example:loa:2",
  "amr": ["pwd", "mfa"],

  "identity_continuation_handle": "Zp3kRt8VbN2wLq6YsD4mXe",

  "act": {
    "iss": "https://gateway.example/",
    "sub": "tool-gateway",
    "act": {
      "iss": "https://agent.example/",
      "sub": "agent-app"
    }
  },

  "cnf": {
    "jkt": "base64url-tool-gateway-key-thumbprint"
  },

  "iat": 1710000235,
  "exp": 1710000535,
  "jti": "idjag-wiki-01"
}

A target not permitted by the chain authorization and current policy fails with invalid_target; the chain stays continuable and only that tool call fails (Section 5.5.6). Appendix B.3.4 illustrates a grant that excludes a newly requested target.

B.1.6. WikiRAS Redeems an Ordinary ID-JAG

ToolGateway redeems the ID-JAG at WikiRAS with the DPoP-bound JWT grant and a DPoP proof of the same key (Section 5.5.5). WikiRAS follows the base profile: it validates the ID-JAG, ignores the handle, and issues an access token without binding H1 (Section 5.2). ToolGateway calls WikiAPI as Alice's wiki subject and returns the result to AgentApp.

Further calls to WikiAPI for Alice reuse this access token while it remains valid and covers the requested access (Section 8). Access to another upstream repeats Appendix B.1.4 and creates a sibling hop under H0 (H2, and so on).

B.1.7. What a Gateway Implements

The gateway domain adds two things to an ordinary OAuth deployment:

  • GatewayRAS binds the handle when it redeems a continuation-capable ID-JAG, records whether the authorization is eligible for continuation, advertises the continuation grant profile alongside the base grants, places the handle in the access token, and issues assertions from its token endpoint (Section 5.2, Section 5.4, Section 7.2).

  • tool-gateway exchanges the access token it received for an assertion, then presents that assertion once (Section 5.5.7), with its client credential and a DPoP proof, to the IdP for the next ID-JAG.

Both presuppose registrations that ID-JAG already requires: tool-gateway is an OAuth client of the IdP, holding a client-authentication credential and the key its DPoP proofs use, and a client known to WikiRAS, which the onward ID-JAG names as client_id (Section 5.5).

AgentApp and WikiRAS use the base profile unchanged. AgentApp proves no key anywhere and never shares Alice's identity assertion with the gateway. The IdP establishes the chain and evaluates each continuation (Section 5.1, Section 5.5).

B.2. SaaS Chain Example (Separate CAI and Transaction Token Carrier)

A user's request crosses three SaaS domains: ExpenseApp calls ExpenseAPI, whose workload calls TravelAPI, whose workload calls BookingAPI. Each domain has its own Resource Authorization Server, and all trust one enterprise IdP at https://idp.example/. Appendix B.2.6 lists what differs from the gateway example.

Topology: separate CAI with a Transaction Token carrier.

  • Expense domain (expenses.example): client expense-app; ExpenseRAS, Expense Transaction Token Service (TTS), and Expense CAI at ras., tts., and cai.expenses.example; and the workload expense-service behind ExpenseAPI.

  • Travel domain (travel.example): TravelRAS, Travel TTS, and Travel CAI, and the workload travel-service behind TravelAPI.

  • Booking domain (booking.example): BookingRAS in front of BookingAPI. It runs the base ID-JAG profile and is terminal in this chain.

Each domain is the identity authority for its own workloads, so the IdP has the canonical actor identities (https://expenses.example/, expense-app), (https://expenses.example/, expense-service), and (https://travel.example/, travel-service) recorded for these clients, the values their act entries carry (Section 5.5.2).

The user has a pairwise subject at each RAS, which only the IdP can map. H0 is bound at ExpenseRAS, H1 at TravelRAS; H2 reaches BookingRAS, which never binds it.

Hop 0 roots the chain at ExpenseRAS and carries H0 to the workload:

ExpenseApp       IdP        ExpenseRAS      Expense TTS  ExpenseService
     |            |              |               |              |
     |-ID Token-->|              |               |              |
     |<-ID-JAG H0-|              |               |              |
     |-jwt-bearer: ID-JAG, DPoP->| bind H0       |              |
     |<-----------AT1------------|               |              |
     |---------------call ExpenseAPI: AT1 + DPoP--------------->|
     |            |              |               |<-----AT1-----|
     |            |              |<-resolve AT1--|              |
     |            |              |---bound H0--->|              |
     |            |              |               |-TT with H0-->|

Hop 1 continues to TravelRAS; hop 2 repeats it from Travel to Booking:

ExpenseService    Expense CAI     IdP       TravelRAS  Travel TTS/API
       |               |           |            |             |
       |-exchange TT-->|           |            |             |
       |<--assertion---|           |            |             |
       |--assertion, actor, DPoP-->|            |             |
       |<--------ID-JAG H1---------|            |             |
       |-------jwt-dpop: ID-JAG + DPoP--------->| bind H1     |
       |<------------------AT2------------------|             |
       |-------------call TravelAPI: AT2 + DPoP-------------->|
       |               |           |            | TT with H1 to workload

B.2.1. Root Exchange (H0 at ExpenseRAS)

ExpenseApp exchanges the user's ID Token, whose sid anchors the chain to the IdP session, for an ID-JAG addressed to ExpenseRAS:

POST /token HTTP/1.1
Host: idp.example
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&requested_token_type=urn:ietf:params:oauth:token-type:id-jag
&audience=https://ras.expenses.example/
&resource=https://api.expenses.example/
&scope=expenses.read
&subject_token=<id_token>
&subject_token_type=urn:ietf:params:oauth:token-type:id_token
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=<expense-app JWT>

In this deployment, the chain authorization permits designated workloads to continue to Expense, Travel, and Booking. Current enterprise policy also permits that access (Section 5.1.4).

Server-side state (IdP authorization, illustrative):

(https://ras.expenses.example/, https://api.expenses.example/)
    permitted scopes: expenses.read

(https://ras.travel.example/, https://api.travel.example/)
    permitted scopes: trips.read

(https://ras.booking.example/, https://api.booking.example/)
    permitted scopes: stays.book

The IdP creates the root hop H0 and embeds it in the ID-JAG (Section 4).

On the wire (decoded ID-JAG):

{
  "iss": "https://idp.example/",
  "aud": "https://ras.expenses.example/",
  "sub": "expense-pairwise-subject",

  "client_id": "expense-app",
  "resource": "https://api.expenses.example/",
  "scope": "expenses.read",

  "auth_time": 1710000000,
  "acr": "urn:example:loa:2",
  "amr": ["pwd", "mfa"],

  "identity_continuation_handle": "kW4uJ8pTe2NxA6rQvD1zYs",

  "iat": 1710000005,
  "exp": 1710000305,
  "jti": "idjag-expense-01"
}

B.2.2. ExpenseRAS Binds H0; Expense TTS Carries It

ExpenseApp redeems the ID-JAG at ExpenseRAS for an access token, AT1, and ExpenseRAS binds H0, the issuing IdP, and the tenant it associates with that IdP to the authorization state behind AT1, and records that authorization as eligible for continuation (Section 5.2). The carrier is what differs: the handle stays in this record, and AT1 does not carry it.

Server-side state at ExpenseRAS:

{
  "identity_continuation_handle": "kW4uJ8pTe2NxA6rQvD1zYs",
  "status": "ACCEPTED",
  "continuation_eligible": true,
  "authorization_state": "at1-authz-2f9c",
  "idp": "https://idp.example/",
  "tenant": "tenant-123",
  "client_id": "expense-app",
  "bound_at": 1710000010
}

ExpenseApp calls ExpenseAPI with AT1. The Expense TTS resolves AT1 against that record over its own-domain interface with ExpenseRAS, derives H0, and issues a Transaction Token for expense-service, the workload that completes the request (Section 5.3). The token's req_wl names expense-api, which requested the Transaction Token; expense-service is the workload assigned to continue the transaction. The TTS records the assignment to that workload in authenticated routing state, the domain's own record of which workload handles a transaction. Neither ExpenseApp nor expense-service supplies H0.

Intra-domain context (decoded Transaction Token):

{
  "iss": "https://tts.expenses.example/",
  "aud": "https://expenses.example/",
  "sub": "expense-pairwise-subject",
  "txn": "txn-expense-88f2",
  "scope": "expense-report:complete",
  "req_wl": "expense-api",

  "tctx": {
    "identity_continuation": {
      "iss": "https://idp.example/",
      "tenant": "tenant-123",
      "handle": "kW4uJ8pTe2NxA6rQvD1zYs"
    }
  },

  "iat": 1710000012,
  "exp": 1710000072,
  "jti": "tt-expense-0007"
}

The Transaction Token stays inside expenses.example. The tctx.identity_continuation encoding is illustrative; the profile standardizes no carrier schema.

B.2.3. ExpenseService Obtains the Assertion

expense-service presents the Transaction Token as the subject_token at Expense CAI's token endpoint, authenticating as a client and proving its own key (Section 5.4.1):

POST /token HTTP/1.1
Host: cai.expenses.example
Content-Type: application/x-www-form-urlencoded
DPoP: <proof signed by the expense-service key>

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&requested_token_type=urn:ietf:params:oauth:token-type:identity-continuation
&subject_token=<the Transaction Token above>
&subject_token_type=urn:ietf:params:oauth:token-type:txn_token
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=<expense-service JWT>

Expense CAI verifies the Transaction Token and reads H0. It checks the routing state that assigns this transaction to expense-service; the domain audience and req_wl alone do not establish that assignment. It rechecks with ExpenseRAS that H0's authorization remains active and is eligible for continuation, then issues the assertion bound to the proven key (Section 5.4.3).

The IdP accepts its assertions for hops ExpenseRAS accepts because it trusts Expense CAI for that RAS from tenant configuration at the IdP; the rest of the conjunctive trust rule applies as it does to a co-located RAS (Section 7.3, Section 9.4).

On the wire (decoded assertion):

{
  "iss": "https://cai.expenses.example/",
  "aud": "https://idp.example/",
  "identity_continuation_handle": "kW4uJ8pTe2NxA6rQvD1zYs",

  "act": {
    "iss": "https://expenses.example/",
    "sub": "expense-service"
  },

  "cnf": {
    "jkt": "base64url-expense-service-key-thumbprint"
  },

  "iat": 1710000020,
  "exp": 1710000200,
  "jti": "b8Rn5Yx1Qe4Nk2Wf6zVc9d"
}

B.2.4. Continuation to TravelRAS (H1)

expense-service presents the assertion to the IdP with an [RFC7523] client assertion and a DPoP proof of the continuation assertion's cnf key, requesting an ID-JAG for TravelRAS. The IdP maps the authenticated client to its canonical actor identity (Section 5.5.2):

POST /token HTTP/1.1
Host: idp.example
Content-Type: application/x-www-form-urlencoded
DPoP: <proof signed by the expense-service key>

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&requested_token_type=urn:ietf:params:oauth:token-type:id-jag
&audience=https://ras.travel.example/
&resource=https://api.travel.example/
&scope=trips.read
&subject_token=<identity-continuation-assertion>
&subject_token_type=urn:ietf:params:oauth:token-type:identity-continuation
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=<expense-service client assertion>

The IdP validates the exchange (Section 5.5.3):

  • Issuer trust: Expense CAI is trusted for ExpenseRAS, the RAS recorded for H0, rather than being that RAS itself.

  • Chain state: H0 names an accepted hop on an active chain.

  • Current actor and binding: act names expense-service, the authenticated client, and the DPoP proof matches cnf.

  • Authorization: TravelRAS, TravelAPI, and trips.read are permitted by the chain authorization and current policy.

The IdP never calls ExpenseRAS; the assertion is its evidence of acceptance (Section 5.2.1). It resolves the user's Travel subject, creates H1 as a child of H0, and places expense-service atop the root actor expense-app in the lineage (Section 5.5.5).

On the wire (decoded ID-JAG):

{
  "iss": "https://idp.example/",
  "aud": "https://ras.travel.example/",
  "sub": "travel-pairwise-subject",

  "client_id": "expense-service",
  "resource": "https://api.travel.example/",
  "scope": "trips.read",

  "auth_time": 1710000000,
  "acr": "urn:example:loa:2",
  "amr": ["pwd", "mfa"],

  "identity_continuation_handle": "Uc9fB3mHs5LdK7gEnX2wRj",

  "act": {
    "iss": "https://expenses.example/",
    "sub": "expense-service",
    "act": {
      "iss": "https://expenses.example/",
      "sub": "expense-app"
    }
  },

  "cnf": {
    "jkt": "base64url-expense-service-key-thumbprint"
  },

  "iat": 1710000025,
  "exp": 1710000325,
  "jti": "idjag-travel-01"
}

B.2.5. The Pattern Repeats to BookingRAS (H2)

expense-service redeems the ID-JAG at TravelRAS for AT2, and TravelRAS binds H1 exactly as ExpenseRAS bound H0. The Travel TTS derives H1 into a Transaction Token for travel-service. Within the illustrated tctx.identity_continuation object, only the handle changes:

Intra-domain context (excerpt):

"tctx": {
  "identity_continuation": {
    "iss": "https://idp.example/",
    "tenant": "tenant-123",
    "handle": "Uc9fB3mHs5LdK7gEnX2wRj"
  }
}

travel-service obtains an assertion for H1 from Travel CAI and exchanges it for an ID-JAG with audience=https://ras.booking.example/, resource=https://api.booking.example/, and scope=stays.book, all permitted by the chain authorization and current policy. It authenticates with its own client assertion and proves the key in the continuation assertion's cnf. The IdP resolves its canonical actor identity (Section 5.5.2), creates H2 under H1, and extends the lineage:

On the wire (selected claims from the decoded ID-JAG):

{
  "aud": "https://ras.booking.example/",
  "sub": "booking-pairwise-subject",
  "client_id": "travel-service",
  "resource": "https://api.booking.example/",
  "scope": "stays.book",
  "identity_continuation_handle": "Ht6mZ2pQe8VrKx4NcWy1Jd",
  "act": {
    "iss": "https://travel.example/",
    "sub": "travel-service",
    "act": {
      "iss": "https://expenses.example/",
      "sub": "expense-service",
      "act": {
        "iss": "https://expenses.example/",
        "sub": "expense-app"
      }
    }
  }
}

BookingRAS is terminal: it redeems the ID-JAG under the base profile, ignores H2, issues AT3, and binds nothing (Section 5.2). travel-service calls BookingAPI with AT3.

B.2.6. What Differs from the Gateway Example

  • The CAI is a separate service in each continuing domain, which the IdP trusts for that domain's RAS from tenant configuration (Section 7.3); a co-located RAS needs no such record, though the same conjunctive trust applies to both (Section 9.4).

  • The handle never enters an access token; a Transaction Token Service derives it from the RAS binding for each request, and the workload presents that token to obtain the assertion.

  • Two continuing domains produce a three-entry lineage: two continuation actors and the root actor.

  • ExpenseRAS chooses to sender-constrain the root access token, so ExpenseApp presents DPoP proofs at the RAS and on its API call; that is RAS policy under the base profile. The gateway example uses a bearer root access token.

B.3. Background Agent Example (Scheduled Continuation)

Alice configures a daily calendar briefing that runs without her presence. The chain is anchored to a grant rather than a session (Appendix B.3.5). This example also shows rejection of a target excluded by the grant but permitted by tenant policy.

Topology: separate CAI with a Transaction Token carrier.

  • Platform domain (platform.example): workload briefing-agent; PlatformRAS, Platform TTS, and Platform CAI in front of TaskAPI; and the Scheduler, an internal component that holds only the task identifier and triggers each run.

  • Calendar domain (calendar.example): CalendarRAS in front of CalendarAPI. It is terminal in every run.

  • Mail domain (mail.example): MailRAS in front of MailAPI, reached only in Appendix B.3.4; likewise terminal.

The platform domain is the identity authority for briefing-agent, so the IdP has the canonical actor identity (https://platform.example/, briefing-agent) recorded for that client, the value its act entry carries (Section 5.5.2).

H0 is bound at PlatformRAS to the task authorization and outlives Alice's session; each run receives a fresh child of H0 for its terminal target.

B.3.1. Setup: Anchoring the Chain to a Grant

Alice authorizes "summarize my calendar every morning." Because the task must outlive her session, briefing-agent presents a refresh token from a grant that permits continuation as the root exchange's subject token, so the chain is anchored to that grant rather than to her session (Section 5.1, Section 6). In this deployment, the grant permits only the Platform and Calendar access needed for the task, and current policy permits that access. The root ID-JAG targets PlatformRAS.

Server-side state (IdP grant authorization, illustrative):

(https://ras.platform.example/, https://api.platform.example/tasks)
    permitted scopes: task.manage

(https://ras.calendar.example/, https://api.calendar.example/)
    permitted scopes: calendar.read

The exchange and RAS binding follow the pattern of Appendix B.2.1 and Appendix B.2.2. PlatformRAS binds H0 to a durable task authorization that it keys by its own task identifier; the record holds no bearer credential.

Server-side state (PlatformRAS task authorization):

task_id:                      task-123
owner:                        alice
actor:                        briefing-agent
identity_continuation_handle: Pz6vTq1NcY4kM8bJf3RxWa  # H0
permitted_purpose:            morning-calendar-brief
schedule:                     "0 7 * * *"
governing_grant:              grant-8f2c19a4  # internal reference
expiry:                       1719450000  # local, not IdP lifetime
status:                       active
continuation_eligible:        true

Server-side state (Scheduler):

task_id: task-123

The Scheduler never receives H0 or any user, chain, or bearer credential; task-123 identifies a row in PlatformRAS's own state and means nothing outside the platform.

B.3.2. Each Run: Deriving H0 from Task State

Each run begins with no user present, so H0 comes from state the platform holds:

 Scheduler   BriefingAgent      Platform TTS
     |              |                 |
     |---trigger--->|                 | task-123
     |              |-task-123+proof->|
     |              |                 | verify proof + task; derive H0
     |              |<-fresh TT(H0)---|

The task identifier is not a secret and does not authorize a run. The Scheduler's trigger authenticates and carries only task-123; BriefingAgent authenticates to the Platform TTS and proves possession of its key; and the TTS, after confirming that task-123 is active and that BriefingAgent is its designated actor, derives H0 into a fresh Transaction Token (Section 5.3). Neither the Scheduler nor BriefingAgent selects H0.

B.3.3. Each Run: Continuing to CalendarRAS

Each run performs assertion issuance, continuation exchange, and ID-JAG redemption:

 BriefingAgent    Platform CAI       IdP         CalendarRAS
       |               |             |               |
       |--exchange TT->|             |               |
       |<-assertion----|             |               |
       |---------------------------->|               |
       |      assertion + DPoP       |               |
       |<----------------------------| ID-JAG(child) |
       |-------------------------------------------->|
       |                 ID-JAG                      |
       |<--------------------------------------------| access token
       |               |             |      no binding (terminal)

BriefingAgent exchanges the Transaction Token at Platform CAI's token endpoint and presents the assertion to the IdP the response's identity_continuation_authorization_server names, with its client credential and a DPoP proof. Platform CAI applies Section 5.4.3 to durable task state rather than to a live user's request: it authenticates briefing-agent, verifies its key and transaction, and rechecks that PlatformRAS's H0 authorization remains active.

The assertion and onward ID-JAG use the formats shown in Appendix B.2.3 and Appendix B.2.4, with Platform CAI as the assertion issuer. briefing-agent is both the root actor and the current actor here, so the onward act merges them into one entry (Section 5.5.5). CalendarRAS is terminal and issues the access token without binding the child hop. Each run's child is a sibling, not a descendant, of the previous run's child.

B.3.4. A Newly Requested Target

Suppose the platform later extends the briefing to include unread mail, which requires https://api.mail.example/ behind https://ras.mail.example/. Alice's grant authorizes only Platform and Calendar access, so the IdP rejects a continuation from H0 to MailRAS. A general tenant policy allowing mail access does not by itself expand that grant (Section 5.5.3).

HTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
  "error": "invalid_target"
}

A different chain authorization could permit read access to productivity services selected by current policy, as in Appendix B.1.2. Under that authorization, adding Mail to the eligible services could permit mail.read without a new chain. A request for mail.send still fails with invalid_scope if that authorization or current policy excludes it. These outcomes follow the deployment's authorization semantics, not how the IdP stores the authorization. A target-specific failure leaves the chain continuable for other authorized targets.

B.3.5. What Differs from the SaaS Chain Example

  • The root subject token is a refresh token, so the chain anchors to a grant and survives logout; grant-anchor support is optional (Section 6.1).

  • H0 is bound to a durable task authorization that PlatformRAS keys by task identifier; the Scheduler holds only that identifier, which is not a secret and authorizes nothing.

  • Every run derives H0 afresh from active task state and obtains a new assertion. Stealing the task record exposes H0 but not the agent key, and continuation still requires a fresh assertion while the authorization is active.

  • Each run creates a sibling child of H0 rather than a descendant of the previous run's child.

This example uses a user-present setup event. More generally, chain establishment requires an authorized root exchange whose subject token resolves to an active user session or supported grant anchor (Section 5.1, Section 6.1). Administrative policy alone, without such an anchor, cannot establish a chain.

Appendix C. Open Items for Working Group Discussion

This non-normative appendix identifies questions for Working Group review.

[[ To be removed before publication as an RFC ]]

  1. Acceptance attestation. Could a recipient-bound design, in which the IdP binds a continuation credential to an intended actor, actor class, trust domain, or key, or a target-resolved design replace the CAI assertion while still supplying evidence of RAS acceptance and of the actor's association with that context, which today only a party in the RAS's domain can provide (Appendix A.2)?

  2. Sender constraint. Should mutual-TLS confirmation be defined jointly with ID-JAG? Should the assertion and ID-JAG permit different proven keys, and how should supported methods be advertised (Section 5.5.2)?

  3. Client establishment control. Should root clients be able to require or suppress chain establishment (Section 5.1)? The authors' current position is that establishment remains a tenant policy decision, so that existing clients need no change to participate in a chain.

  4. Stateless handles. Can self-verifying handles preserve ancestry and subtree revocation within the recommended size bound, and at what privacy and operational cost (Section 4, Section 5.5.5)?

  5. Idempotent recovery. Should optional support be discoverable, and if so should an IdP advertise that it offers recovery, the retry window, or both (Section 5.5.7.1)?

  6. Limits. The document recommends that an assertion's lifetime not exceed 300 seconds, recommends that IdPs accept lifetimes of up to 300 seconds and leaves the maximum to deployment, and requires a finite hop-count limit without fixing a default (Section 3.2, Section 6.3). Should the 300-second recommendations become requirements, should the profile fix a hop-count default, and should the accepted maximum be advertised in metadata?

The project issue tracker also records WG questions on authorization bounds (#106), acceptance freshness (#107), actor identity evidence (#108), CAI discovery (#109), bearer ingress (#110), and acceptance accountability (#41): https://github.com/mcguinness/draft-mcguinness-oauth-id-continuation-assertion/issues

Further extension topics include client-requested limits or permitted actors, intra-domain actor lineage and audit ([I-D.mcguinness-oauth-actor-receipts], [I-D.mcguinness-oauth-actor-proofs]), non-user roots, and RAS-derived narrowing (Section 5.2.1).

Acknowledgments

The authors thank the Working Group participants who developed the OAuth Identity and Authorization Chaining Across Domains and the Identity Assertion JWT Authorization Grant specifications, on whose work this profile builds.

Document History

[[ To be removed before publication as an RFC ]]

-02

-01

-00

Authors' Addresses

Karl McGuinness
Independent
Aaron Parecki
Okta