IAM-05 · Identity & Access

Cryptographic Identity for AI Agents: Issuing Verifiable Identity with mTLS, JWT, and SPIFFE/SPIRE

How to give non-human AI agents verifiable cryptographic identity using mTLS, JWT, and SPIFFE/SPIRE — why static API keys fail and how to issue short-lived workload identity.

Agent identity flow: an agent authenticates to an issuer, receives a short-lived scoped token, and presents it to a resource that verifies scope before actingagentnon-human idtoken issuerOAuth / mTLSresourceverifies scopeauthenticatescoped tokenleast privilege: the token grants only this task, expires fast, and is bound to the agent's identity

An AI agent that books travel, queries a production database, or fires off API calls on your behalf is, to every system it touches, an anonymous stranger holding a password. That password is usually a static API key or a long-lived token copied into an environment variable. It does not expire on its own, it does not prove what software is presenting it, and once it leaks it works for anyone, anywhere, until a human notices and rotates it. As agents move from demos into production — calling tools, spawning sub-agents, and acting without a person in the loop — that model breaks.

The fix is to give each agent a cryptographic identity: a credential the agent can prove it holds, that is bound to the specific workload, that expires in minutes rather than months, and that any service can verify without phoning home to a central authority. This article explains why non-human AI agents need verifiable identity, then walks through the three building blocks that make it real in production — mTLS, JWT, and the SPIFFE/SPIRE framework that ties them together into automatic, short-lived workload identity.

What does “cryptographic identity for an AI agent” actually mean?

Cryptographic identity means an agent holds a private key it never shares, and a verifiable document — a certificate or a signed token — that binds that key to a name. When the agent connects to a service, it proves possession of the private key, and the service checks the binding against a trust anchor it already knows. No shared secret crosses the wire, the credential is cryptographically tied to the workload, and it carries a short expiry so a stolen copy is worthless within minutes.

That is the whole idea in one paragraph, and it is the answer to the title question: AI agents need verifiable identity because they act autonomously across trust boundaries, and you issue it by giving each agent a short-lived cryptographic credential — an X.509 certificate for mTLS, a signed JWT for application-layer calls, or both — automatically provisioned by a workload identity system like SPIFFE/SPIRE rather than a static key pasted into config.

The rest of this guide unpacks each piece. If you only remember one thing: stop treating agents like users with passwords, and start treating them like workloads that earn a fresh identity every time they run.

How is this different from how agents authenticate today?

Most agents today authenticate with a bearer token — a string that grants access simply by being presented. OpenAI keys, cloud service account keys, database passwords, and OAuth tokens are all bearer credentials. They share three weaknesses that matter far more for autonomous software than for a human typing a password once a day:

  • They are not bound to the holder. A bearer token works for whoever holds it. There is no way for the receiving service to tell whether the legitimate agent or an attacker who exfiltrated the token is making the call.
  • They are long-lived. Keys are issued once and used for months because rotating them is painful. An agent that runs thousands of times reuses the same secret every run, widening the blast radius of any leak.
  • They are opaque about what is calling. A token says “someone authorized as project X.” It does not say “the invoice-processing agent, version 2.3, running in the eu-west cluster.” Without that, least-privilege authorization and forensics are guesswork.

Cryptographic identity closes all three gaps. The credential is bound to a private key the agent never transmits, it expires fast, and it names the workload precisely.

Why do non-human AI agents need verifiable identity at all?

Because the assumptions that made API keys tolerable for scripts collapse once software starts acting on its own. An agent is not a cron job with a fixed task list. It plans, it chains tool calls, it can spin up sub-agents, and it makes decisions you did not explicitly script. Three pressures push verifiable identity from “nice to have” to “required.”

The non-human identity population is exploding

Inside any modern environment, machine identities already outnumber human ones by a wide margin — service accounts, CI runners, microservices, and now AI agents. This category is usually called non-human identity (NHI), and it has become a recognized attack surface in its own right. Leaked secrets in source code, over-permissioned service accounts, and orphaned credentials are recurring root causes in real breaches. Agents make this worse on two axes: there are suddenly many more of them, and each one is more capable, because an agent can reason its way around guardrails a static script never could. You cannot manage what you cannot name and verify, so identity is the prerequisite for everything else — authorization, auditing, and revocation.

Agents cross trust boundaries autonomously

