Loading WASM runtime…

Why Agent Identity Matters

As AI agents proliferate — spawning sub-agents, calling external APIs, acting on behalf of humans — the industry is hitting a wall: no standard way to prove which agent did what, on whose behalf, and with what authority. Existing identity primitives were designed for services, not for autonomous reasoning processes that delegate to one another at runtime.

TODAY — AGENTS SHARE STATIC CREDENTIALS, NO DELEGATION TRAIL Orchestrator AI Agent (LLM) Sub-Agent Executor (spawned) Tool / API External service Audit / SIEM Who called what? sk-api-XXXXX sk-api-XXXXX No attestation Any process can claim any identity No delegation trail Who authorised this sub-agent to act? Shared + replayable Static key, broad scope, no per-request binding Blind audit log Caller = "my-app" — no chain visible
No Workload Identity
Each cloud assigns its own credential (IAM role, service account, managed identity). Agents running inside a workload inherit that coarse-grained identity — there's no way to distinguish which agent made a call.
Invisible Delegation Chains
When an orchestrator spawns sub-agents, there's no cryptographic record of the delegation. The API sees a static key — it can't tell if the call was authorised by a human, a policy, or an arbitrary agent process.
Static, Shared Credentials
API keys and secrets are long-lived, shared across agent instances, and scoped to the entire service — not the specific task. A compromised agent or leaked key gives an attacker full service-level access.
The core gap: IETF WIMSE (Workload Identity in Multi-System Environments) was created specifically to address this. It provides a standard, portable workload identity primitive — agent+jwt — that works across clouds, carries cryptographic proof of the delegation chain, and binds each request to a non-replayable proof token.
Why not just use what's already there?

Every team asks this first. Here's what each existing approach provides — and the specific gap it leaves for AI agents.

Existing approach What it gives you What it doesn't solve for agents
OAuth Bearer token
Authorization: Bearer <token>
Authorization for an action or scope on one AS Ambient authority — stolen token = full access until expiry. No per-request proof. No delegation chain: the API sees the token but can't tell if an agent or a human used it, or which sub-agent in a chain called it.
mTLS alone
X.509 client cert
Transport-layer identity; proves the caller holds a private key Cert identity is service-level (e.g. "my-app"), not agent-level. All agent instances share the same cert. No delegation trail — the sub-agent cert says nothing about which orchestrator spawned it.
API keys / secrets
sk-abc123 / HMAC
Service-to-service authentication; simple to implement Static, long-lived, broadly scoped. Shared across all agent instances — a compromised key is service-level blast radius. No per-request binding, no chain, no revocation without rotating every caller.
Cloud IAM roles
AWS IAM / GCP SA / Azure MI
Cloud-native identity; short-lived creds auto-rotated by the platform Cloud-scoped — a GCP service account cannot natively authenticate to AWS. Agent process inherits the workload IAM role; no way to distinguish orchestrator from sub-agent or carry delegation context across clouds.
K8s Service Accounts / SPIFFE SVID
spiffe://cluster/ns/sa
Platform identity; cryptographic attestation of the running workload SPIFFE identifies the workload, not the individual agent. No delegation semantics — SPIRE has no concept of "agent A authorised agent B to act on behalf of user C". Stops at service boundary, no application-layer chain.
WIMSE Agent Fabric adds the missing layer: each agent gets a short-lived agent+jwt bound to its EC key pair, a cryptographic AgentChain recording every delegation hop, and a per-request agent-proof+jwt tied to the exact target URI — preventing replay and proving exactly which agent, in which chain, on whose behalf.
Five concrete AI agent identity challenges — what the industry is debating right now

These are not theoretical. Each represents a real class of incident or compliance gap that enterprises encounter when deploying autonomous AI agents at scale.

① Over-permissioning

Agents inherit their host workload's IAM role — which was sized for the workload, not the task. A summarisation agent running inside an "admin" workload can read, write, and delete with full admin authority — even if the task only needed read access to one document. No current framework reduces scope automatically at agent spawn time.

Real impact: a single compromised agent instance = full workload-level blast radius
② Acting on behalf of humans — without attestation

Agents commonly claim "I am acting on behalf of user@example.com" in request headers or metadata — but there is no cryptographic proof of this claim. The downstream API can't verify whether the human actually authorised this action, whether the agent has exceeded the scope the human intended, or whether the delegation has since been revoked.

Real impact: unauthorised actions attributed to users who never consented
③ Scope creep through delegation

When an orchestrator spawns sub-agents, it typically passes its own credentials or tokens. The sub-agent receives the same scope as the orchestrator — delegation doesn't reduce authority, it propagates it unchanged. This creates a privilege escalation path: a compromised sub-agent gains the full authority of every agent above it in the chain.

Real impact: confused deputy attacks across agent hierarchies
④ Non-repudiation failure

After an incident, the audit log shows caller=my-app — it does not show which agent instance, which model version, which prompt template, or which human initiated the chain. There is no cryptographic way to prove which reasoning process issued the API call. Attribution of AI-driven actions is currently impossible without agent-level identity.

Real impact: regulators and insurers increasingly demand traceable attribution for AI actions
⑤ Multi-tenant isolation failure

In multi-tenant agent platforms, agents serving different customers often run inside the same workload and share the same cloud identity. There is no identity-layer boundary between tenant A's agent and tenant B's agent — isolation relies entirely on application code correctness, not on cryptographic enforcement. A prompt injection or context leak can expose tenant A's tool calls, credentials, or outputs to tenant B's agent if the application layer fails.

Real impact: cross-tenant data exfiltration and regulatory violation with zero forensic signal in the identity layer
What's already been tried — and where each solution stops short

The industry has not been standing still. These are real approaches teams are using today. Each solves part of the problem — none addresses agent-level cryptographic identity.

Approach What it solves Where it stops What WIMSE adds
Tool / function calling frameworks
OpenAI function_call, Anthropic tool_use, LangChain tools
Structured tool invocation; the model declares which tool it wants to call Tools are defined per session, not per agent identity. Any agent (or attacker with model access) can call any tool in the session — there is no per-agent-instance credential binding AgentToken bound to agent's EC key; tool calls carry per-request agent-proof+jwt — the tool server verifies which specific agent is calling, not just which session
OAuth 2.0 scopes for agents
access_token with scope=read:documents
Limits what a token can do; coarse-grained access control at the API level Scopes describe what a token can do — not which agent is using it. All agent instances share one token; scope doesn't encode the delegation chain or reduce with each hop AgentChain JWT encodes the full delegation path with scope reduction at each hop; the downstream API can verify the entire authorisation lineage, not just the final token scope
Observability / tracing
LangSmith, LangFuse, OpenTelemetry
Reconstructs what happened; correlates spans across agent calls; useful for debugging Traces are collected, not attested — any log-line can be forged or omitted. Tracing depends on instrumentation completeness; it cannot prove that a logged action actually happened from that agent AgentChain and AgentProofToken are cryptographically signed — audit records are tamper-evident by construction, not reconstructed from logs after the fact
Service mesh (Istio / Linkerd)
mTLS + SPIFFE SVID at the sidecar
Transport-layer mutual authentication; proves the pod is who it claims to be Identity is at the service level — all agents inside a pod share the same SVID. Mesh identity doesn't survive TLS termination at a load balancer; no delegation semantics at the application layer AgentToken operates at the application layer, above TLS — it survives LB termination and identifies the individual agent within the workload, not just the workload itself
Cloud IAM conditions
AWS IAM condition keys, GCP IAM conditions
Fine-grained access control; can restrict which resources a role can access based on request attributes Cloud-scoped — conditions on a GCP IAM policy don't apply to an AWS API call. Conditions apply to the workload role, not to a specific agent instance. No cross-cloud or cross-org delegation SPIFFE Client Auth + Identity Chaining bridges cross-domain calls with preserved agent identity; CB4A adds per-credential governance independent of cloud IAM
Why this is now a regulatory requirement — not just a best practice
EU AI Act (2025–2027)
  • Art. 9 — Risk management system must document and monitor AI system behaviour; agent identity records are evidence
  • Art. 13 — Transparency: outputs of high-risk AI must be traceable to the specific AI system and version that produced them
  • Art. 14 — Human oversight: systems must be designed so a human can verify what the AI did and when
Without per-agent identity, Art. 13 compliance is structurally impossible for multi-agent systems
NIST AI RMF (2023)
  • Govern 6.2 — Transparency and accountability: AI actors must be identifiable and accountable for AI system outputs
  • Map 1.6 — Identify AI risks: autonomous delegation without identity is a first-class risk category
  • Measure 2.5 — Monitor AI system behaviour: cryptographic audit trails are the mechanism for trustworthy monitoring
NIST profiles treat agent accountability as a governance requirement, not an engineering choice
SOC 2 Type II & GDPR
  • SOC 2 CC6 (Logical Access) — Agent API calls to external services are in scope; without per-agent identity, auditors cannot verify least-privilege enforcement
  • GDPR Art. 5(2) — Accountability: data controllers must demonstrate compliance; AI agent actions on personal data require attributable identity
  • GDPR Art. 25 — Data protection by design: per-agent identity and scope reduction are the privacy-by-design mechanism for agent systems
