When one service calls another, the receiver has to know who is talking. For most of the agents and proxies I run, that answer is still a long-lived string: an API key in a config file, a token in a keychain. Copy it to another machine and it works the same, which is convenient until it leaks.
TL;DR. SPIFFE is the standard for giving software a name. SPIRE is the runtime that hands out that name only after checking where a process is actually running. An SVID is the document that carries the name, and it expires on its own. The WIT is the newest kind of SVID: a token that rides inside the request, bound to a key the workload never hands over, so a copied token alone is not enough. That is the property AI agents need, and it has not shipped yet. What you can deploy today is OAuth 2.1, ideally with the token bound to its sender. OAuth 2.1 is also what the MCP authorization spec is built on.
OpenClaw on Oracle Cloud is a free VM holding a cascade of provider keys. The proxy behind same harness, more engines injects three vendor credentials into one Claude Code session. None of those strings knows where it is running. Machine identity issues the credential to a process after the platform has checked what the process is, expires it on a timer, and in its newest form binds it to a key that never leaves the process.
SPIFFE: a name, and a place to ask for it
SPIFFE (Secure Production Identity Framework for Everyone) is a specification, not a product. It is a CNCF graduated project, and it defines three things.
The first is the SPIFFE ID, a URI that names a workload: spiffe:// followed by a trust domain and a path. The trust domain is the boundary of one issuing authority, usually a company or an environment. The path is whatever naming scheme you choose, for example the namespace and service account a pod runs as. Addresses move. The name is supposed to survive a reschedule.
The second is the Workload API, usually a Unix domain socket on the local machine. The caller presents nothing. The implementation identifies the caller from outside the conversation, by asking the kernel and the orchestrator. There is no bootstrap secret, because nobody hands the workload one.
The third is the trust bundle: the CA certificates a workload should trust when it validates someone else, and the way two trust domains federate without sharing a CA.
That is the whole standard: a naming scheme, a local door, and a way to know whose signatures to believe. Who deserves which name is an implementation’s job.
SVID: the document that carries the name
A SPIFFE Verifiable Identity Document is a SPIFFE ID plus a signature from the trust domain’s authority. The spec now lists three document types: an X.509 certificate, a JWT, and a WIT. The first two are the ones running in production today.
An X.509-SVID carries the SPIFFE ID as its single URI name. Two services that both hold one can open mutual TLS and each learns who is on the other end (this is how most service meshes use SPIFFE). The private key stays inside the workload, and the proof happens in the handshake. The catch is any hop that terminates the connection: a load balancer, API gateway or queue that opens the request and forwards it proves who the proxy is, not who sent it.
A JWT-SVID exists for that gap. It is a signed token that rides inside the request, so it survives the hops that TLS doesn’t. It is also a bearer token, and the spec says so plainly:
“Being a bearer token, JWT-SVIDs are susceptible to replay attacks.”
A mandatory audience claim, a single audience, and an aggressive expiry narrow the window. They don’t close it: anyone who captures the token before it expires can present it to the service it was minted for.
| X.509-SVID | JWT-SVID | |
|---|---|---|
| Proves identity at | the TLS handshake | each request |
| Survives a proxy in the middle | no | yes |
| A stolen copy is enough | no, it needs the private key | yes, until it expires |
| SPIRE default lifetime | 1 hour | 5 minutes |
Those lifetimes matter. A credential that lives minutes and is reissued automatically is a different animal from one that lives until someone remembers to rotate it. It still has a bearer problem, but a short one.
SPIRE: the authority that checks before it signs
SPIRE is the production-ready implementation of SPIFFE that the project maintains. The spec says what an identity looks like. SPIRE answers how you decide who gets one without handing out a secret to prove it.
It splits the job in two. A SPIRE Server is the authority for one trust domain: signing keys, registration entries, every SVID. A SPIRE Agent runs on every node that hosts workloads, serves the Workload API socket, and asks the server for SVIDs on behalf of processes it has vouched for.
Node attestation proves the machine. When an agent starts, it and the server verify the node using evidence the platform already signs: an AWS instance identity document, Azure managed identity, a GCE instance identity token, a Kubernetes service account token, or an existing certificate. On a machine with none of that, a one-time join token does the job. That is the only pre-shared secret, and it is spent on first use. Once attested, the agent gets a SPIFFE ID of its own.
Workload attestation proves the process. The agent doesn’t ask the caller who it is. It asks the kernel which process is on the other end, then asks the local orchestrator what that process is: Unix user, container image, Kubernetes namespace and service account. Plugins cover Unix, Docker and Kubernetes (the August release added Slurm, the HPC scheduler).
The facts the agent collects are selectors. A registration entry joins them to a name: this service account, in this namespace, on a node attested as part of this cluster, gets this SPIFFE ID. No match, nothing. A match gets a short-lived SVID, and for certificates the agent renews it before it expires.
The trust comes from the platform’s signature on the node plus the kernel’s answer about the process. Ops work moves from rotating secrets to writing registration entries, reviewable in a pull request. Same shape as the first 30 days of platform rails around inference: find the constraint, stand the rails, leave gates that actually enforce.
There is no workload secret on disk to steal, because nobody wrote one.
SPIRE has limits. It solves identity between workloads you run, and between trust domains that agree to federate. It does nothing for a SaaS API that only accepts its own key. The model vendors I pay still want a string.
WIT: a token that travels with its proof
The Workload Identity Token comes from WIMSE (Workload Identity in Multi-System Environments), an IETF working group building on SPIFFE, OAuth and JWT. SPIFFE has adopted it as its third document type, the WIT-SVID.
It is a signed JWT, like a JWT-SVID, and the difference starts with one claim. A WIT carries a public key. Both specs are blunt: a WIT must not be used as a bearer token. Every time the workload presents it, the workload has to prove it holds the matching private key.
That proof is a second, tiny token. The workload signs a Workload Proof Token with its private key. It names the target URI, carries a unique ID and a hash of the WIT it belongs to, and expires in minutes or seconds. The receiver checks the WIT against the trust bundle, then checks the proof against the key inside the WIT.
Capture only the WIT and you can’t mint a proof, so the WIT is useless. Capture the proof as well and you can replay it against that one URI until it expires, and not even that if the receiver remembers proof IDs it has already seen. With a JWT-SVID, the captured token was the whole credential.
| JWT-SVID | WIT-SVID | |
|---|---|---|
| Carries | a SPIFFE ID and an audience | a SPIFFE ID and a public key |
| Audience claim | mandatory | forbidden |
| Presented as | a bearer token | a token plus a fresh signed proof |
| Spec status | stable | incubating |
The WIT-SVID document is merged and marked Incubating: breaking changes are avoided but still possible, and implementations typically gate it behind a flag. The Workload API carries a WIT-SVID Profile that implementations may support.
It has not landed in SPIRE. The tracking issue, WIT-SVID support in SPIRE, has been open since September 2025 and parked in the backlog since October. Releases shipped scaffolding: dummy profile implementations in 1.14.0, an issuer setting, server-side plumbing in 1.15.3. Ask a released agent for a WIT-SVID over the Workload API and it answers with a not-implemented error. On the development branch the option is off by default and needs a second feature flag on top.
OAuth 2.1: the part you can deploy this quarter
So what does a workload use in the meantime? OAuth 2.1 is still a draft, but it consolidates existing RFCs: proof key exchange is mandatory for the browser flow, the implicit and password grants are gone, and both the 2012 framework and its bearer-token companion are replaced. For service-to-service calls it keeps the client credentials grant, where a workload authenticates as itself with no user in the picture.
OAuth 2.1 also says tokens should be bound to their sender, either by proving possession of a key on each request or by issuing the token against the client’s own certificate. A token bound that way is worth nothing to whoever copies it. Mutual TLS already speaks that language on most gateways.
The two stacks compose. SPIFFE answers who the workload is; OAuth answers what it may do, and on whose behalf. An X.509-SVID is an ordinary client certificate, so it slots into certificate-bound tokens. SPIRE can also publish its JWT signing keys through a discovery endpoint, so a JWT-SVID can be exchanged for a token, most commonly a cloud role. That path hands over a bearer credential unless the authorization server adds sender-binding itself. The IETF’s own agent draft assumes this pairing.
A working-group draft posted on September 15, 2026, AI Identity Management System, with authors from AWS, OpenAI, Okta, Ping Identity, Zscaler and Defakto, argues that an AI agent is a workload: a WIMSE identifier as its name, SPIFFE as the mature implementation, short-lived credentials issued at runtime, and OAuth for delegation on top.
The MCP authorization specification is built on the same pieces: OAuth 2.1, protected resource metadata, and resource indicators so a token is minted for one named server. Two caveats keep that honest. MCP authorization is optional and written for HTTP transports, so a local tool on standard input is told to take credentials from its environment. And MCP sends its access token as a bearer credential, audience-restricted when the authorization server honours the resource parameter, and copyable either way. Binding tokens to their sender is the part OAuth already offers.
An agent is a workload that decides for itself which services to call next.
That is a hard fit for a bearer token. Agents chain through tools nobody listed in advance, so every token they hold should be worthless the moment it leaves the process. Mine still hold the strings from the top of this page, because the vendors on the other end accept nothing else. Deploy a sender-bound OAuth token issued to a workload whose name its platform attested, on the part of the fleet you control. The WIT can land later as one more document type on rails you already run.
I take selected, forward-deployed platform work of this shape. Available Q4 2026. Ottawa, Ontario remote, Canada remote. Propose a time on Hire.
References
- SPIFFE WIT-SVID specification (Incubating) and the SPIFFE specification index
- WIT-SVID support in SPIRE, the open tracking issue, and the SPIRE repository
- IETF WIMSE: workload credentials, the proof token, and the AI identity draft
- The OAuth 2.1 Authorization Framework and the MCP authorization specification