A human user authenticates at a boundary — a login — and then operates inside a session a person is steering. An agent crosses boundaries continuously and unattended: it calls an internal API, which calls a database, which triggers another service. Each hop needs to answer “who is calling, and are they allowed to?” If every hop trusts a shared bearer token, then compromising one component hands the attacker the keys to all of them. Verifiable per-workload identity lets each service make its own authorization decision based on who the caller provably is, not on possession of a secret that has been passed around.

Autonomy raises the cost of a stolen credential

When a human leaks a password, the damage is bounded by what one person can do before someone notices. When an autonomous agent’s credential leaks, an attacker can script it to act at machine speed, across every tool the agent can reach, for as long as the credential lives. Long-lived bearer tokens turn a single leak into open-ended access. Short-lived, workload-bound credentials turn the same leak into a few minutes of narrow exposure. That difference — months of broad access versus minutes of narrow access — is the core security argument for cryptographic agent identity.

What is mTLS and how does it give an agent identity at the transport layer?

Mutual TLS (mTLS) is ordinary TLS with one addition: both sides present a certificate and both sides verify the other. In normal HTTPS, only the server proves who it is (your browser checks the site’s certificate) while the client stays anonymous and authenticates later with a password or token. In mTLS, the client — your agent — also presents an X.509 certificate, and the server validates it during the TLS handshake. Identity is established before a single byte of application data is sent.

For an AI agent, mTLS means its identity is proven at connection time, cryptographically, by possession of a private key that never leaves the workload. The certificate contains the agent’s name (more on the naming scheme under SPIFFE below), is signed by a Certificate Authority both sides trust, and is checked automatically by the TLS stack. There is no bearer token to steal because there is no shared secret — the agent proves it holds the private key matching the public key in its certificate.

What does mTLS protect against that a token does not?

mTLS gives you three properties that bearer tokens cannot:

  • Mutual authentication. The agent verifies the service is genuine and the service verifies the agent. This blocks an attacker who stands up a fake endpoint to harvest agent credentials, and it blocks an unauthorized client from reaching a protected service at all.
  • Proof of possession. Because authentication depends on the private key, intercepting the handshake does not let an attacker impersonate the agent. Compare that with a leaked bearer token, which is instantly replayable by anyone.
  • Encryption plus identity in one layer. The same handshake that proves identity also establishes the encrypted channel, so you are not bolting authentication on top of an already-open connection.

What are the limits of mTLS for agents?

mTLS is not free, and it is not the whole answer. It operates at the transport layer, so it tells a service “this connection is from agent A,” but it does not by itself carry application-level context like “agent A is acting on behalf of user U with read-only scope.” Certificate lifecycle — issuing, distributing, rotating, and revoking certs for thousands of ephemeral agents — is genuinely hard if you do it by hand, which is exactly the problem SPIFFE/SPIRE exists to solve. And revocation via traditional CRLs or OCSP is awkward at scale, which is why the modern pattern leans on very short certificate lifetimes instead of revocation lists: if a cert lives for an hour, you barely need to revoke it.

What is JWT and where does it fit in agent identity?

A JWT (JSON Web Token) is a compact, signed token that carries a set of claims — statements like “subject is the invoice agent,” “issued by this authority,” “expires at this time,” “scope is read-only.” It is signed (and verifiable) using public-key cryptography, so any service holding the issuer’s public key can confirm the token is authentic and untampered with, without contacting the issuer. JWTs operate at the application layer, inside the request, which makes them the natural place to carry the context that transport-layer mTLS cannot.

For agents, JWTs answer the questions mTLS leaves open: On whose behalf is the agent acting? With what permissions? For which audience? A well-formed agent JWT names the agent as the subject, names the intended recipient service as the audience (aud), carries a short expiry (exp), and includes the specific scopes the agent is allowed to use for this call. A service can then make a fine-grained authorization decision from the token’s claims.

Are JWTs bearer tokens too — and isn’t that the thing we’re avoiding?

Yes, a plain JWT is a bearer token: whoever holds it can use it until it expires. That is why the design rules matter so much. The way to make JWTs safe for agents is to treat them as short-lived, narrowly scoped, audience-bound credentials rather than long-lived keys:

  • Short exp. Minutes, not days. A leaked token that expires in five minutes is a small problem.
  • Tight aud. A token minted for service X should be rejected by service Y, so a captured token cannot be replayed elsewhere.
  • Minimal scope. Each token grants only what the specific action needs, so a leak does not expose the agent’s full authority.
  • Combine with mTLS. Send the JWT over an mTLS connection. Now the channel proves which workload is connected (mTLS) and the token proves what it is authorized to do right now (JWT). The two layers cover each other’s gaps.