Auditors increasingly flag multi-agent systems without per-agent identity as CC6 gaps
Architecture — Agent Identity Chain
Identity Provider idp.agent-fabric.example Orchestrator chain_depth=0 Executor Agent chain_depth=1 Gateway validates chain+proof Tool Server protected resource AT chain validate proof
Step-by-step walkthrough
Run through the steps in order — each button unlocks the next. Click Restart to reset anytime.
Click "Generate Keys" to begin
Issuer
idp.agent-fabric.example
Algorithm
ES256 (EC P-256)
Key Pairs
3 generated (IdP · Orchestrator · Executor)
Trust establishment. The IdP's private key is the root of trust. Every agent+jwt issued by this IdP is signed with it. Agents embed their own public key in the cnf.jwk claim so verifiers can later check proof-of-possession.
Spec: draft-ietf-wimse-workload-creds · typ: agent+jwt · alg: ES256
Orchestrator AgentToken — JWT Anatomy
Token loading…

Header red

sub
role
chain_depth
cnf.jwk — The token embeds the orchestrator's public key. When it later generates a proof token, any verifier can confirm the proof was signed by the matching private key — without a separate key lookup.
Executor AgentToken — JWT Anatomy
Token loading…

Header red

chain_depth
chain_hash
Wire Format — Agent Identity Chain
Building chain…
AT-1~AT-2 wire format — Tokens are concatenated with ~ (same separator as SD-JWT disclosures). The Gateway validates every token in the chain in order, checking signatures, expiry, and that chain depths are strictly sequential (0, 1, 2…). Skipping or repeating a depth fails validation.
Chain Validation — Gateway Checks
Hop 1 (Orchestrator) — signature valid, role=orchestrator, chain_depth=0
Hop 2 (Executor) — signature valid, role=executor, chain_depth=1
Sequential depth order — 0 → 1 (no gaps, no repeats)
All tokens within expiry window
Why chain depth matters. Without sequential depth enforcement, a compromised executor could self-issue a new token with chain_depth=0 to appear as an orchestrator, gaining elevated privileges. The Gateway rejects any token whose depth is not exactly previous_depth + 1.
Spec: draft-ietf-wimse-workload-creds · typ: application/agent-proof+jwt
Agent Proof Token — JWT Anatomy
Token loading…

Header red

aud (target URI)
chain_hash
Per-request binding. The proof token is signed by the executor's private key (matching the cnf.jwk in the AgentToken). Its aud is the exact target URI, and chain_hash is SHA-256 of the full chain string. Even if an attacker captures this token, replaying it to a different endpoint fails the aud check — and replaying to the same endpoint fails the JTI replay detection.
How it works
  • 1
    The Identity Provider generates an EC P-256 key pair — the root of trust for all agent tokens in this domain.
  • 2
    The Orchestrator receives a signed agent+jwt with role=orchestrator and chain_depth=0. Its public key is bound via cnf.jwk.
  • 3
    When delegating, the Executor also gets a agent+jwt with chain_depth=1. The chain wire format is AT-1~AT-2.
  • 4
    The Gateway validates every token in the chain: signature, expiry, issuer, and strictly sequential chain depths.
  • 5
    A per-request agent-proof+jwt binds the call to the exact target URI (aud) and the chain hash, preventing reuse or redirection.
Emerging alternative: draft-ietf-wimse-http-signature proposes replacing the JWT-based agent-proof+jwt with RFC 9421 HTTP Message Signatures — a transport-layer binding that covers the full HTTP request (method, path, headers, body digest) rather than just the URI. Tracked in standards-baseline.json as a future variant of pkg/identity/proof.go.
Replay Attack Simulation

An attacker intercepts a valid Agent-Proof-Token and immediately replays it to gain unauthorized access. WIMSE prevents this with per-request JTI (JWT ID) replay detection maintained by the Gateway.

Legitimate Agent generates proof Attacker captures & replays Gateway JTI replay store
Chain
orchestrator → executor (2 hops)
Chain Hash
Status
Ready to simulate attack
Replay Attack Results
Captured Proof JTI (JWT ID)
1st Request — ACCEPTED
JTI stored in replay store
Request processed normally
🚫
2nd Request — REJECTED
jti already used
The protection. Every agent-proof+jwt carries a unique jti (UUID). The Gateway's replay store records each seen JTI within the token's validity window. The second request with the same JTI is rejected before any business logic runs.
Token Tampering Simulation

An attacker modifies the claims of a valid agent+jwt — for example, changing role from executor to orchestrator to gain elevated privileges. ES256 (EC P-256) makes this immediately detectable.

Original Orchestrator Token — Valid Signature

Header

Tampered Token — Signature Zeroed Out
What the attacker did: Replaced the last JWT segment (ES256 signature) with 43 zero bytes. The header and payload are unchanged — the role, subject, and all claims look identical. But the signature no longer matches the IdP's public key.
Parse JWT header and payload
Fetch IdP public key from JWKS
Verify ES256 signature
Signature verification FAILED
Why it works. EC P-256 signatures are computed over base64url(header) + "." + base64url(payload). Any modification to either part — even a single byte — produces a completely different expected signature. The attacker cannot forge a valid signature without the IdP's private key.
WIMSE Agent Fabric — Threat Model
T1 · Stolen Identity Token
An attacker captures a valid agent+jwt from network traffic and reuses it to impersonate a legitimate agent.
Per-request agent-proof+jwt is signed by the agent's private key. Without the private key the attacker cannot forge a valid proof.
T2 · Proof Token Replay
An attacker replays a captured agent-proof+jwt within its validity window to access a resource a second time.
The Gateway maintains a JTI replay store. Each proof has a unique jti; reuse is detected and rejected immediately.
T3 · Token Tampering
An attacker modifies the claims of a captured token (e.g., changes role, sub, or chain_depth) to escalate privileges.
All tokens are signed with ES256 (EC P-256). Any modification to the header or payload invalidates the signature.
T4 · Unauthorized Tool Access
A compromised executor agent attempts to access a tool or resource it was never authorized to use.
The Gateway enforces fine-grained authorization via the Authorizer interface (backed by OpenFGA). Every request is checked: subject × tool × action.
T5 · Chain Depth Escalation
A malicious executor tries to issue a token with chain_depth=0 to appear as an orchestrator, or skips depth levels to forge the delegation chain.
The Gateway validates that chain depths are strictly sequential (0, 1, 2…). Any gap or reset causes validation to fail.
T6 · Audience Confusion
A proof token generated for Tool A is forwarded to Tool B, where the attacker hopes it will be accepted for a different operation.
The aud claim is bound to the exact target URI. The Gateway validates that aud matches the request URI precisely.
T7 · Chain Substitution
An attacker swaps the Agent-Chain-Token header with a chain where they have higher privileges, hoping the proof token will still be accepted.
The proof token carries chain_hash = base64url(SHA-256(AT-1~…~AT-N)). The Gateway recomputes the hash of the presented chain — a substituted chain produces a different hash and the request is rejected.
T8 · Token Theft with mTLS Enabled
An attacker steals an agent+jwt (e.g., from a log or compromised proxy) and replays it from a machine with a different TLS certificate.
When MTLSClientCA is set, verifyMTLSBinding() checks that the peer certificate's URI SAN equals the token's sub claim. The attacker's cert has a different URI SAN — the check fails. The agent uses the same EC key pair for mTLS cert, cnf.jwk, and proof signing, so compromising the token alone is useless without the private key.
AI-specific threats — autonomous agents introduce new attack surfaces

T9–T12 are attack vectors unique to autonomous AI agents. Traditional workload identity defences were not designed with reasoning processes, prompt injection, or runtime delegation in mind.

