Skip to main content

How LumoAuth Secures an Agent

This is the page to read first if you want the whole picture: how one agent request flows through workload attestation → agent identity → MCP authorization → JIT / human-in-the-loop escalation → audit, why that beats a service-account API key, and which credential opens which door. In plain terms: workload attestation is the agent proving where it runs with a token from its platform; MCP (Model Context Protocol) is the standard way agents call tool servers; JIT (just-in-time) permissions are narrow, short-lived permissions an agent asks for at the moment it needs them, which a human can approve.

Every other agent page is a deep-dive on one stage of this lifecycle. Start here, then follow the links.

The agent request lifecycle​

19 / 19
  1. Note: 1. Attestation — no static secret
  2. Agent to Workload: Request platform identity token
  3. Workload to Agent: Signed OIDC / SVID token
  4. Agent to LumoAuth: Exchange platform token (RFC 8693)
  5. LumoAuth to LumoAuth: Verify issuer + signature (attestation)
  6. LumoAuth to Agent: Agent access token (sub=agent_<id>)
  7. Note: 2. Call a tool with a scoped token
  8. Agent to MCP Server / Resource: POST /mcp + Authorization: Bearer
  9. MCP Server / Resource to LumoAuth: Verify token / RFC 9728 metadata
  10. LumoAuth to MCP Server / Resource: allow + scopes (audit logged)
  11. MCP Server / Resource to Agent: tool result
  12. Note: 3. Sensitive action → escalate
  13. Agent to LumoAuth: JIT request (payment.execute, justification)
  14. LumoAuth to LumoAuth: Risk score → refuse auto-approve
  15. LumoAuth to Human Approver: Route to approval inbox (+ notify)
  16. Human Approver to LumoAuth: Approve
  17. LumoAuth to Agent: Short-lived JIT token (≤10 min)
  18. Agent to MCP Server / Resource: Perform the escalated action
  19. Note: 4. Every step is attributed & audited

Each stage maps to a doc:

StageWhat happensWhere
Workload attestationThe agent proves where it runs (K8s ServiceAccount, AWS IRSA, GCP, GitHub OIDC, SPIFFE SVID) and exchanges that for a LumoAuth token — no static secret.Workload Federation, Attestation
Agent identityThe agent is a first-class principal (agt_…) with capabilities, budgets, and an audit trail — or a cryptographic AAuth identity (the agent signs each request with its own key) with proof-of-possession.Agent Registry, AAuth Protocol
MCP authorizationThe agent calls an MCP server that is an OAuth protected resource; tokens are pinned to that server (resource indicators) and the server advertises its authorization server through protected resource metadata.MCP Servers
JIT / HITL escalationSensitive actions aren't standing capabilities — the agent requests them just-in-time, a human approves, and the grant is a short-lived downscoped token.JIT Permissions, Push Approval
AuditEvery step is attributed to the specific agent (actor_id=agt_…), including the full delegation chain via act claims.Audit Logs

Why not a service-account API key?​

The comparison that makes the case, stage by stage:

Service-account API keyLumoAuth Agent + MCP
Identity"service account X used by 47 services"agt_01HF… — one specific agent
ScopeAll-or-nothingPer-token, per-resource, time-bound
Sensitive actionsSame keyJIT + human approval (HITL)
RevocationRotate everywhereRevoke agent → CAEP (shared security-event signals) invalidates in 30s
Audit trail"the API key did it"Filter actor_id=agt_… for every action
Delegation chainUntrackedToken exchange records every hop

Agent credentials & tokens map​

An agent developer encounters several credential types. This is the map: what each one is, which door it opens, how long it lives, and how to exchange one for another.