This is the same pattern that OAuth 2.1 client-credentials flows use for service-to-service calls, and it is why SPIFFE defines a JWT-based identity document alongside its X.509 one — so you get a consistent identity whether you are securing a raw connection or a request that passes through a layer-7 HTTP proxy.

What are SPIFFE and SPIRE, and why are they the backbone of workload identity?

SPIFFE (Secure Production Identity Framework For Everyone) is an open standard, hosted by the Cloud Native Computing Foundation (CNCF), that defines how to name and credential a workload. SPIRE (the SPIFFE Runtime Environment) is the reference implementation that actually issues those identities at runtime. Together they automate the hard parts of cryptographic identity — naming, issuing, rotating, and attesting — so your agents get fresh, verifiable credentials without anyone pasting a key into a config file. SPIFFE/SPIRE is a CNCF-graduated project, which is the foundation’s highest maturity tier and signals broad production adoption.

The core insight of SPIFFE is attestation: instead of handing a workload a secret it then uses to prove who it is (a circular bootstrapping problem — how did it get the secret securely in the first place?), the platform observes the workload and issues identity based on verifiable properties. SPIRE checks attributes like which Kubernetes service account a pod runs under, which node it is on, or which process and container started it, and only then mints a credential. The workload never holds a long-lived bootstrap secret. This is how you escape the “secret zero” problem that plagues API-key models.

What is a SPIFFE ID and an SVID?

A SPIFFE ID is the name of a workload, written as a URI like spiffe://example.org/agent/invoice-processor. It is the stable, human-readable, machine-verifiable identity of the agent. An SVID (SPIFFE Verifiable Identity Document) is the credential that proves the workload owns that SPIFFE ID. SPIFFE defines two SVID formats, which map exactly onto the two mechanisms above:

  • X.509-SVID — an X.509 certificate carrying the SPIFFE ID. This is what you use for mTLS: the agent presents its X.509-SVID in the TLS handshake.
  • JWT-SVID — a signed JWT carrying the SPIFFE ID. This is what you use when traffic passes through layer-7 infrastructure (API gateways, HTTP proxies) that would terminate a raw mTLS connection.

So SPIFFE is not an alternative to mTLS and JWT — it is the system that issues and standardizes the certificates and tokens those mechanisms consume, with one consistent naming scheme across both.

How does SPIRE actually hand an identity to an agent?

The flow is designed so that no secret has to be planted in advance:

  1. The SPIRE Server is the central authority. It signs SVIDs and holds the registration entries that say which attested properties map to which SPIFFE ID.
  2. A SPIRE Agent runs on each node. It first proves the node’s identity to the server (node attestation — using a cloud instance identity document, a Kubernetes credential, or a join token), then helps attest the workloads on that node.
  3. When your AI agent’s process starts and asks for its identity, the SPIRE Agent performs workload attestation — inspecting the calling process’s properties (its Kubernetes service account, Unix user, container labels, and so on) against the registration entries.
  4. If the properties match a registered entry, SPIRE issues the SVID for that SPIFFE ID — an X.509 cert, a JWT, or both — directly to the workload over a local API (the Workload API), never over the network as a static file.
  5. SPIRE rotates the SVID automatically before it expires, on a short cycle. The agent simply re-reads its identity from the local API. There is no manual rotation and no long-lived secret to leak.

The practical payoff: your AI agent never has a hard-coded credential. It comes up, asks the local Workload API “who am I?”, receives a short-lived SVID minted just for it, uses it for mTLS or as a JWT, and gets a fresh one before the old one expires.

How do mTLS, JWT, and SPIFFE/SPIRE compare — and when do you use each?

These are not competing choices; they are layers that fit together. The table below clarifies what each does and where it sits.

Mechanism Layer What it proves Lifetime pattern Best for Key limitation
Static API key Application Possession of a shared secret Long-lived (months) Quick prototypes only Not bound to holder; replayable; opaque about the caller
mTLS (X.509) Transport Which workload owns the connection Short (minutes–hours) Service-to-service and agent-to-service over raw connections No application context; cert lifecycle is hard by hand
JWT Application What the caller is authorized to do, and on whose behalf Short (minutes) Carrying scope/context, layer-7 paths through proxies A plain JWT is still a bearer token unless short-lived and audience-bound
SPIFFE/SPIRE Identity framework A standard name (SPIFFE ID) + auto-issued SVID Short, auto-rotated Automating identity issuance, rotation, and attestation across all of the above Operational footprint to run; overkill for a single tiny service