T9 · Prompt Injection → Credential Exfiltration
A malicious user crafts an input that instructs the agent to forward its identity token or call a tool with attacker-controlled parameters — effectively hijacking the agent's credentials at the application layer.
Partial mitigation: AgentProofToken aud is bound to the exact target URI — a redirected call to an attacker-controlled URL won't produce a valid proof for that URL. CB4A Tier 1/2/3 governance limits what APIs can be called without explicit human approval. Full defence requires input sanitisation and prompt-level guardrails at the application layer — WIMSE addresses the credential binding, not the injection vector itself.
T10 · Unattested User Context (Human Impersonation)
An agent claims "I am acting on behalf of user@example.com" in a request header or API parameter. A downstream service accepts the claim and grants elevated access as if the human authorised the action — but there is no cryptographic proof of that authorisation.
The Transaction Token (txntoken+jwt) is issued by the gateway and carries the originating user's azp (authorising party) claim, signed by the gateway's key. Every downstream service validates the Txn-Token independently — the attacker cannot forge the user context without the gateway's signing key. The WPT tth claim cryptographically binds every hop to the same originating transaction.
T11 · Cross-Tenant Context Leakage
In a multi-tenant agent platform, an agent serving tenant A processes a prompt injection that causes it to include tenant A's credentials, tool output, or intermediate reasoning in a response or tool call that is later read by tenant B's session — breaching tenant isolation without any identity layer signal.
Partial mitigation: Each agent session has a fresh AgentToken with the tenant's SPIFFE ID in sub; CB4A credentials are minted per-session with session-scoped vault entries; the gateway validates SPIFFE ID against expected tenant on every call — a cross-tenant tool call would present the wrong SPIFFE ID and be rejected. Full defence requires application-layer session isolation and LLM context sandboxing that WIMSE complements but does not replace.
T12 · Delegation Scope Creep (Privilege Amplification)
An orchestrator delegates to a sub-agent and passes its full credential set. The sub-agent acquires the orchestrator's complete authority — not a reduced subset — and uses it to access resources it was never intended to reach. In multi-hop chains, each hop can amplify rather than reduce the scope of the previous hop.
chain_depth is validated strictly sequentially (0, 1, 2…) — no gaps or resets. The OpenFGA Authorizer evaluates every request against the sub-agent's own SPIFFE ID, not the chain as a whole. The sub-agent's permitted actions are defined at AgentToken issuance time by the IdP — the orchestrator cannot grant permissions it doesn't have, and cannot expand scope through delegation. Each hop in the chain can only reduce, not extend, authority.
Security Model Summary
  • 🔑
    Identity — Every agent has an EC P-256 key pair. The public key is bound into the AgentToken via cnf.jwk.
  • 🔗
    Delegation Chain — Multi-hop calls are represented as AT-1~AT-2~…~AT-N. Each hop's chain_depth is validated sequentially.
  • 📝
    Proof of Possession — Each request carries a short-lived agent-proof+jwt signed by the caller's private key, bound to the target URI and chain hash.
  • 🛡️
    Authorization — The Gateway enforces per-subject, per-tool, per-action authorization. can_call implies can_read; can_write implies can_read.
  • 🚫
    Replay Prevention — Every proof token has a unique jti. The Gateway's replay store ensures each token can only be used once within its validity window.
Cross-Organisation Agent Federation (OID-FED 1.0)

An agent from Org B calls a gateway controlled by Org A. The gateway has no static entry for Org B's IdP — it resolves the key dynamically via an OpenID Federation trust chain: Trust Anchor → Subordinate Statement → Entity Configuration.

⚓ Trust Anchor enterprise.example 🏢 Org B IdP idp.org-b.example 🤖 Org B Agent foreign agent 🛡️ Org A GW federation resolver SS (signed by anchor) SS
Run through the steps in order — each button unlocks the next. Click Restart to reset anytime.
Trust Anchor
Org B IdP
Authority Hint
Entity Configuration JWT — Org B IdP's self-signed statement
Loading…

Header red

Entity Configuration is Org B's self-signed statement (typ: entity-statement+jwt). It carries Org B's public key and an authority_hints list — the pointers that tell a resolver where to find the Trust Anchor that can certify this entity.
Org B Agent Token — issued by federated IdP
Loading…

Header

subject
issuer
Identical format, foreign issuer. This token is indistinguishable in format from a local agent token — it uses the same agent+jwt type and ES256. The only difference is the iss claim points to Org B's IdP rather than Org A's. The Gateway has no static config for this issuer — it must resolve it dynamically.
Trust Chain Resolution — Gateway Steps
Peek iss from token — not in static validator map
Fetch Entity Configuration from idp.org-b.example/.well-known/openid-federation
Follow authority_hints → Trust Anchor:
Fetch Subordinate Statement for Org B from Trust Anchor
Verify Subordinate Statement signature using anchor key ✓
Extract Org B's certified key from SS.JWKS — x=
Verify Entity Configuration with extracted leaf key ✓
Validate agent token with dynamically resolved key
Zero pre-configuration. Org A's Gateway accepted a token from Org B's agent with no static setup for Org B. The Trust Anchor's public key is the only prerequisite — from it, the resolver can dynamically certify any entity in the federation.
How it works
  • 1
    The Trust Anchor generates a key pair and signs a Subordinate Statement (SS) certifying Org B's IdP public key.
  • 2
    Org B's IdP publishes a self-signed Entity Configuration (EC) JWT at /.well-known/openid-federation with authority_hints pointing to the anchor.
  • 3
    Org B's agent is issued a standard agent+jwt — identical in format to a local agent token.
  • 4
    When the token arrives at Org A's Gateway, it peeks at iss, finds no static validator, and falls back to the Federation Resolver.
  • 5
    The resolver walks the chain: EC → authority_hints → SS → anchor key → SS signature verified → leaf key extracted → EC signature verified.
  • 6
    The token is validated with the dynamically-resolved key. No pre-shared keys or static config were needed for Org B.
Post-Quantum Safety for Agent Fabric

Agent Fabric tokens (agent+jwt), proof tokens (application/agent-proof+jwt), and OID-FED entity statements all use ES256 (EC P-256). Shor's algorithm on a quantum computer breaks EC in polynomial time — every delegation chain, every proof token, every trust chain becomes forgeable.

Harvest Now, Decrypt Later: Adversaries collecting today's inter-agent traffic can break the signatures retroactively once a cryptographically-relevant quantum computer (CRQC) is available (~2030–2035 estimates). Agent delegation chains are high-value targets — they encode full audit trails.
Quantum Computer vs. EC P-256 — Attack Simulation

EC P-256 relies on the Elliptic Curve Discrete Logarithm Problem: given public point Q = k·G, finding private key k requires ~2128 classical operations — infeasible. Shor's algorithm on a CRQC solves ECDLP in O(n³), extracting k in seconds.

EC P-256 Key Q = k·G public: Q known private: k hidden Classical Computer Baby-step Giant-step · ~2¹²⁸ ops infeasible 0% → heat death of universe Quantum CRQC Shor's Algorithm · QFT + period finding · O(n³) polynomial time 0% → seconds on CRQC Result awaiting simulation
① Both computers receive EC public key Q=k·G. Classical and quantum attempt to recover the hidden private key k.
② Classical: Baby-step Giant-step requires ~2¹²⁸ steps. EC P-256 security holds — progress stalls well below 1%.
③ CRQC: Shor's Algorithm uses QFT to find the discrete logarithm period. Private key k extracted — all past signatures forgeable.
Threat timeline
Now — 2028EC P-256 secure. Begin inventory of agent key material. Adopt hybrid-capable validators.
2028 — 2032Hybrid mode: agent+jwt carries both ES256 and ML-DSA-44 signatures. Both accepted by gateways.
2032+ES256-only agent tokens rejected. ML-DSA-44 mandatory for all chain links, proofs, and OID-FED JWTs.
NIST PQC 2024 standards — what replaces EC
Signature

ML-DSA (Dilithium)

Primary NIST recommendation. Lattice-based. Replaces ECDSA for all agent+jwt and proof+jwt signing.

Pub key1312 B vs 64 B (EC)
Signature2420 B vs 64 B
Used forAgentToken, ProofToken, OID-FED EC
KEM

ML-KEM (Kyber)

Replaces ECDH in TLS 1.3 key exchange. Protects the transport layer for mTLS agent-to-gateway connections.

Pub key1184 B vs 32 B (ECDH)
Ciphertext1088 B
Used formTLS key exchange (Phase 2 mTLS)
Hash-Based

SLH-DSA (SPHINCS+)

Conservative option. Only relies on hash function security. Ideal for Trust Anchor signing (long-lived, high-assurance).

Pub key32 B (small)
Signature8–50 KB
Used forOID-FED Trust Anchor subordinate statements
Three-Era Migration Roadmap — Live Progressive View

Click each era to explore the token structure, pros, cons, and required migration actions for that phase of the quantum transition.