CredentialWhat it isAccepted atLifetimeObtain / exchange
Cloud OIDC attestation tokenThe platform's own identity token — K8s projected ServiceAccount token, AWS IRSA, GCP metadata token, GitHub OIDC, SPIFFE JWT-SVID.LumoAuth token-exchange endpoint (/oauth/token, grant_type=token-exchange)Short (issued by the platform, minutes)Read from the workload; present as subject_token.
Core agent OAuth access token (sub=agent_<id>, is_agent)The platform's native agent token. The passport for JIT, the Ask API, the token vault (LumoAuth-held third-party credentials that agents borrow short-lived tokens from), and AuthZEN (the standard authorization-check API).main firewall APIs, jit_api (AccessTokenAuthenticator)Short (configurable, ≤1h typical)client_credentials, workload token-exchange, or admin mint (/admin/agents/{id}/token).
agk_ API keyA long-lived agent API key.JIT endpoints (documented; see the note below)Long-lived until revokedCreated by an admin in the portal/admin API.
AAuth token (auth+jwt, cnf PoP)Cryptographic AAuth identity — bound to an Ed25519/RSA key via cnf, every call a signed HTTP request.aauth_api endpoints (/aauth/*)1h default (configurable)AAuth flow: agent token + resource token → auth+jwt (AAuth).
JIT tokenA short-lived, downscoped token issued after a human approves a JIT request.The specific resource/action it was granted for≤10 minApproved JIT request → get_token(request_id).
DPoP proofA per-request sender-constraining proof JWT bound to a key thumbprint (jkt).Any DPoP-enabled OAuth endpointPer-requestGenerated by the client for each call (DPoP).
The AAuth → platform bridge

AAuth tokens (iss=<agent-url>, cnf PoP) are a cryptographic identity verified by the /aauth/* endpoints. To let an AAuth agent also call the platform's JIT, token-vault, and AuthZEN APIs — which resolve agents from a sub=agent_<id> claim — LumoAuth ships a token-exchange bridge:

POST /orgs/{orgId}/api/v1/aauth/agent/platform-token
Signature-Input / Signature: <RFC 9421 signature by the agent's cnf key>
Content-Digest: sha-256=:…:
{ "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
"subject_token": "<aauth agent token>",
"subject_token_type": "urn:lumoauth:params:oauth:token-type:aauth-token" }
→ { "access_token": "...", "token_type": "DPoP", "expires_in": 300,
"cnf_jkt": "<RFC 7638 thumbprint of the agent key>", "agent_id": "agt_…" }

The request must carry a signed HTTP request (HTTP message signature) made with the key bound in the AAuth token's cnf claim (same rules as the agent-token endpoint: content-digest and content-type covered, a fresh created, and a single-use nonce). Presenting the AAuth token as a plain bearer is rejected with 401, so a captured token cannot be replayed to obtain a platform token. The endpoint is rate-limited per client IP and per agent.

The platform token is itself sender-constrained: it is issued as a DPoP token bound to the agent key (cnf.jkt), whatever the key type (Ed25519, P-256 or RSA; the DPoP validator accepts EdDSA, ES*, RS* and PS* proofs), and platform APIs require a matching DPoP proof on every call. The bridge auto-links the AAuth agent to its core agt_… record if it isn't already, so the "one agent, one identity record" invariant always holds. This is the standard "AAuth agent uses platform APIs" step.

Agents can enforce per-MCP-tool access with that token via POST /orgs/{orgId}/api/v1/agents/me/mcp/authorize ({server_id, tool} → allow/deny from the Zanzibar mcp_tool grants), and check their own permissions on the polymorphic POST /api/v1/authz/check family (agents are first-class subjects there, not only on AuthZEN).

agk_ API keys on JIT

Agent API keys (agk_…) authenticate on the JIT endpoints (and the other agent routes): the jit_api firewall's bearer authenticator resolves them to a ROLE_AGENT principal. A core agent access token works too. See JIT Permissions.

One identity, many surfaces​

The goal is one agent, one record. A single registered agent (agt_…) should be the same principal whether it authenticates via OAuth client credentials, a workload attestation exchange, or the AAuth protocol — and that one identity is what JIT, the token vault, Zanzibar (agent: tuples), observability, and audit all key off. When you register an AAuth agent, link it to (or let it resolve to) a core agent so it isn't invisible to the rest of the platform.

Where to go next​

Standards used on this page​

Plain nameStandard
Token exchange (delegation)RFC 8693
Protected resource metadataRFC 9728
Resource indicatorsRFC 8707
Signed HTTP requests (HTTP message signatures)RFC 9421
Key thumbprintRFC 7638
Sender-constrained tokens (DPoP)RFC 9449
Shared Signals Framework (SSF) and Continuous Access Evaluation Profile (CAEP)OpenID SSF 1.0 and OpenID CAEP 1.0
Authorization API (AuthZEN)OpenID AuthZEN Authorization API 1.0

See the standards reference for what each one covers and how LumoAuth uses it.