The decision is usually additive, not exclusive:

  • Securing a raw connection between an agent and a backend service? Use mTLS with X.509-SVIDs.
  • Need to carry “acting on behalf of user U with read-only scope” through an HTTP API gateway? Use a JWT-SVID inside the request, ideally over mTLS.
  • Running more than a handful of agents, especially ephemeral ones? Use SPIFFE/SPIRE to issue and rotate both, so you never manage certificates or tokens by hand.

How do you actually issue cryptographic identity to an AI agent?

Here is the path most teams take, from prototype to production, without trying to boil the ocean on day one.

Step 1: Name your agents

Before any cryptography, decide on a naming scheme. SPIFFE IDs give you a ready-made convention: spiffe://yourtrustdomain/agent/<name>. A clear, stable naming scheme is what makes authorization and audit possible later — you authorize names, not secrets. Decide on your trust domain (typically one per organization or per environment) and a path structure that reflects how you reason about agents (by team, by function, by environment).

Step 2: Replace static keys with short-lived credentials

The single highest-impact change is reducing credential lifetime. Even before you adopt a full framework, move from month-long keys to credentials measured in minutes, fetched at runtime. Short lifetimes make revocation almost a non-issue and shrink the value of any leak. This is the principle behind both X.509-SVIDs and properly scoped JWTs.

Step 3: Establish mutual authentication on internal traffic

For agent-to-service and service-to-service calls inside your perimeter, turn on mTLS so both ends authenticate. In a Kubernetes environment, a service mesh can provide mTLS between workloads, and several meshes integrate with SPIFFE identities natively. The goal is that no internal call is accepted on the strength of a shared token alone — the connecting workload must prove its identity.

Step 4: Carry context in scoped, audience-bound JWTs

Where calls pass through layer-7 HTTP infrastructure, or where a service needs to know on whose behalf an agent acts, attach a JWT with a tight aud, a short exp, and the minimal scope for the action. Validate the signature against the issuer’s public key, and reject any token whose audience does not match. This is where you enforce least privilege at the request level.

Step 5: Automate issuance and rotation with SPIFFE/SPIRE

When manual certificate and token management becomes the bottleneck — and with fleets of ephemeral agents it always does — adopt SPIRE to issue X.509-SVIDs and JWT-SVIDs automatically via attestation, and to rotate them on a short cycle. At that point your agents never hold a planted secret: they attest, receive an identity, and refresh it transparently. This is the end state the earlier steps were building toward.

Step 6: Authorize on identity, then log it

With verifiable identity in place, write authorization policies against SPIFFE IDs (or the JWT subject and scopes) rather than against possession of a key. Then log the proven identity on every call. Because the identity is cryptographically verified rather than merely asserted, your audit trail finally answers “which agent did this, exactly?” with confidence — the forensic question that opaque API keys can never answer.

What problems does this still leave open?

Cryptographic workload identity is necessary but not sufficient, and it is worth being honest about the rough edges:

  • On-behalf-of delegation is its own problem. Proving which agent is calling is solved; cleanly propagating which user the agent acts for, with the right scope, across a chain of services and sub-agents is still an active area of design. JWT claims help, but multi-hop delegation needs careful policy.
  • Authorization is separate from authentication. Identity tells you who; you still need a policy engine to decide what they may do. Verifiable identity makes those policies trustworthy, but it does not write them for you.
  • Running the infrastructure has a cost. SPIRE is operational software, with servers, agents, and attestation configuration to manage. For a single small service it is overkill; its value shows up with scale and ephemerality.
  • Agents can still be tricked. A perfectly authenticated agent that is prompt-injected into misusing its legitimate permissions is an authorization-and-guardrails problem, not an identity one. This is where capability-based scoping of each tool and continuous, per-action checks under zero-trust enforcement take over. Identity bounds who and what, which limits the blast radius — but it does not stop an agent from misusing access it genuinely holds.

None of these undermine the case for cryptographic identity; they clarify that it is the foundation other controls sit on, not a complete security program by itself.

The bottom line

