| Internet-Draft | KAIF | July 2026 |
| Lundholm | Expires 20 January 2027 | [Page] |
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.¶
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.¶
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.¶
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 20 January 2027.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
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:¶
KAIF addresses these challenges by combining three existing standards and practices:¶
KAIF is intended for operator-initiated, agent-executed, boundary-crossing transactions. A "boundary-crossing transaction" is any action where:¶
The following are out of scope for v1.0:¶
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.¶
KAIF-specific terms:¶
KAIF has been validated in at least one concrete multi-system deployment as an implementation-backed protocol design. That deployment demonstrated, end to end:¶
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.¶
The protocol wire format in this document uses authorization_tier and authorization_tier_value as the canonical delegation strength fields.¶
Implementations MAY use local internal terms such as trust_tier, trust_score, or similar, but those names are deployment-specific and are not normative protocol vocabulary unless explicitly mapped to the KAIF claims defined here.¶
+------------+
| 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)|
+--------------+
¶
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:¶
{
"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"
}
}
¶
The agent exchanges the delegation grant (subject_token) and its SPIFFE identity JWT-SVID (actor_token) for an access token:¶
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¶
The server returns a signed JWT that carries operator identity, agent identity, delegation depth, tier, and scope:¶
{
"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"]
}
}
¶
When a relying party receives the access token from an agent:¶
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
¶
Purpose: Operator provisions a delegation grant for an agent.¶
Request:¶
{
"id_token": "eyJhbGc...",
"agent_id": "lyra",
"scope": "invoke:completion vault:read:anthropic_key",
"ttl_seconds": 600
}
¶
Validation:¶
id_token MUST be a valid OIDC token from configured IdP¶
agent_id MUST be registered in operator's ACL¶
scope MUST be a subset of agent's permitted scopes¶
ttl_seconds MUST be between 60 and 86400¶
Response:¶
{
"delegation_id": "d-550e8400-e29b-41d4-a716-446655440000",
"delegation_token": "eyJhbGc...",
"expires_at": 1719493200,
"agent_id": "lyra",
"scope": "invoke:completion vault:read:anthropic_key"
}
¶
Errors:¶
Purpose: RFC 8693 token exchange for agent-initiated access-token requests.¶
Request:¶
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¶
Validation steps (in order):¶
Parse and validate subject_token (delegation grant)¶
Parse and validate actor_token (JWT-SVID)¶
Validate scope¶
Check authorization tier¶
Compute delegation depth¶
Response:¶
{
"access_token": "eyJhbGc...",
"issued_token_type":
"urn:ietf:params:oauth:token-type:access_token",
"token_type": "Bearer",
"expires_in": 600,
"scope": "invoke:completion"
}
¶
Errors:¶
invalid_request (400): Malformed request¶
invalid_grant (400): subject_token invalid/expired/revoked¶
invalid_scope (400): Scope not permitted¶
invalid_client (401): actor_token invalid¶
insufficient_trust (403): Authorization tier below minimum¶
delegation_depth_exceeded (403): Depth would exceed limit¶
Purpose: RFC 7662 [RFC7662] token introspection for relying parties that verify tokens in real time.¶
Request:¶
{
"token": "eyJhbGc..."
}
¶
Response (if active):¶
{
"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
}
}
¶
Response (if revoked or invalid):¶
{
"active": false
}
¶
Purpose: Operator revokes a token.¶
Request:¶
{
"token": "eyJhbGc...",
"reason": "operator_request"
}
¶
Response:¶
{
"revoked": true,
"jti": "650e8400-e29b-41d4-a716-446655440001"
}
¶
Mechanics:¶
Purpose: Public JWK Set [RFC7517] document for external relying parties.¶
Response:¶
{
"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"
}
]
}
¶
Caching: MUST set Cache-Control: max-age=3600¶
Purpose: Issuer metadata for relying parties (KAIF v1.1+).¶
Response:¶
{
"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
}
}
¶
KAIF scopes follow OAuth 2.0 conventions with glob-pattern support:¶
scope ::= scope-name ( ":" scope-name )* scope-name ::= identifier | "*"¶
Examples:¶
invoke:completion -- Invoke a specific completion (exact match)¶
vault:read:* -- Read any vault key (glob)¶
admin:* -- All admin operations (glob)¶
vault:read:anthropic_key -- Read one specific key (exact match)¶
Validation: Implementations MUST evaluate exact matches before glob patterns, or use an equivalent matcher. Substring matching is not sufficient.¶
An agent MAY create a delegation chain by using its access token as the subject_token in a second token exchange, creating a sub-delegated token.¶
Rules:¶
Restrictions:¶
may_sub_delegate flag MUST be true.¶
Example:¶
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
¶
Every KAIF operation appends an immutable audit entry, linked by SHA-256 [RFC6234] hash chaining:¶
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
}
¶
Verification:¶
External parties can verify audit chain integrity by replaying the hash computation:¶
expected_hash = SHA256(prev_hash | ts | action | detail) assert actual_hash == expected_hash¶
KAIF provides two revocation models:¶
Relying parties MAY cache tokens and check expiry locally. Revocation is eventual: the denylist is checked on the next refresh.¶
Latency: Minutes (depends on token cache TTL)¶
Relying parties call /introspect on every token use to check revocation status in real time.¶
Latency: <100ms (Redis denylist lookup)¶
Operators choose strict vs. lazy based on their risk tolerance and throughput requirements.¶
KAIF deployments commonly back the JTI denylist and audit chain with a managed Redis service.¶
When the backing store is a managed HA service that does not expose customer-triggerable restart or failover operations, implementations MUST validate continuity through client-observable behavior rather than cluster control-plane actions.¶
At minimum, a conformant deployment using such a service MUST demonstrate:¶
Platform-specific HA limitations and validation methods SHOULD be documented in implementation reports or deployment profiles, not embedded into interoperable wire semantics.¶
KAIF SHOULD support mutual TLS (mTLS) token binding [RFC8705]. When an agent presents a client certificate, KAIF MUST include:¶
"cnf": {
"x5t#S256": "sha256:a1b2c3d4..."
}
¶
The relying party MUST verify that the mTLS handshake certificate thumbprint matches the token's cnf value.¶
All timestamp validation MUST use 10-second clock skew tolerance (not configurable).¶
KAIF MUST support zero-downtime key rotation by maintaining both active and retained keys in the JWKS. Relying parties MUST accept tokens signed with either key for a retention period (recommended: 7 days).¶
KAIF MUST validate that actor_token SPIFFE ID matches the configured SPIRE trust domain. Mismatched trust domains MUST be rejected with invalid_client.¶
Scope validation MUST use exact-match-first, then glob matching. Substring matching MUST NOT be used (e.g., "vault:read" does NOT match "vault:read:key").¶
KAIF implementations MUST:¶
| Attacker | Threat | Required Control | Residual Risk |
|---|---|---|---|
| External caller without delegation | Attempts token exchange without operator grant |
subject_token signature, expiry, revocation, and ACL validation |
Stolen valid grant until expiry or revocation |
| Compromised workload | Uses wrong or forged workload identity |
actor_token JWT-SVID validation against trust bundle and ACL-bound SPIFFE ID |
Abuse by a legitimately attested but compromised workload |
| Token thief | Replays access token at relying party | Short TTL, optional mTLS binding, strict introspection for high-risk paths | Replay window exists when relying parties use lazy revocation |
| Over-privileged intermediary agent | Attempts excessive sub-delegation | Scope subset checks, may_sub_delegate, depth enforcement, tier gating |
Misconfigured ACL or operator approval can still over-authorize |
| Malicious or faulty relying party | Accepts invalid, expired, or wrong-audience token | Mandatory JWKS validation, expiry checks, audience checks, optional strict introspection | Weak local policy at relying party remains possible |
| Audit tampering actor | Alters forensic record after issuance | Hash-chained audit entries and externally verifiable prev_hash continuity |
Record deletion or total store loss still requires external retention strategy |
KAIF is intended to prove delegated authority, not to maximize identity disclosure. Implementations SHOULD minimize personal and operational data as follows:¶
sub SHOULD use the least identifying operator handle consistent with the deployment's audit requirements.¶
principal_chain SHOULD contain only the identities required to explain delegation lineage.¶
detail fields SHOULD exclude prompt bodies, business payloads, secrets, and raw token material unless separately required by policy.¶
A third-party service that accepts KAIF tokens MUST implement:¶
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¶
HTTP status codes are used as defined in [RFC9110].¶
| Condition | Action | HTTP Status |
|---|---|---|
| Signature invalid | Reject | 401 Unauthorized |
| Expired | Reject | 401 Unauthorized |
| Revoked (strict mode) | Reject | 401 Unauthorized |
| Scope insufficient | Reject | 403 Forbidden |
| Introspect unreachable (strict mode) | Degrade or reject (policy choice) | 503 Service Unavailable |
This is KAIF v1.0, the initial standards-track release. Future versions:¶
.well-known/kaif-metadata.json)¶
Implementations MUST gracefully ignore unrecognized claims in KAIF tokens to allow forward compatibility.¶
This document registers the following values with IANA:¶
Type: urn:ietf:params:oauth:grant-type:token-exchange (RFC 8693)¶
Description: Token exchange grant (already registered; KAIF profiles its use)¶
Claim name: kaif Claim description: Container for KAIF-specific claims (authorization_tier, delegation_depth, principal_chain) JWT claims registry: Requested¶
An implementation claims KAIF v1.0 conformance if it:¶
Conformance is demonstrated by passing the KAIF conformance kit included with this repository.¶
Protocol conformance and deployment evidence are related but distinct:¶
An implementation MAY publish deployment evidence, interoperability notes, or platform-specific profiles in addition to protocol conformance results.¶
A report SHOULD clearly state:¶
If a deployment uses a managed Redis service for denylist and audit persistence, conformance evidence SHOULD include a revocation-store resilience profile.¶
That profile SHOULD verify:¶
prev_hash continuity after reconnect¶
If the platform does not expose customer-triggerable restart or failover operations, the implementation MUST document that limitation and MAY satisfy this profile using client-side disconnect and reconnect simulation plus state verification.¶
One implementation-backed validation of KAIF exercised the following path:¶
This validation supports the claim that KAIF can convey delegated authority, workload identity, audience restriction, and correlated receipt data across a real external boundary.¶
This validation does not, by itself, prove:¶
Implementers SHOULD publish similarly bounded implementation reports so that protocol review can distinguish wire-level interoperability from deployment-specific success.¶