Token Structure (agent+jwt)
{
  "typ": "agent+jwt",
  "alg": "ES256"
}.{
  "sub": "spiffe://cloud-a/agent",
  "cnf": { "jwk": { "kty":"EC",
    "crv":"P-256","alg":"ES256" } },
  "exp": ..., "jti": "..."
}
mTLS
TLS 1.3
ECDHE + ECDSA
EC P-256 cert
URI SAN: spiffe://...
Pros
Small tokens (~64B sig). Fast ES256 verification. Universal library support. Proven in production. No size overhead for JWT payloads.
Cons / Risks
Vulnerable to Shor's algorithm on CRQC. HNDL: today's traffic collectible for future decryption. Migration window opens ~2028.
Action items now: Inventory all agent key material. Upgrade validators to be alg-agnostic. Do NOT hardcode "alg":"ES256" checks — use allow-list validation.
Agent Fabric component impact
ComponentCurrentPQ-SafeMigration
AgentToken (agent+jwt)ES256ML-DSA-44Hybrid: both sigs during transition; validators accept either
AgentProofTokenES256 + cnf.jwk bindingML-DSA-44 + PQ cnf.jwkcnf.jwk becomes OKP key with ML-DSA curve
AgentChain linksEach AT-N: ES256Each AT-N: ML-DSA-44Chain validator must support both alg types per link
OID-FED Entity Configentity-statement+jwt ES256ML-DSA or SLH-DSA for Trust AnchorPublish both EC and PQ keys in JWKS during transition
mTLS agent certsEC P-256 X.509ML-DSA cert + ML-KEM key exchangeDual-cert: present both EC and PQ cert; server picks best
JTI replay storeIn-memory (single node)Distributed (Raft-replicated)JTI store upgrade is independent of PQ algorithm migration
Quantum Threat Model — Updated
ThreatVectorClassical RiskQuantum RiskMitigation
T-Q1: CRQC Key Extraction Shor's algorithm extracts EC P-256 private key from public point Q Low — 2¹²⁸ ops Critical — seconds on CRQC Migrate all agent keys to ML-DSA-44; deprecate ES256
T-Q2: HNDL — Delegation Chains Collect agent+jwt chains today; break sig keys post-CRQC; forge entire chains None High — full audit trail exposed + forgeable Deploy hybrid mode from 2028; PQ-only mandatory by 2032
T-Q3: HNDL — mTLS Sessions Record TLS handshakes; ECDH session secrets recoverable via Shor's once CRQC available None High — all past session secrets exposed Deploy ML-KEM-768 (X25519MLKEM768) for TLS key exchange
T-Q4: OID-FED Trust Chain Forgery Extract IdP signing key; issue fake subordinate statements; hijack entire federation Low Critical — entire trust graph collapses SLH-DSA for Trust Anchors; ML-DSA for subordinate statements
T-Q5: JTI Hash Weakening (Grover) Grover's algorithm halves SHA-256 pre-image resistance from 256 to 128 effective bits Negligible Medium — SHA-256 JTIs weaker but not broken Upgrade JTI generation to SHA-512 or use 256-bit cryptographic random UUIDs
T-Q6: Proof Token Forgery Recover workload private key via Shor's; generate valid agent-proof+jwt for any URI Low Critical — replay protection bypassed for all old proof tokens Migrate proof token cnf.jwk to OKP/ML-DSA; enforce short proof TTL ≤ 2 min
Agent Fabric advantage: Because each delegation link carries its own cnf.jwk, upgrading to PQ is link-by-link — you don't need to migrate all agents simultaneously. An orchestrator with an ML-DSA key can issue chains to executors that still use EC, and a mixed-alg chain can still be validated if the validator supports both.
Paxos / Raft Consensus for Agent Fabric

A production Agent Fabric IdP cluster runs multiple replicas. Without distributed consensus, the JTI replay store is per-node (replay attacks succeed by hitting different replicas), key rotation creates a split-brain window, and token revocation propagates with unpredictable delay.

ProblemWithout ConsensusWith Raft/Paxos
JTI replay across replicasReplay hits replica that hasn't seen the JTIJTI log replicated; replay rejected cluster-wide
AgentToken issuance in HATwo leaders race → duplicate JTIsOne Raft leader issues; committed before returning
Signing key rotationReplicas briefly serve old and new keysKey swap committed as Raft entry with activation time
Revocation propagationRevoked token accepted by lagging replicaRevocation log replicated; instant cluster-wide effect
OID-FED SS cache invalidationStale SS used after Trust Anchor updateCache invalidation event committed as Raft entry
Animated Paxos round — agent token issuance

Proposal value = {sub, chain_depth, cnf.jwk, jti, exp}. Proposer = IdP primary. Acceptors = IdP replicas. Quorum = 2 of 3.

Proposer idp-primary Acceptor 1 idp-replica-1 Acceptor 2 idp-replica-2 Prepare(n=1) Promise(n=1) Prepare(n=1) Promise(n=1) Accept(n=1,{jti,sub}) Accept(n=1,{jti,sub}) Click ▶ to begin
Phase 1a — Prepare(n) — Proposer broadcasts ballot number to all acceptors
Phase 1b — Promise(n) — Acceptors promise not to accept lower ballots; return any prior accepted value
Phase 2a — Accept(n, v) — Proposer has quorum, broadcasts token payload for acceptance
Phase 2b — Committed — Quorum accepted; agent+jwt issued; JTI recorded on all 3 replicas
Practical: Raft over Classic Paxos
Most deployments use Raft (Multi-Paxos equivalent with deterministic leader election). etcd, CockroachDB, and TiKV all use Raft. A 3-node or 5-node Agent Fabric IdP cluster backed by etcd (as used by Kubernetes) gets Raft consensus for free, including a replicated JTI store, consistent key rotation, and revocation log.
  • 1
    3 IdP replicas (or 5 for 2-failure tolerance). Raft leader handles all token issuance writes.
  • 2
    JTI written to Raft log before token returned to caller. All replicas see the same JTI history.
  • 3
    Key rotation committed as a Raft entry with a future activation timestamp. All replicas switch simultaneously.
  • 4
    Gateways subscribe to revocation SSE stream from Raft leader. Revoked JTIs propagated within one RTT.
mTLS Transport — Token-Cert Binding

Mutual TLS adds a transport-layer identity check on top of the application-layer token validation. Each agent presents an EC P-256 certificate with a SPIFFE URI SAN during the TLS handshake. The gateway verifies that cert.URI SAN[0] == AgentToken.sub — a stolen token is useless without the matching private key.

Shared-key design: The same EC P-256 key pair is used for (1) the mTLS client certificate, (2) the cnf.jwk in the AgentToken, and (3) the AgentProofToken signing key. Compromising the token alone is not enough — an attacker must also compromise the private key.
Happy Path — cert SAN = token sub
🔒 Agent GW Gateway Tool
1. mTLS handshake — agent presents cert
2. Gateway: cert SAN = token sub ✓
3. Request forwarded → 200 OK
Token Theft Attack — cert SAN ≠ token sub
Attacker GW Gateway Tool
1. mTLS handshake — attacker presents own cert
2. Gateway: cert SAN ≠ token sub ✗
3. Request rejected → 401 Unauthorized
Defence-in-depth comparison
ThreatWithout mTLSWith mTLS
Stolen AgentToken Thwarted by cnf.jwk proof (attacker needs private key) Double protection: cert binding also checked
Network eavesdropping Tokens visible in plaintext (HTTP) TLS 1.3 encrypted channel (AEAD)
Identity spoofing Prevented by IdP JWT signature Cert URI SAN additionally bound to token sub
MITM / downgrade Not prevented TLS 1.3 min-version, no downgrade possible
Emerging alternative: draft-ietf-wimse-http-signature would extend the proof mechanism to HTTP Message Signatures (RFC 9421), covering not just the URI but the full request including headers and body digest. This complements mTLS by adding application-layer binding even when TLS terminates at a proxy. Tracked for a future variant of pkg/identity/proof.go.
SCENARIO

Transaction Tokens

Each service in a multi-agent call chain sees an isolated request. Without a shared context token, there is no cryptographic way to link every hop back to the original user intent — making audit trails, authorization budgets, and per-transaction rate-limits impossible. Transaction Tokens (draft-ietf-oauth-transaction-tokens-11) solve this by issuing a signed JWT at the entry point that propagates unchanged through the entire chain.

Call chain with Txn-Token propagation
User alice@corp OIDC token TTS Transaction Token Service issues txntoken+jwt txn=uuid, sub=alice Orchestrator spiffe://.../orch WIT + proof (tth set) Service B spiffe://.../svc-b WIT + proof (tth set) Service C spiffe://.../svc-c verifies tth ✓ txntoken+jwt tth bound tth bound

The Txn-Token is issued once at the entry point and forwarded unchanged at every hop. Each agent attaches a fresh agent-proof+jwt with tth = SHA-256(txntoken), cryptographically binding the per-request proof to the originating transaction.

Live flow — Txn-Token propagation & tth binding
User OIDC TTS issues txn Orch proof+tth Svc B proof+tth Svc C validates tth

Click a button to start the flow.

① User → TTS — OIDC token initiates transaction
② TTS → Orch — txntoken+jwt issued with txn ID & sub
③ Orch → Svc B — agent-proof+jwt with tth = SHA-256(txntoken)
④ Svc B → Svc C — same txntoken + fresh tth-bound proof
Txn-Token structure (txntoken+jwt)
// Header
{
  "alg": "ES256",
  "typ": "txntoken+jwt"
}

// Payload
{
  "iss": "https://tts.example",
  "sub": "alice@corp",
  "aud": ["https://api.example"],
  "txn": "a3f8-b12c-…",    // unique txn ID
  "rctx": {
    "req_ip": "10.0.0.1",
    "req_wl": "spiffe://.../orch"
  },
  "azd": [{ "type": "payment" }]
}
AgentProofToken with tth binding
// Header
{
  "alg": "ES256",
  "typ": "application/agent-proof+jwt"
}