AI agents act autonomously, cross trust boundaries unattended, and can do damage at machine speed — which is exactly why the static-API-key model that barely sufficed for scripts is the wrong default for them. Verifiable cryptographic identity replaces “whoever holds this secret” with “whoever can prove they are this workload, right now.” You build it from three complementary layers: mTLS proves which workload owns a connection, JWT carries what that workload is authorized to do and on whose behalf, and SPIFFE/SPIRE issues and rotates both automatically through attestation, so no long-lived secret ever has to be planted. Start by naming your agents and shortening credential lifetimes; grow into mutual authentication, scoped tokens, and automated issuance as your fleet does. The payoff is the ability to answer, with cryptographic confidence, the question every autonomous system eventually forces: which agent did this, and was it allowed to?

Frequently asked

What is the difference between mTLS and JWT for agent identity?

mTLS works at the transport layer and proves which workload owns a connection using an X.509 certificate during the TLS handshake, with no shared secret crossing the wire. A JWT works at the application layer, inside the request, and carries claims about what the caller is authorized to do and on whose behalf. They are complementary: send a short-lived, audience-bound JWT over an mTLS connection so the channel proves the workload identity and the token proves the authorization context. mTLS alone lacks application context; a plain JWT alone is a replayable bearer token unless it is short-lived and audience-bound.

Why are static API keys a bad fit for AI agents?

Static API keys are bearer credentials with three weaknesses that hurt autonomous software badly: they are not bound to the holder, so anyone who copies the key can use it; they are typically long-lived, so a leak grants open-ended access until a human notices and rotates; and they are opaque about which exact workload is calling, which makes least-privilege authorization and forensics guesswork. An autonomous agent with a leaked key can be scripted to act at machine speed across every tool it can reach, turning one leak into broad, lasting exposure.

What is a SPIFFE ID and an SVID?

A SPIFFE ID is the verifiable name of a workload, written as a URI such as spiffe://example.org/agent/invoice-processor. An SVID (SPIFFE Verifiable Identity Document) is the credential that proves the workload owns that SPIFFE ID. SPIFFE defines two SVID formats: an X.509-SVID (a certificate used for mTLS) and a JWT-SVID (a signed token used when traffic passes through HTTP layer-7 infrastructure like API gateways). Both carry the same SPIFFE ID, giving one consistent identity across transport-layer and application-layer paths.

How does SPIRE issue identity without a planted secret?

SPIRE uses attestation instead of a bootstrap secret. A SPIRE Agent on each node first proves the node's identity to the SPIRE Server (node attestation), then performs workload attestation by inspecting a starting process's verifiable properties — its Kubernetes service account, Unix user, container labels, and so on. If those properties match a registration entry, the SPIRE Server issues the corresponding SVID directly to the workload over a local Workload API. SPIRE then rotates the SVID automatically before it expires. The workload never holds a long-lived secret, which avoids the 'secret zero' bootstrapping problem.

Do I need SPIFFE/SPIRE, or can I use mTLS and JWT on their own?

You can use mTLS and JWT without SPIFFE/SPIRE, and for a handful of services that may be enough. SPIFFE/SPIRE becomes valuable when you need to issue, rotate, and attest credentials across many workloads — especially ephemeral agents — without managing certificates and tokens by hand. SPIRE issues both X.509 and JWT SVIDs automatically through attestation and rotates them on a short cycle, which is exactly the part that becomes unmanageable manually at scale. For a single small service, running SPIRE is usually overkill.

How does cryptographic identity help with revocation?

The modern pattern relies on very short credential lifetimes rather than revocation lists. Traditional X.509 revocation through CRLs or OCSP is awkward to operate at scale, so instead of trying to revoke a credential quickly, you make it expire quickly — minutes to a couple of hours. A leaked SVID or scoped JWT is then worthless almost immediately, and automated rotation (as SPIRE provides) keeps issuing fresh credentials without manual effort. Short lifetimes turn a leak from open-ended access into a brief, narrow window.

Does verifiable identity stop prompt injection or agent misuse?

No. Cryptographic identity solves authentication — proving which agent is acting and bounding what permissions it holds — but it does not stop an authenticated agent from being manipulated into misusing the access it legitimately has. Prompt injection and agent misuse are authorization and guardrail problems. Identity limits the blast radius by enforcing least privilege and giving you a trustworthy audit trail of which agent did what, but you still need separate authorization policy, scoping, and runtime guardrails to constrain how an agent uses its access.