Most agent failures in payments do not start with a clever prompt injection. They start with a credential that was too broad and lasted too long. The agent inherits whatever the spawning user or service account could already do, and then it does more of it, faster, with less oversight.

If module 2 settled that authentication is not the same as intent, this module covers the credential itself: what the agent carries, how narrow it is, and how long it lives. Get this wrong and every downstream control, from the tool gateway to the audit log, is reasoning about the wrong principal.

The default that quietly breaks everything

When a team ships an agent, the path of least resistance is to hand it the credentials already sitting in the environment. A long-lived API key. A service account token. The OAuth session of the user who kicked off the task.

That choice collapses three separate things into one identity. You can no longer tell the user apart from the agent acting for the user, you cannot tell one agent task apart from another, and you cannot tell a compromised run apart from a healthy one. The credential says "this is the billing service," not "this is the refund agent, running task 4f9c, authorized to refund up to $200 on order 88231, for the next 90 seconds."

For a money-moving agent that gap is the whole problem. A static service-account token that can move funds, lives for months, and is shared across every task is the single most useful thing an attacker can steal. It is also the thing that makes a misfiring agent indistinguishable from a malicious one in your logs.

What "scoped and short-lived" actually means

Three properties, and you need all three.

Per-agent and per-task. The identity belongs to a specific agent instance running a specific task, not to the human or the service that launched it. Two refund agents, or the same agent on two tasks, get two distinct identities.

Short-lived. The credential is valid for minutes, not months, and rotates automatically. A stolen token is worthless almost immediately, and you remove the standing secret that has to be guarded, rotated, and revoked by hand.

Attestable. The platform can prove the credential was issued to a workload it actually verified, rather than minted by anyone who knew a shared secret. This is the difference between "we issued this" and "something presented a string that looked right."

Attestation: SPIFFE and SPIRE

SPIFFE is the open standard here. It defines a SPIFFE ID, a URI of the form spiffe://trust-domain/path, and a SPIFFE Verifiable Identity Document (SVID) that proves it, issued as either a short-lived X.509 certificate or a JWT.

SPIRE is the reference implementation. A SPIRE server issues SVIDs, and a SPIRE agent runs on each node, attests the workload before handing it an identity, and rotates the SVID automatically before it expires. Attestation is the load-bearing step: the platform checks properties of the workload, such as what it is and where it runs, before issuing anything. SVIDs are deliberately short-lived, on the order of minutes to hours, and rotate without an application restart.

For our purposes, SPIFFE answers "which workload is this, provably." It does not by itself answer "on whose behalf, and with what permission." That second question is where token exchange comes in.

Delegation: OAuth token exchange

RFC 8693, OAuth 2.0 Token Exchange, gives us a standard way to trade a broad token for a narrower one. A service presents an existing token to the authorization server and receives a new one with a different audience, a smaller scope, or delegation semantics that record who is acting for whom.

The mechanics matter for audit. The request carries a subject_token representing the original user and may carry an actor_token representing the party now acting. When both are present, the issued token includes an act claim naming the actor on top of the subject. So the resulting token does not just say "user 88231." It says "the refund agent, acting for user 88231."

RFC 8693 also defines a may_act claim that a subject token can carry to pre-authorize specific actors. The authorization server inspects it when deciding whether to honor the exchange. That gives you a place to encode "this user's session may be exchanged for a refund-agent token, and nothing else," before any agent ever runs.

The two standards compose cleanly. SPIFFE proves the workload. Token exchange turns that proven workload plus a user grant into a task-scoped, time-boxed credential with delegation recorded in the token itself.

A worked example

A support agent needs to issue a refund. Here is the credential path, kept deliberately narrow at every hop.

  1. The agent workload boots. SPIRE attests it and issues an X.509-SVID with the SPIFFE ID spiffe://payments.example/agent/refund, valid for 15 minutes.
  2. The agent presents that SVID plus the user's session token to the authorization server and requests a token exchange. The request names the audience (the refund API), the scope (refund:create), and a resource constraint (order 88231, amount up to $200).
  3. The authorization server checks the user session's may_act claim, confirms it pre-authorizes the refund agent, and issues an access token that lives for 90 seconds, carries an act claim identifying the refund agent, and is bound to exactly that order and ceiling.
  4. The refund API accepts the token, sees both the subject and the acting agent, and enforces the $200 ceiling. The tool gateway in module 6 enforces the same envelope independently.
  5. Ninety seconds later the token is dead. There is no standing secret to revoke, and no broad refund credential sitting in the agent's memory waiting to be exfiltrated.

Compare that with the default. A shared payments-service API key, no expiry, full refund authority, and a log line that reads "payments-service issued refund" with no way to attribute it to a task, an agent, or the user who triggered it. The narrow path costs a few extra calls. The broad path costs you the entire investigation when something goes wrong.

What this does and does not buy you

Scoped, short-lived, attestable credentials remove the standing money-moving secret, shrink the blast radius of any single compromise to one task and a few seconds, and make every action attributable to a named agent acting for a named user. That attribution is what makes the audit trail in module 8 worth keeping.

It does not stop an agent from being tricked into doing the wrong thing within its scope. A 90-second token bounded to $200 still moves $200 if the agent is manipulated into a bad refund. That is the job of mandates (module 4), the tool gateway (module 6), and human checkpoints (module 7). Credentials bound the worst case. They do not decide intent.

The takeaway is narrow and firm: never let a money-moving agent run on the spawning user's service account. Give it its own identity, prove that identity, scope it to the task, and let it expire on its own. Everything else in this course assumes you already know which principal you are governing.

← Previous
Authentication vs Intent: The Gap Prompt Injection Lives In
Next →
Signed Mandates: Cryptographic Permission to Spend with AP2