// Payload
{
  "aud": "https://svc-b.example/api",
  "chain_hash": "SHA-256(chain)",
  "tth": "SHA-256(txntoken)",  // ← binds to txn
  "jti": "unique-per-request",
  "exp": 1753649999
}
Architecture decision — why implement Txn-Token?
Problem without Txn-Token How Txn-Token resolves it Tradeoffs
No cryptographic link between hop-level proofs and the original user request — audit logs show isolated events txn ID is the same across all hops; every tth binding anchors the proof to the same JWT Cons:
  • New service dependency: TTS must be highly available
  • Token is forwarded at every hop (overhead per request)
  • Spec still at draft-11 — rctx / azd field names may change before RFC
  • Services must be updated to propagate the Txn-Token header

Pros:
  • Single source of truth for user context across the chain
  • Authorization budget / rate-limit can be enforced per-transaction
  • Non-repudiable audit trail — txn ID links all log entries
  • No PII duplication in per-hop tokens — only sub + scoped azd
Authorization context (scopes, budget, RAR details) known only at entry point — downstream services cannot verify intent azd claim carries Rich Authorization Requests details from the AS; any service can inspect them
A compromised intermediate agent can forge its own proof and claim it's acting on behalf of the user tth in AgentProofToken must match the TTS-issued Txn-Token — the intermediate cannot forge this binding without the Txn-Token private key
Call-chain scoping: an agent could reuse a proof in a different transaction context The txn ID is unique per transaction; the receiving service checks both tth and jti, ensuring the proof is scoped to exactly one request in one transaction
Implementation: pkg/txntoken
Issuer
issuer := txntoken.NewIssuer(
  "https://tts.example",
  ttsKey, time.Minute*5,
)
tok, _ := issuer.Issue(txntoken.IssueOptions{
  Subject:   "alice@corp",
  Audiences: []string{"https://api.example"},
  ReqCtx: &txntoken.RequestContext{
    ReqIP: "10.0.0.1",
    ReqWL: "spiffe://.../orch",
  },
})
Proof with tth
proof, _ := identity.GenerateProof(
  identity.ProofGenerateOptions{
    TargetURI:   "https://svc-b.example",
    Chain:       chain,
    WorkloadKey: agentKey,
    TxnToken:    tok,  // tth auto-set
  },
)

// Validator: verify tth
pv.Validate(identity.ProofValidateOptions{
  ...,
  TxnToken: tok,
})

10 new tests in pkg/txntoken/txntoken_test.go and 3 in pkg/identity/identity_test.go cover happy path, typ header, txn ID propagation, authorization details round-trip, wrong key, expiry, issuer mismatch, hash determinism, and tth mismatch.

SCENARIO

SPIFFE Client Authentication

Agents already hold an AgentToken (agent+jwt) that proves their SPIFFE identity. Traditional OAuth client authentication requires pre-shared secrets — a rotation burden that breaks in ephemeral agent environments. SPIFFE Client Auth (draft-ietf-oauth-spiffe-client-auth-02) lets the agent use its existing token as a client assertion to authenticate to any OAuth 2.0 AS, eliminating secrets entirely.

OAuth 2.0 client_credentials with JWT bearer assertion
IdP / SPIRE idp.agent-mesh.example issues agent+jwt signed with IdP key Agent spiffe://.../agents/orch holds: AgentToken OAuth AS token endpoint grant_type=client_credentials validates AgentToken sig Resource API protected endpoint Bearer token in header ①agent+jwt ②client_assertion jwt-bearer assertion type ③Bearer access_token ④Authorization: Bearer

No pre-shared client secret anywhere in the flow. The OAuth AS validates the AgentToken's signature against the IdP's public key — the same key it already trusts for workload identity.

Live flow — secret-free client authentication
IdP SPIRE Agent spiffe://.. OAuth AS API resource

Click Play to start.

① IdP issues agent+jwt — SPIFFE identity, signed with IdP key, no secret
② Agent → OAuth AS — client_assertion = agent+jwt, grant_type = client_credentials
③ AS validates AgentToken sig via IdP JWKS — issues Bearer access_token
④ Agent calls Resource API — Authorization: Bearer <access_token>
OAuth request (POST /token)
# application/x-www-form-urlencoded
grant_type=client_credentials
client_assertion_type=urn:ietf:params:oauth:
  client-assertion-type:jwt-bearer
client_assertion=<compact AgentToken JWT>
scope=read:tasks write:results

# Response
{
  "access_token": "<opaque 32-byte bearer>",
  "token_type":   "Bearer",
  "expires_in":   3600,
  "sub":          "spiffe://.../agents/orch"
}
Authenticator — AS-side validation
// pkg/spiffeclientauth
auth := spiffeclientauth.NewAuthenticator(
  "https://as.example",
  identity.NewAgentValidator(
    "https://idp.example",
    idpPub,
  ),
  time.Hour,
)

tok, err := auth.Authenticate(
  spiffeclientauth.AuthRequest{
    ClientAssertion:     agentToken,
    ClientAssertionType: "urn:…:jwt-bearer",
    Scope:               "read:tasks",
  },
)
// tok.Sub == "spiffe://.../agents/orch"
Architecture decision — why implement SPIFFE Client Auth?
Problem without it How SPIFFE Client Auth resolves it Tradeoffs
Agents need OAuth access tokens to call APIs — requires registering a client_id + secret that must be rotated Use the existing AgentToken as a client_assertion — no registration, no secrets, no rotation Cons:
  • AS must be updated to verify SPIFFE JWT assertions (new code path)
  • Spec at draft-02 — assertion type URN and validation rules may still change
  • Returned Bearer token is opaque — AS must remain available to introspect

Pros:
  • Zero credential rotation — AgentToken TTL handles revocation
  • Works with any RFC 7523 compatible AS with a plugin
  • SPIFFE ID preserved as sub in Bearer token response
  • Reuses existing IdP trust — no new PKI required
Secret sprawl — each agent deployment needs a unique client_secret, stored in environment or vault The SPIFFE identity of the agent is the credential — no additional secret material needed
Minted tokens carry no agent identity — API can't tell which agent made the call sub claim in the access token response carries the SPIFFE ID, enabling per-agent authorization and audit
Implementation: pkg/spiffeclientauth

8 tests in pkg/spiffeclientauth/spiffeclientauth_test.go cover happy path, token uniqueness per call, wrong assertion type, empty assertion, tampered AgentToken, expired token, issuer mismatch, and empty scope passthrough.

Backwards compatible: existing pkg/identity and internal/gateway packages are unchanged. pkg/spiffeclientauth is an independent add-on that any OAuth AS endpoint can integrate.
SCENARIO

Identity Chaining

An agent in Cloud A holds a SPIFFE identity token issued by Cloud A's IdP. When it needs to call a service in Cloud B, Cloud B's AS won't accept Cloud A's token — different trust domains, different signing keys. Identity Chaining (draft-ietf-oauth-identity-chaining-17) bridges this gap with a JWT Authorization Grant that cross-domain services can validate without pre-configuring shared secrets between the two AS instances.

Cross-trust-domain agent identity propagation
CLOUD A (trust domain: cloud-a.example) CLOUD B (trust domain: cloud-b.example) Agent spiffe://cloud-a.example /agents/orchestrator AS — Cloud A validates agent+jwt issues jwt-authz-grant signed with domainA key aud = Cloud B endpoint AS — Cloud B validates jwt-authz-grant checks iss, aud, exp, sub extracts SPIFFE ID issues Cloud B token Service B protected endpoint cloud-b trust domain ① agent+jwt ② jwt-authz-grant ③ jwt-authz-grant cross-domain ④ Cloud B token ⑤ API call

Cloud B only needs Cloud A's public signing key — no pre-shared secret between the two AS instances. The agent's SPIFFE ID flows through the grant's sub claim, giving Cloud B full auditability of cross-domain calls.

JWT Authorization Grant (jwt-authz-grant)
// Header
{
  "alg": "ES256",
  "typ": "jwt-authz-grant"
}

// Payload
{
  "iss": "https://as.cloud-a.example",
  "sub": "spiffe://cloud-a.example/agents/orch",
  "aud": ["https://as.cloud-b.example/token"],
  "iat": 1753649000,
  "exp": 1753649300,   // 5 min TTL
  "jti": "kY2mNpXx…"     // replay prevention
}
Go implementation — pkg/identitychaining
// Domain A: issue grant
gi := identitychaining.NewGrantIssuer(
  "https://as.cloud-a.example",
  domainAKey, agentValidator,
  5*time.Minute,
)
grant, _ := gi.Issue(
  agentToken,
  "https://as.cloud-b.example/token",
)

