<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     docName="draft-lundholm-kaif-00"
     category="std"
     ipr="trust200902"
     submissionType="IETF"
     consensus="true"
     tocInclude="true"
     sortRefs="true"
     symRefs="true"
     version="3">
<front>
<title abbrev="KAIF">The Kindred Agent Identity Framework (KAIF)</title>
<seriesInfo name="Internet-Draft" value="draft-lundholm-kaif-00"/>
<author fullname="Geoffrey Lundholm" initials="G." surname="Lundholm">
<organization>Kindred Systems</organization>
<address><postal><city>London</city><country>United Kingdom</country></postal>
<email>kindred@kindredsystems.ai</email></address>
</author>
<date year="2026"/>
<area>Security</area>
<keyword>OAuth</keyword>
<keyword>token exchange</keyword>
<keyword>SPIFFE</keyword>
<keyword>workload identity</keyword>
<keyword>delegation</keyword>
<abstract>
<t>The Kindred Agent Identity Framework (KAIF) is an OAuth 2.0 token exchange mechanism for delegated agent-to-service authorization, combining RFC 8693 token exchange with SPIFFE workload identity attestation and operator-assigned authorization tiers.</t>
<t>This document specifies the protocol mechanics, deployment profiles, and interoperability requirements for systems implementing agent authorization with audit accountability. KAIF is intended for scenarios in which an operator (human principal) provisionally authorizes an agent (automated workload) to perform bounded actions on their behalf, with cryptographic proof of authorization, delegation depth tracking, and revocation in real time.</t>
<t>This document is intentionally vendor-neutral in its normative requirements. Cloud platforms, model providers, workflow systems, and audit backends discussed by implementations are informative deployment examples, not part of the KAIF wire protocol.</t>
</abstract>
</front>
<middle>
<section anchor="introduction"><name>Introduction</name>
<section anchor="problem-statement"><name>Problem Statement</name>
<t>Contemporary system architectures increasingly rely on autonomous agents, both AI-driven and workflow-based, to execute actions on behalf of human operators in complex distributed environments. Current authorization models present several challenges:</t>
<ol>
<li><strong>Coarse-grained control</strong>: Traditional API keys or static tokens provide no granularity on what actions an agent may perform.</li>
<li><strong>Limited auditability</strong>: It is difficult to correlate which agent executed which action, especially in delegated scenarios.</li>
<li><strong>Revocation latency</strong>: Certificate-based models suffer from multi-minute revocation propagation delays.</li>
<li><strong>Workload identity opacity</strong>: There is no standardized way for an authorization service to verify which workload is requesting access.</li>
</ol>
<t>KAIF addresses these challenges by combining three existing standards and practices:</t>
<ul>
<li><strong>RFC 8693</strong>: OAuth 2.0 Token Exchange <xref target="RFC8693"/> for subject-actor separation</li>
<li><strong>SPIFFE/SPIRE</strong> <xref target="SPIFFE"/> <xref target="SPIRE"/>: Cryptographic workload identity and JWT-SVID attestation</li>
<li><strong>Operator-assigned authorization tiers</strong>: A flexible authorization model that avoids hard-coded trust assumptions</li>
</ul>
</section>
<section anchor="scope-and-intended-deployment"><name>Scope and Intended Deployment</name>
<t>KAIF is intended for operator-initiated, agent-executed, boundary-crossing transactions. A "boundary-crossing transaction" is any action where:</t>
<ul>
<li>The agent is acting on behalf of a human principal (operator)</li>
<li>The action modifies state in an external system (payment, API mutation, purchase)</li>
<li>Regulatory, financial, or security audit requirements require proof of authorization</li>
</ul>
<t>The following are out of scope for v1.0:</t>
<ul>
<li>Behavioral trust scoring (agent action pattern analysis)</li>
<li>Peer reputation models</li>
<li>Long-running streaming delegations</li>
<li>Cross-operator federation (see v2.0 roadmap)</li>
</ul>
</section>
<section anchor="conventions-and-terminology"><name>Conventions and Terminology</name>
<t>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 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they appear in all capitals, as shown here.</t>
<t><strong>KAIF-specific terms:</strong></t>
<ul>
<li><strong>Operator</strong>: A human principal (person) who authorizes an agent to act on their behalf.</li>
<li><strong>Agent</strong>: An automated workload (software) with a SPIFFE identity that executes actions on behalf of an operator.</li>
<li><strong>Boundary Crossing</strong>: An action that crosses a trust boundary--e.g., calling an external API, initiating a payment, or writing to a regulated log.</li>
<li><strong>Authorization Tier</strong>: An operator-assigned permission level (PROVISIONAL, STANDARD, VERIFIED, TRUSTED) that determines token TTL and delegation depth.</li>
<li><strong>Delegation Depth</strong>: The count of intermediate agents in a delegation chain (depth 0 = direct operator-&gt;agent, depth 1 = operator-&gt;agent1-&gt;agent2).</li>
<li><strong>Revocation</strong>: Immediate invalidation of a token via JTI (JWT ID) denylist.</li>
<li><strong>Relying Party</strong>: A third-party service that validates KAIF tokens without running a KAIF server instance.</li>
</ul>
</section>
<section anchor="implementation-status-informative"><name>Implementation Status (Informative)</name>
<t>KAIF has been validated in at least one concrete multi-system deployment as an implementation-backed protocol design. That deployment demonstrated, end to end:</t>
<ul>
<li>operator-originated delegation grant issuance</li>
<li>workload identity presentation during token exchange</li>
<li>audience-bound authorization for a third-party execution surface</li>
<li>receipt correlation back to the originating workflow</li>
<li>workflow resumption after external completion</li>
</ul>
<t>This evidence indicates that the KAIF handshake is viable across a real external boundary. It does not make any specific cloud, AI provider, queue, workflow runtime, or datastore normative for interoperability. Independent implementations remain necessary to establish broader interoperability confidence.</t>
</section>
<section anchor="terminology-stability"><name>Terminology Stability</name>
<t>The protocol wire format in this document uses <tt>authorization_tier</tt> and <tt>authorization_tier_value</tt> as the canonical delegation strength fields.</t>
<t>Implementations <bcp14>MAY</bcp14> use local internal terms such as <tt>trust_tier</tt>, <tt>trust_score</tt>, or similar, but those names are deployment-specific and are not normative protocol vocabulary unless explicitly mapped to the KAIF claims defined here.</t>
</section>
</section>
<section anchor="protocol-overview"><name>Protocol Overview</name>
<section anchor="three-party-flow"><name>Three-Party Flow</name>
<artwork><![CDATA[
+------------+
|  Operator  | (human, OIDC-authenticated)
| (John@co)  |
+------+-----+
       |
       | 1. Provision delegation grant
       | (OIDC id_token -> delegation JWT)
       v
+----------------------+
|   KAIF Server        |
|   (Authorization     |
|    Authority)        |
+---------------------++
       ^               |
       |               | 2. Token Exchange (RFC 8693)
       |               | (delegation JWT + SVID -> access token)
       |               v
       |         +--------------+
       |         |   Agent      |
       |         |  (SPIFFE     |
       |         |   identity)  |
       |         +------+-------+
       |                |
       |                | 3. Use token at relying party
       |                |
       |                v
       |         +--------------+
       |         | Relying      |
       |         | Party        |
       +---------| (e.g.,       |
                 |  Payment API)|
                 +--------------+
]]></artwork>
</section>
<section anchor="delegation-grant-subject-token"><name>Delegation Grant (Subject Token)</name>
<t>An operator provisions a delegation grant, a signed JWT that authorizes an agent to request access tokens. A grant issued by the KAIF server contains:</t>
<sourcecode type="json"><![CDATA[
{
  "iss": "https://auth.example.com",
  "sub": "operator@example.com",
  "aud": "spiffe://example.com/agent/lyra",
  "iat": 1719489600,
  "exp": 1719493200,
  "jti": "550e8400-e29b-41d4-a716-446655440000",
  "scope": "invoke:completion vault:read:anthropic_key",
  "delegation_id": "d-550e8400-e29b-41d4-a716-446655440000",
  "may_act": {
    "sub": "spiffe://example.com/agent/lyra"
  }
}
]]></sourcecode>
</section>
<section anchor="token-exchange-request-rfc-8693"><name>Token Exchange Request (RFC 8693)</name>
<t>The agent exchanges the delegation grant (subject_token) and its SPIFFE identity JWT-SVID (actor_token) for an access token:</t>
<sourcecode><![CDATA[
POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token=<delegation-grant-jwt>
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&actor_token=<svid-jwt>
&actor_token_type=urn:ietf:params:oauth:token-type:jwt
&scope=invoke:completion
&audience=urn:example:payment-api
]]></sourcecode>
</section>
<section anchor="kaif-access-token-response"><name>KAIF Access Token (Response)</name>
<t>The server returns a signed JWT that carries operator identity, agent identity, delegation depth, tier, and scope:</t>
<sourcecode type="json"><![CDATA[
{
  "iss": "https://auth.example.com",
  "sub": "operator@example.com",
  "aud": "urn:example:payment-api",
  "iat": 1719489600,
  "exp": 1719493200,
  "jti": "650e8400-e29b-41d4-a716-446655440001",
  "scope": "invoke:completion",
  "actor": {
    "sub": "spiffe://example.com/agent/lyra",
    "svid_thumbprint": "sha256:a1b2c3d4..."
  },
  "may_act": {
    "sub": "spiffe://example.com/agent/lyra"
  },
  "kaif": {
    "authorization_tier": "STANDARD",
    "authorization_tier_value": 0.65,
    "delegation_depth": 0,
    "delegation_id": "d-550e8400-e29b-41d4-a716-446655440000",
    "rollback_window": "PT10M",
    "principal_chain": ["operator@example.com"]
  }
}
]]></sourcecode>
</section>
<section anchor="validation-flow"><name>Validation Flow</name>
<t>When a relying party receives the access token from an agent:</t>
<sourcecode><![CDATA[
Agent -> Relying Party: "Use this token to execute transaction"
        v
        Relying party checks:
        1. Token signature valid against KAIF issuer JWKS ok
        2. Token not expired ok
        3. Token not in revocation denylist (KAIF /introspect) ok
        4. Scope permits requested action ok
        5. Delegation depth within policy ok
        v
        Relying Party: "AUTHORIZED" -> execute transaction
        v
        Relying Party -> KAIF Server: Log receipt/audit event
]]></sourcecode>
</section>
</section>
<section anchor="detailed-protocol-specification"><name>Detailed Protocol Specification</name>
<section anchor="endpoint-post-provision"><name>Endpoint: POST /provision</name>
<t><strong>Purpose</strong>: Operator provisions a delegation grant for an agent.</t>
<t><strong>Request</strong>:</t>
<sourcecode type="json"><![CDATA[
{
  "id_token": "eyJhbGc...",
  "agent_id": "lyra",
  "scope": "invoke:completion vault:read:anthropic_key",
  "ttl_seconds": 600
}
]]></sourcecode>
<t><strong>Validation</strong>:</t>
<ul>
<li><tt>id_token</tt> <bcp14>MUST</bcp14> be a valid OIDC token from configured IdP</li>
<li><tt>agent_id</tt> <bcp14>MUST</bcp14> be registered in operator's ACL</li>
<li><tt>scope</tt> <bcp14>MUST</bcp14> be a subset of agent's permitted scopes</li>
<li><tt>ttl_seconds</tt> <bcp14>MUST</bcp14> be between 60 and 86400</li>
</ul>
<t><strong>Response</strong>:</t>
<sourcecode type="json"><![CDATA[
{
  "delegation_id": "d-550e8400-e29b-41d4-a716-446655440000",
  "delegation_token": "eyJhbGc...",
  "expires_at": 1719493200,
  "agent_id": "lyra",
  "scope": "invoke:completion vault:read:anthropic_key"
}
]]></sourcecode>
<t><strong>Errors</strong>:</t>
<ul>
<li><tt>invalid_request</tt> (400): Missing required fields</li>
<li><tt>invalid_grant</tt> (400): id_token invalid or expired</li>
<li><tt>access_denied</tt> (403): Operator not authorized for agent or scope</li>
</ul>
</section>
<section anchor="endpoint-post-oauth-token"><name>Endpoint: POST /oauth/token</name>
<t><strong>Purpose</strong>: RFC 8693 token exchange for agent-initiated access-token requests.</t>
<t><strong>Request</strong>:</t>
<sourcecode><![CDATA[
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token=<delegation-jwt>
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&actor_token=<svid-jwt>
&actor_token_type=urn:ietf:params:oauth:token-type:jwt
&scope=invoke:completion
&audience=urn:example:payment-api
]]></sourcecode>
<t><strong>Validation steps</strong> (in order):</t>
<ol>
<li><t>Parse and validate subject_token (delegation grant)</t><ul>
<li><bcp14>MUST</bcp14> have valid signature from KAIF issuer</li>
<li><bcp14>MUST NOT</bcp14> be expired (with 10s clock skew tolerance)</li>
<li><bcp14>MUST NOT</bcp14> be in JTI revocation denylist</li>
</ul></li>
<li><t>Parse and validate actor_token (JWT-SVID)</t><ul>
<li><bcp14>MUST</bcp14> have valid signature from SPIRE bundle</li>
<li><bcp14>MUST NOT</bcp14> be expired</li>
<li>SPIFFE ID <bcp14>MUST</bcp14> be registered in ACL</li>
</ul></li>
<li><t>Validate scope</t><ul>
<li><bcp14>MUST</bcp14> be subset of subject_token scope</li>
<li><bcp14>MUST</bcp14> be subset of actor's permitted scopes (ACL)</li>
<li><bcp14>MUST</bcp14> use glob matching (e.g., "vault:read:*" matches "vault:read:key")</li>
</ul></li>
<li><t>Check authorization tier</t><ul>
<li>Fetch the operator-assigned authorization tier (default 0.5 = STANDARD)</li>
<li><bcp14>MUST</bcp14> meet agent's minimum tier requirement</li>
<li>Determine token TTL based on tier</li>
</ul></li>
<li><t>Compute delegation depth</t><ul>
<li>If subject_token is direct provision: depth = 0</li>
<li>If subject_token is access token from prior exchange: depth = subject.kaif.delegation_depth + 1</li>
<li><bcp14>MUST NOT</bcp14> exceed: min(actor ACL depth limit, tier depth limit)</li>
</ul></li>
<li>Mint access token with RS256 signature</li>
</ol>
<t><strong>Response</strong>:</t>
<sourcecode type="json"><![CDATA[
{
  "access_token": "eyJhbGc...",
  "issued_token_type":
    "urn:ietf:params:oauth:token-type:access_token",
  "token_type": "Bearer",
  "expires_in": 600,
  "scope": "invoke:completion"
}
]]></sourcecode>
<t><strong>Errors</strong>:</t>
<ul>
<li><tt>invalid_request</tt> (400): Malformed request</li>
<li><tt>invalid_grant</tt> (400): subject_token invalid/expired/revoked</li>
<li><tt>invalid_scope</tt> (400): Scope not permitted</li>
<li><tt>invalid_client</tt> (401): actor_token invalid</li>
<li><tt>insufficient_trust</tt> (403): Authorization tier below minimum</li>
<li><tt>delegation_depth_exceeded</tt> (403): Depth would exceed limit</li>
</ul>
</section>
<section anchor="endpoint-post-introspect"><name>Endpoint: POST /introspect</name>
<t><strong>Purpose</strong>: RFC 7662 <xref target="RFC7662"/> token introspection for relying parties that verify tokens in real time.</t>
<t><strong>Request</strong>:</t>
<sourcecode type="json"><![CDATA[
{
  "token": "eyJhbGc..."
}
]]></sourcecode>
<t><strong>Response</strong> (if active):</t>
<sourcecode type="json"><![CDATA[
{
  "active": true,
  "sub": "operator@example.com",
  "aud": "urn:example:payment-api",
  "iat": 1719489600,
  "exp": 1719493200,
  "scope": "invoke:completion",
  "actor": {
    "sub": "spiffe://example.com/agent/lyra"
  },
  "kaif": {
    "authorization_tier": "STANDARD",
    "delegation_depth": 0
  }
}
]]></sourcecode>
<t><strong>Response</strong> (if revoked or invalid):</t>
<sourcecode type="json"><![CDATA[
{
  "active": false
}
]]></sourcecode>
</section>
<section anchor="endpoint-post-revoke"><name>Endpoint: POST /revoke</name>
<t><strong>Purpose</strong>: Operator revokes a token.</t>
<t><strong>Request</strong>:</t>
<sourcecode type="json"><![CDATA[
{
  "token": "eyJhbGc...",
  "reason": "operator_request"
}
]]></sourcecode>
<t><strong>Response</strong>:</t>
<sourcecode type="json"><![CDATA[
{
  "revoked": true,
  "jti": "650e8400-e29b-41d4-a716-446655440001"
}
]]></sourcecode>
<t><strong>Mechanics</strong>:</t>
<ul>
<li>Extract JTI from token</li>
<li>Add to Redis denylist with TTL = token.exp</li>
<li>Publish to revocation channel for multi-instance sync</li>
<li>Write audit entry</li>
</ul>
</section>
<section anchor="endpoint-get-well-known-jwks-json"><name>Endpoint: GET /.well-known/jwks.json</name>
<t><strong>Purpose</strong>: Public JWK Set <xref target="RFC7517"/> document for external relying parties.</t>
<t><strong>Response</strong>:</t>
<sourcecode type="json"><![CDATA[
{
  "keys": [
    {
      "kty": "RSA",
      "use": "sig",
      "kid": "2024-06-27-primary",
      "n": "0vx7agoebGcQ...",
      "e": "AQAB",
      "alg": "RS256"
    },
    {
      "kty": "RSA",
      "use": "sig",
      "kid": "2024-06-15-retained",
      "n": "xjlCRBfn...",
      "e": "AQAB",
      "alg": "RS256"
    }
  ]
}
]]></sourcecode>
<t><strong>Caching</strong>: <bcp14>MUST</bcp14> set <tt>Cache-Control: max-age=3600</tt></t>
</section>
<section anchor="endpoint-get-well-known-kaif-metadata-json"><name>Endpoint: GET /.well-known/kaif-metadata.json</name>
<t><strong>Purpose</strong>: Issuer metadata for relying parties (KAIF v1.1+).</t>
<t><strong>Response</strong>:</t>
<sourcecode type="json"><![CDATA[
{
  "issuer": "https://auth.example.com",
  "authorization_endpoint":
    "https://auth.example.com/oauth/authorize",
  "token_endpoint": "https://auth.example.com/oauth/token",
  "introspection_endpoint": "https://auth.example.com/introspect",
  "revocation_endpoint": "https://auth.example.com/revoke",
  "jwks_uri": "https://auth.example.com/.well-known/jwks.json",
  "supported_grant_types": [
    "urn:ietf:params:oauth:grant-type:token-exchange"
  ],
  "token_endpoint_auth_methods_supported": ["none"],
  "response_types_supported": [],
  "scopes_supported": [
    "invoke:completion",
    "vault:read",
    "admin:revoke"
  ],
  "token_endpoint_auth_methods": ["none"],
  "kaif": {
    "authorization_tiers": [
      {
        "tier": "PROVISIONAL",
        "min_value": 0.0,
        "max_value": 0.49,
        "token_ttl": 300,
        "max_delegation_depth": 0
      },
      {
        "tier": "STANDARD",
        "min_value": 0.5,
        "max_value": 0.69,
        "token_ttl": 600,
        "max_delegation_depth": 1
      },
      {
        "tier": "VERIFIED",
        "min_value": 0.7,
        "max_value": 0.89,
        "token_ttl": 900,
        "max_delegation_depth": 2
      },
      {
        "tier": "TRUSTED",
        "min_value": 0.9,
        "max_value": 1.0,
        "token_ttl": 900,
        "max_delegation_depth": 3
      }
    ],
    "revocation_propagation_sla_ms": 100,
    "audit_log_retention_days": 90
  }
}
]]></sourcecode>
</section>
</section>
<section anchor="authorization-tier-model"><name>Authorization Tier Model</name>
<t>KAIF uses operator-assigned authorization tier values in the range 0.0-1.0 to determine access permissions:</t>
<table>
<thead><tr>
<th>Tier</th>
<th>Range</th>
<th>Token TTL</th>
<th>Max Depth</th>
<th>Use Case</th>
</tr></thead>
<tbody>
<tr><td>PROVISIONAL</td><td>0.0-0.49</td><td>300s</td><td>0</td><td>New agents, limited trust</td></tr>
<tr><td>STANDARD</td><td>0.5-0.69</td><td>600s</td><td>1</td><td>Established agents</td></tr>
<tr><td>VERIFIED</td><td>0.7-0.89</td><td>900s</td><td>2</td><td>High-confidence agents</td></tr>
<tr><td>TRUSTED</td><td>0.9-1.0</td><td>900s</td><td>3</td><td>Critical operators, full delegation</td></tr>
</tbody>
</table>
<t><strong>Assigning tier values</strong>:</t>
<t>Operators assign tier values to agents based on their operational context, not automated behavioral scoring in v1.0. Examples:</t>
<ul>
<li>New agent: 0.3 (PROVISIONAL, untested)</li>
<li>Stable agent with 6 months history: 0.6 (STANDARD)</li>
<li>Agent in production payment path: 0.85 (VERIFIED)</li>
<li>Root operator with full authority: 1.0 (TRUSTED)</li>
</ul>
</section>
<section anchor="scope-model"><name>Scope Model</name>
<t>KAIF scopes follow OAuth 2.0 conventions with glob-pattern support:</t>
<artwork><![CDATA[
scope ::= scope-name ( ":" scope-name )*
scope-name ::= identifier | "*"
]]></artwork>
<t><strong>Examples</strong>:</t>
<ul>
<li><tt>invoke:completion</tt> -- Invoke a specific completion (exact match)</li>
<li><tt>vault:read:*</tt> -- Read any vault key (glob)</li>
<li><tt>admin:*</tt> -- All admin operations (glob)</li>
<li><tt>vault:read:anthropic_key</tt> -- Read one specific key (exact match)</li>
</ul>
<t><strong>Validation</strong>: Implementations <bcp14>MUST</bcp14> evaluate exact matches before glob patterns, or use an equivalent matcher. Substring matching is not sufficient.</t>
</section>
<section anchor="delegation-depth-and-sub-delegation"><name>Delegation Depth and Sub-Delegation</name>
<t>An agent <bcp14>MAY</bcp14> create a delegation chain by using its access token as the subject_token in a second token exchange, creating a sub-delegated token.</t>
<t><strong>Rules</strong>:</t>
<ul>
<li>Depth 0: Operator -&gt; Agent (direct)</li>
<li>Depth 1: Operator -&gt; Agent1 -&gt; Agent2 (sub-delegation)</li>
<li>Depth N: Limited by min(ACL max_depth, authorization_tier max_depth)</li>
</ul>
<t><strong>Restrictions</strong>:</t>
<ul>
<li>The parent token's <tt>may_sub_delegate</tt> flag <bcp14>MUST</bcp14> be true.</li>
<li>The parent token <bcp14>MUST</bcp14> be in VERIFIED or TRUSTED tier.</li>
<li>The sub-delegated token scope <bcp14>MUST</bcp14> be a subset of the parent scope.</li>
<li>Depth <bcp14>MUST</bcp14> be strictly increasing, with no cycles.</li>
</ul>
<t><strong>Example</strong>:</t>
<sourcecode><![CDATA[
1. Operator authorizes Agent1
  (depth 0, may_sub_delegate: true, scope: invoke:*)
  -> token T1 with delegation_depth: 0

2. Agent1 uses T1 as subject_token to request
   sub-delegation for Agent2
  -> verify T1.may_sub_delegate = true
  -> verify T1.delegation_depth + 1 <= ACL max
  -> issue token T2 with delegation_depth: 1
    principal_chain: [operator, agent1]

3. Agent2 attempts to sub-delegate to Agent3
  -> check T2.delegation_depth + 1 <= ACL max
  -> issue token T3 with delegation_depth: 2
]]></sourcecode>
</section>
<section anchor="audit-and-non-repudiation"><name>Audit and Non-Repudiation</name>
<t>Every KAIF operation appends an immutable audit entry, linked by SHA-256 <xref target="RFC6234"/> hash chaining:</t>
<artwork><![CDATA[
entry = {
  id: UUID v4,
  ts: ISO 8601,
  action:
    "DELEGATION_PROVISIONED" |
    "TOKEN_ISSUED" |
    "TOKEN_REVOKED" |
    ...,
  agent_id: SPIFFE ID,
  human_id: operator email,
  detail: JSON,
  hash: SHA256(prev_hash | ts | action | detail),
  prev_hash: hash of previous entry
}
]]></artwork>
<t><strong>Verification</strong>:</t>
<t>External parties can verify audit chain integrity by replaying the hash computation:</t>
<artwork><![CDATA[
expected_hash = SHA256(prev_hash | ts | action | detail)
assert actual_hash == expected_hash
]]></artwork>
</section>
<section anchor="revocation-and-propagation"><name>Revocation and Propagation</name>
<t>KAIF provides two revocation models:</t>
<section anchor="lazy-revocation-default"><name>Lazy Revocation (Default)</name>
<t>Relying parties <bcp14>MAY</bcp14> cache tokens and check expiry locally. Revocation is eventual: the denylist is checked on the next refresh.</t>
<t><strong>Latency</strong>: Minutes (depends on token cache TTL)</t>
</section>
<section anchor="strict-revocation"><name>Strict Revocation</name>
<t>Relying parties call <tt>/introspect</tt> on every token use to check revocation status in real time.</t>
<t><strong>Latency</strong>: &lt;100ms (Redis denylist lookup)</t>
<t>Operators choose strict vs. lazy based on their risk tolerance and throughput requirements.</t>
</section>
<section anchor="ha-backed-revocation-stores"><name>HA-Backed Revocation Stores</name>
<t>KAIF deployments commonly back the JTI denylist and audit chain with a managed Redis service.</t>
<t>When the backing store is a managed HA service that does not expose customer-triggerable restart or failover operations, implementations <bcp14>MUST</bcp14> validate continuity through client-observable behavior rather than cluster control-plane actions.</t>
<t>At minimum, a conformant deployment using such a service <bcp14>MUST</bcp14> demonstrate:</t>
<ul>
<li>Redis client reconnect after transient disconnect</li>
<li>Denylist persistence across reconnect</li>
<li>Audit hash-chain continuity across reconnect</li>
<li>Resumption of successful writes after reconnect</li>
</ul>
<t>Platform-specific HA limitations and validation methods <bcp14>SHOULD</bcp14> be documented in implementation reports or deployment profiles, not embedded into interoperable wire semantics.</t>
</section>
</section>
<section anchor="security-considerations"><name>Security Considerations</name>
<section anchor="token-binding-rfc-8705"><name>Token Binding (RFC 8705)</name>
<t>KAIF <bcp14>SHOULD</bcp14> support mutual TLS (mTLS) token binding <xref target="RFC8705"/>. When an agent presents a client certificate, KAIF <bcp14>MUST</bcp14> include:</t>
<sourcecode type="json"><![CDATA[
"cnf": {
  "x5t#S256": "sha256:a1b2c3d4..."
}
]]></sourcecode>
<t>The relying party <bcp14>MUST</bcp14> verify that the mTLS handshake certificate thumbprint matches the token's <tt>cnf</tt> value.</t>
</section>
<section anchor="clock-skew"><name>Clock Skew</name>
<t>All timestamp validation <bcp14>MUST</bcp14> use 10-second clock skew tolerance (not configurable).</t>
</section>
<section anchor="key-rotation"><name>Key Rotation</name>
<t>KAIF <bcp14>MUST</bcp14> support zero-downtime key rotation by maintaining both active and retained keys in the JWKS. Relying parties <bcp14>MUST</bcp14> accept tokens signed with either key for a retention period (recommended: 7 days).</t>
</section>
<section anchor="spiffe-trust-domain-validation"><name>SPIFFE Trust Domain Validation</name>
<t>KAIF <bcp14>MUST</bcp14> validate that actor_token SPIFFE ID matches the configured SPIRE trust domain. Mismatched trust domains <bcp14>MUST</bcp14> be rejected with <tt>invalid_client</tt>.</t>
</section>
<section anchor="scope-validation"><name>Scope Validation</name>
<t>Scope validation <bcp14>MUST</bcp14> use exact-match-first, then glob matching. Substring matching <bcp14>MUST NOT</bcp14> be used (e.g., "vault:read" does NOT match "vault:read:key").</t>
</section>
<section anchor="logging-and-redaction"><name>Logging and Redaction</name>
<t>KAIF implementations <bcp14>MUST</bcp14>:</t>
<ul>
<li>Log JTI (not token values)</li>
<li>Redact <tt>subject_token</tt>, <tt>actor_token</tt>, <tt>authorization</tt> headers in HTTP logs</li>
<li>Never log private key material</li>
<li>Include request ID for tracing</li>
</ul>
</section>
<section anchor="threat-model-summary"><name>Threat Model Summary</name>
<table>
<thead><tr>
<th>Attacker</th>
<th>Threat</th>
<th>Required Control</th>
<th>Residual Risk</th>
</tr></thead>
<tbody>
<tr><td>External caller without delegation</td><td>Attempts token exchange without operator grant</td><td><tt>subject_token</tt> signature, expiry, revocation, and ACL validation</td><td>Stolen valid grant until expiry or revocation</td></tr>
<tr><td>Compromised workload</td><td>Uses wrong or forged workload identity</td><td><tt>actor_token</tt> JWT-SVID validation against trust bundle and ACL-bound SPIFFE ID</td><td>Abuse by a legitimately attested but compromised workload</td></tr>
<tr><td>Token thief</td><td>Replays access token at relying party</td><td>Short TTL, optional mTLS binding, strict introspection for high-risk paths</td><td>Replay window exists when relying parties use lazy revocation</td></tr>
<tr><td>Over-privileged intermediary agent</td><td>Attempts excessive sub-delegation</td><td>Scope subset checks, <tt>may_sub_delegate</tt>, depth enforcement, tier gating</td><td>Misconfigured ACL or operator approval can still over-authorize</td></tr>
<tr><td>Malicious or faulty relying party</td><td>Accepts invalid, expired, or wrong-audience token</td><td>Mandatory JWKS validation, expiry checks, audience checks, optional strict introspection</td><td>Weak local policy at relying party remains possible</td></tr>
<tr><td>Audit tampering actor</td><td>Alters forensic record after issuance</td><td>Hash-chained audit entries and externally verifiable <tt>prev_hash</tt> continuity</td><td>Record deletion or total store loss still requires external retention strategy</td></tr>
</tbody>
</table>
</section>
<section anchor="privacy-and-data-minimization"><name>Privacy and Data Minimization</name>
<t>KAIF is intended to prove delegated authority, not to maximize identity disclosure. Implementations <bcp14>SHOULD</bcp14> minimize personal and operational data as follows:</t>
<ul>
<li><tt>sub</tt> <bcp14>SHOULD</bcp14> use the least identifying operator handle consistent with the deployment's audit requirements.</li>
<li><tt>principal_chain</tt> <bcp14>SHOULD</bcp14> contain only the identities required to explain delegation lineage.</li>
<li>Audit <tt>detail</tt> fields <bcp14>SHOULD</bcp14> exclude prompt bodies, business payloads, secrets, and raw token material unless separately required by policy.</li>
<li>Relying parties <bcp14>SHOULD</bcp14> log JTI, actor identity, action, and result before logging broader contextual data.</li>
<li>Operators and deployments <bcp14>SHOULD</bcp14> define retention periods for audit entries and principal-chain material consistent with legal and regulatory requirements.</li>
</ul>
</section>
</section>
<section anchor="relying-party-profile-normative"><name>Relying Party Profile (Normative)</name>
<t>A third-party service that accepts KAIF tokens <bcp14>MUST</bcp14> implement:</t>
<section anchor="token-validation"><name>Token Validation</name>
<sourcecode><![CDATA[
1. Fetch JWKS from issuer's /.well-known/jwks.json (cache 3600s)
2. Verify token signature using KID matching (try each key)
3. Verify exp > now (with 10s clock skew)
4. If lazy revocation: done
5. If strict revocation: POST /introspect to check JTI denylist
6. Extract scope, verify requested action is permitted
7. Extract actor.sub (SPIFFE ID), log for audit trail
]]></sourcecode>
</section>
<section anchor="error-handling"><name>Error Handling</name>
<t>HTTP status codes are used as defined in <xref target="RFC9110"/>.</t>
<table>
<thead><tr>
<th>Condition</th>
<th>Action</th>
<th>HTTP Status</th>
</tr></thead>
<tbody>
<tr><td>Signature invalid</td><td>Reject</td><td>401 Unauthorized</td></tr>
<tr><td>Expired</td><td>Reject</td><td>401 Unauthorized</td></tr>
<tr><td>Revoked (strict mode)</td><td>Reject</td><td>401 Unauthorized</td></tr>
<tr><td>Scope insufficient</td><td>Reject</td><td>403 Forbidden</td></tr>
<tr><td>Introspect unreachable (strict mode)</td><td>Degrade or reject (policy choice)</td><td>503 Service Unavailable</td></tr>
</tbody>
</table>
</section>
<section anchor="audit-trail"><name>Audit Trail</name>
<t>Relying parties <bcp14>SHOULD</bcp14> log:</t>
<ul>
<li>Timestamp of token use</li>
<li>JTI</li>
<li>Actor SPIFFE ID</li>
<li>Scope used</li>
<li>Action executed</li>
<li>Result (success/failure)</li>
</ul>
<t>This enables cross-party forensics if a token is misused.</t>
</section>
</section>
<section anchor="backward-compatibility"><name>Backward Compatibility</name>
<t>This is KAIF v1.0, the initial standards-track release. Future versions:</t>
<ul>
<li><strong>v1.1</strong>: Issuer metadata endpoint (<tt>.well-known/kaif-metadata.json</tt>)</li>
<li><strong>v2.0</strong>: Multi-issuer federation, cross-operator delegation</li>
<li><strong>v3.0</strong>: Behavioral trust signals (optional, opt-in per operator)</li>
</ul>
<t>Implementations <bcp14>MUST</bcp14> gracefully ignore unrecognized claims in KAIF tokens to allow forward compatibility.</t>
</section>
<section anchor="iana-considerations"><name>IANA Considerations</name>
<t>This document registers the following values with IANA:</t>
<section anchor="oauth-2-0-grant-type"><name>OAuth 2.0 Grant Type</name>
<t><strong>Type</strong>: urn:ietf:params:oauth:grant-type:token-exchange (RFC 8693)</t>
<t><strong>Description</strong>: Token exchange grant (already registered; KAIF profiles its use)</t>
</section>
<section anchor="jwt-claims"><name>JWT Claims</name>
<t><strong>Claim name</strong>: <tt>kaif</tt> <strong>Claim description</strong>: Container for KAIF-specific claims (authorization_tier, delegation_depth, principal_chain) <strong>JWT claims registry</strong>: Requested</t>
</section>
</section>
<section anchor="conformance"><name>Conformance</name>
<t>An implementation claims KAIF v1.0 conformance if it:</t>
<ol>
<li>Implements POST /oauth/token with RFC 8693 semantics</li>
<li>Implements POST /introspect with RFC 7662 semantics</li>
<li>Validates actor_token as JWT-SVID from a configured SPIRE bundle or equivalent SPIFFE trust source</li>
<li>Enforces scope glob matching with exact-match-first behavior</li>
<li>Supports delegation depth tracking and enforcement</li>
<li>Publishes JWKS with active and retained keys</li>
<li>Maintains an audit trail with SHA-256 hash chaining</li>
<li>Supports JTI revocation with sub-second propagation</li>
<li>Validates timestamps with 10-second clock skew tolerance</li>
<li>Passes the KAIF conformance test suite</li>
</ol>
<t>Conformance is demonstrated by passing the KAIF conformance kit included with this repository.</t>
<t>Protocol conformance and deployment evidence are related but distinct:</t>
<ul>
<li>Protocol conformance establishes that an implementation speaks KAIF correctly.</li>
<li>Deployment evidence establishes that a specific operating environment behaved correctly under real conditions.</li>
</ul>
<t>An implementation <bcp14>MAY</bcp14> publish deployment evidence, interoperability notes, or platform-specific profiles in addition to protocol conformance results.</t>
<section anchor="interoperability-evidence-informative"><name>Interoperability Evidence (Informative)</name>
<t>A report <bcp14>SHOULD</bcp14> clearly state:</t>
<ol>
<li>which parts of the KAIF handshake were exercised</li>
<li>whether the relying party was independent from the authorization server</li>
<li>which delivery, receipt, or resume semantics were validated beyond token issuance</li>
<li>which deployment details are informative examples rather than normative protocol requirements</li>
<li>which claims were not tested</li>
</ol>
</section>
<section anchor="revocation-store-resilience-profile"><name>Revocation-Store Resilience Profile</name>
<t>If a deployment uses a managed Redis service for denylist and audit persistence, conformance evidence <bcp14>SHOULD</bcp14> include a revocation-store resilience profile.</t>
<t>That profile <bcp14>SHOULD</bcp14> verify:</t>
<ol>
<li>Redis client reconnect recovery</li>
<li>Denylist persistence after reconnect</li>
<li>Audit chain <tt>prev_hash</tt> continuity after reconnect</li>
<li>Successful new delegation, token issuance, and revocation writes after reconnect</li>
</ol>
<t>If the platform does not expose customer-triggerable restart or failover operations, the implementation <bcp14>MUST</bcp14> document that limitation and <bcp14>MAY</bcp14> satisfy this profile using client-side disconnect and reconnect simulation plus state verification.</t>
</section>
</section>
</middle>
<back>
<references><name>Normative</name>
<reference anchor="RFC2119" target="https://www.rfc-editor.org/info/rfc2119"><front><title>Key words for use in RFCs to Indicate Requirement Levels</title><author initials="S." surname="Bradner"></author><date year="1997" month="March"/></front><seriesInfo name="BCP" value="14"/><seriesInfo name="RFC" value="2119"/><seriesInfo name="DOI" value="10.17487/RFC2119"/></reference><reference anchor="RFC9110" target="https://www.rfc-editor.org/info/rfc9110"><front><title>HTTP Semantics</title><author initials="R." surname="Fielding" role="editor"></author><author initials="M." surname="Nottingham" role="editor"></author><author initials="J." surname="Reschke" role="editor"></author><date year="2022" month="June"/></front><seriesInfo name="STD" value="97"/><seriesInfo name="RFC" value="9110"/><seriesInfo name="DOI" value="10.17487/RFC9110"/></reference><reference anchor="RFC7517" target="https://www.rfc-editor.org/info/rfc7517"><front><title>JSON Web Key (JWK)</title><author initials="M." surname="Jones"></author><date year="2015" month="May"/></front><seriesInfo name="RFC" value="7517"/><seriesInfo name="DOI" value="10.17487/RFC7517"/></reference><reference anchor="RFC7662" target="https://www.rfc-editor.org/info/rfc7662"><front><title>OAuth 2.0 Token Introspection</title><author initials="J." surname="Richer" role="editor"></author><date year="2015" month="October"/></front><seriesInfo name="RFC" value="7662"/><seriesInfo name="DOI" value="10.17487/RFC7662"/></reference><reference anchor="RFC8174" target="https://www.rfc-editor.org/info/rfc8174"><front><title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title><author initials="B." surname="Leiba"></author><date year="2017" month="May"/></front><seriesInfo name="BCP" value="14"/><seriesInfo name="RFC" value="8174"/><seriesInfo name="DOI" value="10.17487/RFC8174"/></reference><reference anchor="RFC8693" target="https://www.rfc-editor.org/info/rfc8693"><front><title>OAuth 2.0 Token Exchange</title><author initials="M." surname="Jones"></author><author initials="A." surname="Nadalin"></author><author initials="B." surname="Campbell" role="editor"></author><author initials="J." surname="Bradley"></author><author initials="C." surname="Mortimore"></author><date year="2020" month="January"/></front><seriesInfo name="RFC" value="8693"/><seriesInfo name="DOI" value="10.17487/RFC8693"/></reference>
</references>
<references><name>Informative</name>
<reference anchor="RFC6234" target="https://www.rfc-editor.org/info/rfc6234"><front><title>US Secure Hash Algorithms (SHA and SHA-based HMAC and HKDF)</title><author initials="D." surname="Eastlake 3rd"></author><author initials="T." surname="Hansen"></author><date year="2011" month="May"/></front><seriesInfo name="RFC" value="6234"/><seriesInfo name="DOI" value="10.17487/RFC6234"/></reference><reference anchor="RFC8705" target="https://www.rfc-editor.org/info/rfc8705"><front><title>OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens</title><author initials="B." surname="Campbell"></author><author initials="J." surname="Bradley"></author><author initials="N." surname="Sakimura"></author><author initials="T." surname="Lodderstedt"></author><date year="2020" month="February"/></front><seriesInfo name="RFC" value="8705"/><seriesInfo name="DOI" value="10.17487/RFC8705"/></reference><reference anchor="SPIFFE" target="https://spiffe.io/"><front><title>Secure Production Identity Framework for Everyone (SPIFFE)</title><author><organization>Cloud Native Computing Foundation</organization></author><date/></front></reference><reference anchor="SPIRE" target="https://spiffe.io/docs/latest/spire/"><front><title>The SPIFFE Runtime Environment (SPIRE)</title><author><organization>Cloud Native Computing Foundation</organization></author><date/></front></reference>
</references>
<section anchor="illustrative-implementation-status-informative"><name>Illustrative Implementation Status (Informative)</name>
<t>One implementation-backed validation of KAIF exercised the following path:</t>
<ol>
<li>an operator provisioned a delegation grant for a registered workload</li>
<li>the workload exchanged that grant together with its workload identity for an audience-bound token</li>
<li>a third-party execution surface accepted the boundary request</li>
<li>a completion receipt was written back to the originating system</li>
<li>the originating workflow resumed and completed its downstream steps</li>
</ol>
<t>This validation supports the claim that KAIF can convey delegated authority, workload identity, audience restriction, and correlated receipt data across a real external boundary.</t>
<t>This validation does not, by itself, prove:</t>
<ul>
<li>interoperability across multiple independent KAIF implementations</li>
<li>standardization of any particular cloud transport, agent runtime, queue, workflow engine, or datastore</li>
<li>completeness of every optional KAIF feature or future extension</li>
</ul>
<t>Implementers <bcp14>SHOULD</bcp14> publish similarly bounded implementation reports so that protocol review can distinguish wire-level interoperability from deployment-specific success.</t>
</section>
</back>
</rfc>