// Domain B: validate grant
gv := identitychaining.NewGrantValidator(
  "https://as.cloud-a.example",
  domainAPub,
)
claims, _ := gv.Validate(
  grant,
  "https://as.cloud-b.example/token",
)
// claims.Subject == "spiffe://cloud-a.../agents/orch"
Architecture decision — why implement Identity Chaining?
Problem without it How Identity Chaining resolves it Tradeoffs
Agent in cloud-a.example cannot authenticate to cloud-b.example APIs — their IdPs have different signing keys and different trust domains Domain A's AS issues a jwt-authz-grant that is addressed specifically to domain B's token endpoint — domain B validates it with only domain A's public key Cons:
  • Two round-trips before the first API call (get grant, exchange for B token)
  • Domain B must pre-configure domain A's public key
  • Spec at draft-17 — may still evolve before RFC
  • Short-lived grants (5 min) — agent must refresh for long-running tasks

Pros:
  • Zero pre-shared secrets between domains
  • SPIFFE ID preserved across the domain boundary — full audit trail
  • jti prevents grant replay attacks
  • Short grant TTL limits blast radius if a grant is intercepted
Token exchange via RFC 8693 requires domain A and B to share infrastructure or a common token exchange service The JWT grant is self-contained and cryptographically verifiable — domain B needs no connection to domain A beyond the initial public key exchange
Cross-domain calls lose the agent's SPIFFE identity — cloud B sees an opaque service token sub in the grant carries the original SPIFFE ID; cloud B can use it for per-agent authorization and audit
Implementation: pkg/identitychaining

10 tests in pkg/identitychaining/identitychaining_test.go cover the happy path, typ header verification, audience mismatch, wrong signing key, expired grant, issuer mismatch, invalid AgentToken, missing subject/audience inputs, and a full end-to-end cross-domain flow.

Backwards compatible: pkg/identity, pkg/spiffeclientauth, and internal/gateway are unchanged. pkg/identitychaining is an independent package that layers on top of the existing AgentValidator.
Related standards — tracked, not yet implemented
Formalises the problem statement and requirements for cross-organisational delegation of workload and agent identities. As this draft matures it may introduce normative constraints on delegation claim schemas and trust chain validation that will affect pkg/identitychaining and pkg/identity/chain.go.
Introduces an identity propagation context token/claim that travels unchanged through multi-hop OAuth delegation chains. Conceptually extends what pkg/identitychaining carries today: in a future revision, the grant token could embed a propagation-context claim linking every hop back to the originating user intent.
CB4A — Credential Broker for Agents

Implementing draft-hartman-credential-broker-4-agents-00 (March 2026) in Go — compiled to WASM. All JWT signing, PDP evaluation, CDP minting, DPoP binding and verification run live in your browser.

CB4A solves AI agent credential sprawl: AI agents increasingly need to call external APIs (Stripe, GitHub, AWS, databases). Injecting long-lived API keys into agents creates massive exposure. CB4A introduces a Policy Decision Point (PDP) that evaluates every credential request, and a Credential Delivery Point (CDP) that mints short-lived, DPoP-bound tokens from a vault. Agents never hold real credentials.

WIMSE Agent Fabric handles who the agent is:
AgentToken (agent+jwt) + SPIFFE SVID prove agent identity to the gateway. Delegation chains show the full call path. mTLS binds cert to token.
CB4A handles what credentials the agent may use:
The agent presents its SPIFFE SVID in the Task Request Envelope. CB4A's PDP evaluates the request; the CDP mints a short-lived DPoP-bound token from the vault. The base secret never leaves the vault.
PDP — Policy Decision Point
Evaluates every request against policy rules. Routes to Tier 1 (auto), Tier 2 (human), or Tier 3 (MFA). Zero credential access — policy authority only.
CDP — Credential Delivery Point
Verifies signed PDP decisions. Mints short-lived DPoP-bound tokens from HSM-backed vault. Zero policy authority — credentials only.
DPoP — Sender Constraint (RFC 9449)
Fresh ephemeral key pair per mint. JWK thumbprint in token cnf.jkt. Per-request DPoP proof with htm, htu, ath. Stolen tokens are useless.
Protocol Architecture
Agent SPIFFE SVID signs TRE PDP policy engine zero-cred access CDP mints DPoP token zero-policy access Vault HSM / KMS CDP access only External API Stripe / AWS / GitHub / DB TRE JWT Decision JWT base cred DPoP token DPoP-bound token returned to agent
① Agent signs Task Request Envelope (TRE JWT, typ: tre+jwt)
② PDP evaluates policy — routes to Tier 1/2/3; issues signed Decision JWT
③ CDP verifies Decision, retrieves base cred from vault, mints DPoP-bound token
④ Agent calls External API: Authorization: DPoP <token> + DPoP: <proof>
Tier 1 — Auto-Approved
Instant approval. No human action. Low-risk scopes: read-only access to non-production data.
Example: analytics:events:read
Tier 2 — Human-in-the-Loop
Request parked. Human reviews via dashboard and approves/denies async. Audit records approver identity.
Example: billing:invoices:write
Tier 3 — FIDO2 / MFA
Synchronous MFA required. Approver must complete FIDO2 challenge before decision is issued. Highest-risk operations only.
Example: admin identity + any scope
Live Interactive Demo — Real Go WASM (pkg/cb4a)

Click Initialize to boot the CB4A system in your browser. Ephemeral PDP signing keys are generated, a CDP is wired to an in-memory vault pre-seeded with 5 credential scopes, and an immutable audit log is created. No network calls — all Go code runs via WASM.

Why CB4A? Comparison with Other Credential Management Approaches

AI agents need credentials to call external APIs. How you manage those credentials determines your blast radius when an agent is compromised. Here's how CB4A compares — and where it complements tools you already have.

Approach Agents hold real creds? Per-request policy? Human approval? Token binding? Immutable audit?
Static Secrets
env vars / baked into containers
Always — in memory, logs, cores None None None None
HashiCorp Vault
agent retrieves secret via API
⚠ Briefly (after retrieval) None post-retrieval None None ⚠ Vault access log only
1Password / AWS Secrets Mgr
cloud-native secret stores
⚠ Briefly (after retrieval) None post-retrieval None None ⚠ Access log only
CB4A
brokered credential issuance
Never — DPoP token only Every request — PDP evaluates Tiered: auto / HITL / FIDO2 MFA DPoP RFC 9449 (cnf.jkt) Append-only, fail-closed

Deployment Scenarios

CB4A superior

Migrating from Static Secrets

API keys baked into Docker images or injected as env vars are the worst credential pattern. Any agent compromise, log leak, or process dump exposes the key with no TTL and no scope constraint.

CB4A replaces key injection entirely. Agents authenticate with their SPIFFE SVID and receive short-lived, scoped, DPoP-bound tokens per request. The API key never leaves the vault. A compromised agent can only use its current token until expiry — and only for the approved scope and URI.

Migration: Vault stores the old API keys; CB4A's CDP becomes the only caller. Agents get new binaries that call CB4A instead of env vars.
Complementary with Vault

HashiCorp Vault Already Deployed

Your team already uses Vault for secret storage — dynamic secrets, PKI, KV v2. Agents currently call vault read secret/api-key and use the returned value directly. The problem: after retrieval, the agent holds a long-lived credential Vault can't revoke without a full rotation.

CB4A adds the governance layer Vault lacks. The CDP is the only entity in Vault's access policy for the credential paths. Agents call CB4A, not Vault. CB4A adds: per-request PDP evaluation, DPoP sender-constraint (stolen token useless), tiered human approval for sensitive scopes, and an immutable audit trail correlating request → decision → API usage.

Integration: Replace vault policy: agent-read with cdp-only-read. No secret migration needed — Vault stays as the HSM backend.
Complementary with Cloud SM

AWS Secrets Manager / 1Password for Business

Cloud-native secret stores offer rotation, cross-region replication, IAM policies, and audit logs. Agents use SDK calls to retrieve credentials at startup or per-request. But retrieval still hands the raw credential to the agent process — post-retrieval exposure is identical to static secrets.

CB4A uses your cloud SM as the vault backend. The CDP reads from AWS Secrets Manager or 1Password's API. Your existing secrets, rotation schedules, and IAM policies remain unchanged. What changes: agents never call AWS SM directly; they call CB4A. The cloud SM IAM policy restricts direct access to the CDP service account only. CB4A adds per-request approval, DPoP binding, and cross-agent correlation that cloud SM audit logs cannot provide.

Integration: Create a CDP service account with read-only access to specific secret paths. All other IAM entities denied. Zero migration cost for existing secrets.
Bottom line: If you already run Vault or AWS Secrets Manager, CB4A is an upgrade path, not a replacement. Your stored credentials stay where they are — CB4A's CDP becomes the exclusive caller, adding per-request governance on top of your existing investment. The more sensitive the AI agent's scope, the higher the value of CB4A's tiered approval.
What the draft proposes
A Credential Delegation Protocol for AI Agents being developed in IETF WIMSE WG. It proposes a typed delegation token model — agents explicitly delegate specific credentials to sub-agents, producing a verifiable delegation chain. The delegating agent signs a delegation token scoped to the sub-agent's SPIFFE identity.
CB4A vs. CredDelegation
CB4A takes a broker approach: agents request credentials from a central PDP/CDP, which evaluates policy and mints ephemeral tokens. CredDelegation takes a chain approach: the parent agent creates a signed delegation token on-the-fly. CB4A enforces central governance + human-in-the-loop; CredDelegation is lighter-weight but requires trust in the delegating agent. These may be complementary layers — CB4A for acquiring root credentials, CredDelegation for sub-agent propagation.

Status: monitoring. Tracked in standards-baseline.json as draft-sweeney-wimse-credential-delegation.

x402 + WIMSE: Pay-per-Call APIs for AI Agents

Integrating the x402 HTTP payment protocol with WIMSE Agent Fabric + CB4A. Instead of EVM wallet signatures, agents present CB4A-DPoP credentials as payment authorization — fully cryptographically bound to the paying agent's SPIFFE identity.

AI agents increasingly need to call pay-per-use APIs (data, compute, external tools). x402 standardises HTTP-level payment — but who is authorising the spend? WIMSE + CB4A answer this: the PDP evaluates spending authority, the CDP mints a short-lived DPoP-bound payment credential, and the WIMSE AgentToken cryptographically proves which agent authorised each payment.

x402 — HTTP Payment Layer
Server returns 402 Payment Required + PaymentRequired JSON. Agent retries with X-Payment header. No blockchain required in this implementation.
CB4A — Spending Authority
PDP evaluates every payment request. Tier 1 (auto, ≤50 credits), Tier 2 (HITL, >50). CDP mints a DPoP-bound credential with scope payment:ASSET:AMOUNT. No raw secrets ever leave the vault.
WIMSE — Payer Identity
AgentToken (agent+jwt) is included in every payment payload. Gateway verifies that the token's sub matches the CB4A agent_svid. Cryptographic proof of payer identity — no impersonation.
Protocol Flow
Agent SPIFFE SVID AgentToken API Server x402-protected PaymentGateway PDP policy engine T1 auto / T2 HITL CDP credential vault DPoP-bound token Vault payment tokens never exposed ① GET 402 ② request auth ③ decision ④ fetch ⑤ DPoP-bound payment cred ⑥ X-Payment → 200
Live Demo — Full Payment Flow

All cryptography runs in your browser via WASM. Real EC P-256 keys, real JWTs, real DPoP proofs.

Payment Audit Trail
TimeEventAgentScopeTierStatus
No events yet
Security Properties
No Double-Spend
DPoP proof includes a unique jti. The PaymentGateway tracks consumed proofs — replaying the same payment payload is detected and rejected immediately.
Payer Binding
WIMSE AgentToken sub must match CB4A agent_svid. An agent cannot present another agent's CB4A credential — identity and spending authority are cryptographically linked.
Scope Enforcement
Payment credentials are scoped to a specific asset and amount (payment:AGENT_CREDIT:50). The PDP enforces spending tiers. Agents cannot self-escalate their payment limits.
Agent Auth Standards Landscape

Comparing four emerging approaches to AI agent authentication and authorization: XAA (Cross App Access), AAuth (Agent Authorization), CB4A (Credential Broker for Agents), and WIMSE (Workload Identity in Multi-System Environments).

These are complementary, not competing — each solves a different layer of the agent auth problem. An enterprise agent deployment may use all four simultaneously.

WIMSE
Agent ↔ Agent identity
JWT chains, mTLS, OpenFGA authz. The internal service mesh identity layer.
IETF WG · Active
CB4A
Agent → External API creds
PDP/CDP split, vault-backed, tiered approval. Credential brokering layer.
Individual draft · March 2026
AAuth
Agent cryptographic identity
HTTPSig, agent_token, per-call intent. Replaces API keys with signatures.
Dick Hardt · In development
XAA
App-to-app delegation
OAuth extension, ID-JAG token. Eliminates consent prompts for enterprise agent flows.
xaa.dev · RFC 8693 / RFC 7523
XAA — Cross App Access xaa.dev

XAA extends OAuth to let an enterprise Identity Provider manage app-to-app connections without per-user consent prompts. It implements the Identity Assertion Authorization Grant (ID-JAG) — pre-authorized by enterprise policy, no user interaction after initial setup.

The Problem
Autonomous agents calling OAuth-protected APIs trigger repeated consent screens. This drives users to share credentials or use unauthorized tools. Traditional OAuth wasn't designed for non-interactive agents.
The Solution
Enterprise IdP issues a pre-authorized ID-JAG delegation token replacing user consent. The Authorization Server accepts it and issues a scoped Bearer token — zero user interaction after initial enterprise policy setup.
App / Agent Auth Code + PKCE Identity Provider enterprise IdP issues ID-JAG Auth Server validates ID-JAG issues Bearer token Resource Server OAuth-protected API standard Bearer ① Auth Code + PKCE ② ID-JAG delegation ③ Bearer token
① Agent authenticates to IdP with Auth Code + PKCE — standard OAuth login flow
② IdP issues ID-JAG delegation token — pre-authorized by enterprise admin, no user consent prompt
③ Auth Server validates ID-JAG, issues scoped Bearer token — agent calls Resource API
Best for
Agents calling OAuth-protected APIs on behalf of enterprise users — Salesforce, Workday, Google Workspace. Eliminates consent friction in automated workflows.
Standards basis
RFC 8693 (Token Exchange), RFC 7523 (JWT Bearer), RFC 6750 (Bearer Token). Builds on proven OAuth 2.0 infrastructure — no new runtime required.
Limitation
Delegates on behalf of a user, not the agent itself. No agent-specific cryptographic identity, no credential isolation, no per-request policy engine.
AAuth — Agent Authorization Protocol aauth.dev · Dick Hardt

AAuth is an HTTP authorization protocol where every agent gets its own cryptographic identity via HTTPSig and a signed agent_token. Created by Dick Hardt (OAuth 2.0 original author). Coexists with OAuth 2.0 / OIDC rather than replacing them.

The Problem
Traditional OAuth assumes clients built against known APIs. AI agents assemble tool chains at runtime against unfamiliar services. API keys leak. Scopes don't capture per-call intent. Mid-task authorization (pending consent) is treated as an error, not a valid state.
The Solution
Each HTTP client holds a unique agent_token (cryptographic identity). Requests are signed with HTTPSig. Resources issue resource_token describing requirements; person servers issue auth_token granting access. Pending is a first-class state — not an error.
Four Access Modes (incrementally adoptable)
Mode 1 — Identity
Agent signs request with HTTPSig + agent_token. Resource verifies directly. No intermediary required.
Mode 2 — Resource
Resource issues tokens for agent access. Resource controls its own authorization policy independently.
Mode 3 — Person
Person server mediates consent, issues auth_token. Mid-task consent with pending states natively supported.
Mode 4 — Federated
Cross-domain authorization across organizations. Agent identity travels between services and trust domains.
Agent agent_token HTTPSig per-call intent Resource verifies sig issues resource_token (needs person auth) Person Server consent / pending issues auth_token mid-task support Protected API validates auth_token + HTTPSig verify grants access ① HTTPSig + agent_token ② resource_token (needs person) ③ auth_token granted
① Agent signs HTTP request with HTTPSig using agent_token. Request carries per-call intent — not just a static scope.
② Resource verifies sig, determines consent needed. Issues resource_token describing requirements. Agent receives a pending state (not an error).
③ Person server mediates consent, issues auth_token. Agent retries with auth_token — access granted by Protected API.
Key Differentiator
Every agent has real cryptographic identity. Requests carry intent, not just scope. Mid-task consent is a first-class state — not an error to be handled by retry logic.
Standards basis
HTTPSig (RFC 9421), JWK, JOSE. By Dick Hardt — OAuth 2.0 original author. Complements rather than replaces OAuth/OIDC — designed for coexistence.
Current state
In active development. Not yet an IETF WG document. Reference implementation at aauth.dev. Protocol details may change — early adopter stage.
Four-Way Comparison Matrix
Dimension WIMSE CB4A AAuth XAA
Primary problem Agent-to-agent identity chains External API credential sprawl Agent lacks cryptographic identity OAuth consent friction for agents
Agent identity AgentToken JWT (ES256, cnf.jwk) SPIFFE SVID via SPIRE agent_token + HTTPSig signing Inherited from user OAuth session
Token type(s) agent+jwt, agent-proof+jwt tre+jwt, pdp-decision+jwt, cb4a-token+jwt agent_token, resource_token, auth_token ID-JAG delegation + standard Bearer
Token binding cnf.jwk (mandatory) DPoP RFC 9449 (cnf.jkt) HTTPSig per-request (per-call) None — standard Bearer token
External API access → CB4A handles this Core use case — vault-backed Yes — any HTTP resource Yes — OAuth-protected only
Human approval None Tier 1/2/3 (auto / HITL / MFA) First-class pending / consent state ⚠ Initial setup only
Mid-task auth states None ⚠ Via HITL approval queue Native pending state support None
Cross-domain ⚠ Via OID-FED exchange ⚠ Trust domain scoped Mode 4 federated Enterprise IdP federation
Credential isolation N/A — no external creds Vault-backed, agents hold tokens not secrets No shared secrets — signatures only Bearer token held by agent
Infrastructure cost Low — IdP + Gateway High — SPIRE + PDP + CDP + Vault Medium — identity + person servers Low — existing enterprise IdP
Standards status IETF WIMSE WG (active) Individual draft, March 2026 Draft by Dick Hardt, in dev xaa.dev · RFC 8693 / RFC 7523
How They Fit Together — Complementary Layers

These four standards are not alternatives — they solve different problems at different layers. A mature agent deployment uses whichever combination its architecture requires.

Agent-to-Agent Identity — WIMSE (this project)
Agent-to-agent calls use AgentTokens (agent+jwt) + AgentProofTokens. JWT delegation chains prove the full call path. mTLS cert-token binding. SPIFFE SVID as the universal identifier across all layers.
External API Credentials — CB4A (this project)
When agents call external APIs (Stripe, GitHub, AWS), CB4A brokers short-lived DPoP-bound tokens from an HSM-backed vault. The agent's WIMSE SVID authenticates the request. Base secrets never touch the agent.
Per-Call Agent Authorization — AAuth
AAuth gives agents cryptographic identity via agent_token + HTTPSig, with native support for mid-task consent states (pending/approved/denied). Complements WIMSE for HTTP-native agent environments.
Enterprise App Delegation — XAA
XAA extends OAuth for enterprise app-to-app delegation without per-user consent prompts. When agents call OAuth-protected SaaS (Salesforce, Workday), XAA handles delegation. Complements CB4A for OAuth resources.
Practical example: A billing agent uses WIMSE to call the internal invoice service, CB4A to broker a short-lived Stripe API token from the vault, XAA to read customer data from Salesforce without a consent prompt, and AAuth for per-call authorization when the resource server requires explicit intent. None of these overlap — each covers a distinct part of the problem.
Standards Tracker

This PoC implements eleven IETF and OpenID standards — most of them active drafts still evolving toward production readiness. A GitHub Actions workflow checks the IETF Datatracker API daily and opens a labelled issue when any revision changes. The Impl. commit column links to the exact commit that last implemented or verified compatibility with that draft revision.

Last checked: 2026-08-02  ·  standards-baseline.json  ·  standards-tracker.yml

Individual Draft
WG Draft
Last Call
Published / Final
Obsoleted
PoC status:   ✓ Implemented — Go code + animated demo   ◌ Monitoring — tracked, not yet built   ✗ Excluded — out of scope (reason in docs/standards-tracking.md)
Standard Working Group IETF Status PoC Status Rev Files PoC impact Impl. commit
WIT — Workload Identity Credentials IETF WIMSE WG ● WG Draft ✓ Implemented -02 pkg/identity/token.go, pkg/identity/chain.go AgentToken (agent+jwt) extends WIT — any cnf.jwk or typ changes affect pkg/identity 12a6936
WPT — Workload Proof Token IETF WIMSE WG ● WG Draft ✓ Implemented -01 pkg/identity/proof.go, internal/gateway AgentProofToken (application/agent-proof+jwt) — aud, wth, tth=SHA-256(Txn-Token), jti ed3bd65
Txn-Token — OAuth 2.0 Transaction Tokens IETF OAuth WG ● WG Draft ✓ Implemented -11 pkg/txntoken, pkg/identity (tth) typ=txntoken+jwt, propagates user identity + authz context through agent chains; tth binds AgentProofToken to the originating transaction ed3bd65
Identifiers — Workload Identifier IETF WIMSE WG ● WG Draft ✓ Implemented -03 pkg/identity/token.go, pkg/keys/mtls.go SPIFFE URI format for agent SVIDs — spiffe://trust-domain/path 12a6936
mTLS — Mutual TLS Binding IETF WIMSE WG ● WG Draft ✓ Implemented -02 pkg/keys/mtls.go, internal/gateway/server.go Token-cert binding in gateway middleware — URI SAN matching against AgentToken sub 73f519b
Arch — WIMSE Architecture IETF WIMSE WG ● WG Draft ✓ Implemented -08 pkg/identity/chain.go, internal/gateway Token exchange, trust domain boundaries, delegation chain semantics 018b9d8
CB4A — Credential Broker for Agents Individual (S. Hartman) ● Individual draft ✓ Implemented -00 pkg/cb4a TRE JWT, PDP decision JWT, CB4A token, Tier model, DPoP binding via cnf.jkt 77d0232
DPoP — OAuth 2.0 Demonstrating Proof of Possession IETF OAuth WG ● Published RFC ✓ Implemented RFC 9449 pkg/cb4a/cdp.go DPoP proof JWT (dpop+jwt), cnf.jkt thumbprint, ath binding, jti replay protection in CDP 77d0232
OID-FED — OpenID Federation 1.0 OpenID Foundation ● Published (OIDF) ✓ Implemented 1.0-41 pkg/federation, internal/gateway/multivalidator.go Entity Configuration, Subordinate Statement, authority_hints, chain resolution for cross-org AgentToken validation dd5b164
SPIFFE Client Auth — JWT-bearer OAuth assertion IETF OAuth WG ● WG Draft ✓ Implemented -02 pkg/spiffeclientauth AgentToken as client_assertion (urn:…:jwt-bearer) — eliminates pre-shared OAuth client secrets for agent workloads 018b9d8
Identity Chaining — JWT Authorization Grant IETF OAuth WG ● WG Draft ✓ Implemented -17 pkg/identitychaining typ=jwt-authz-grant, cross-trust-domain propagation of agent SPIFFE IDs; aud=target AS endpoint, jti replay protection 018b9d8
JWT-BCP — JWT Best Current Practices IETF OAuth WG ● Active BCP ✓ Implemented bis All validator files Compliance audit 2026-08-02: all parsers now enforce WithValidMethods(ES256), WithExpirationRequired, WithIssuedAt, and typ header checks — mitigates algorithm confusion, alg:none, and missing-exp attacks 9d73ac4
HTTP-Sig — WIMSE HTTP Message Signature Auth IETF WIMSE WG ● WG Draft ◌ Monitoring pkg/identity/proof.go (future) Alternative to AgentProofToken using RFC 9421 HTTP Message Signatures — tracked as potential replacement for JWT-based proof if WG adopts as primary mechanism monitoring
CredDelegation — Credential Delegation Protocol for AI Agents IETF WIMSE WG ● Individual draft ◌ Monitoring pkg/cb4a (future) Competing/complementary approach to CB4A for AI agent credential delegation — introduces typed delegation tokens; noted in Credential Broker tab monitoring
CrossOrgDelegation — Cross-Org Workload Delegation IETF WIMSE WG ● Individual draft ◌ Monitoring pkg/identitychaining, pkg/identity/chain.go Formalises cross-org delegation requirements — informs AgentChain semantics and Identity Chaining scenario monitoring
PropagationContext — Multi-Hop Identity Context IETF OAuth WG ● Individual draft ◌ Monitoring pkg/identitychaining, pkg/txntoken Multi-hop identity propagation context travelling with delegation chains — future extension of Identity Chaining and Txn-Token scenarios monitoring
Automated tracking — how it works
Daily cron — 09:00 UTC
GitHub Actions runs scripts/check_standards.py each morning. The script queries the IETF Datatracker REST API for each tracked draft and compares the returned rev field against standards-baseline.json.
Revision detected → baseline committed
When a new revision appears, last_known_rev is updated and committed with [skip ci]. A developer manually sets implemented_rev in the baseline file after updating the Go code to match the new revision.
GitHub issue created automatically
A standards-update labelled issue lists the new revision, PoC impact, affected files, and a checklist: read the IETF diff, check for breaking typ / claim / header changes, update the Go implementation, bump implemented_rev.
RFC and manual-only standards: DPoP is an RFC (stable, no API polling needed). OpenID Federation 1.0 has no IETF Datatracker API — the tracker skips it and flags it for manual review in any generated issue.
Due-diligence policy — every tracker finding

Each standards-update issue must be triaged, reviewed for breaking changes, and verified against the threat model before it can be closed. See docs/standards-tracking.md — checklist.

Threat model review
Every code change from a spec update must be checked against: algorithm confusion, alg:none, missing exp/iat, typ header confusion, replay, audience escalation, key confusion, and DPoP replay (where applicable).
Animated demo required
Every implemented standard must have an animated flow in this demo — SVG packet animation, step highlights, or live interactive demo. A text description alone is not sufficient. Monitored (not-yet-implemented) drafts get a callout note instead.
JWT BCP audit (2026-08-02)
Applied during this issue cycle: all jwt.NewParser calls across the PoC now enforce WithValidMethods(["ES256"]), WithExpirationRequired(), and WithIssuedAt(). Algorithm confusion, alg:none, and far-future token attacks are fully mitigated.