API Keys Were Never Going to Survive AI Agents: The AuthN/AuthZ Patterns That Will

Sources

The most dangerous phrase in an agent rollout is "we gave it an API key." A static key grants an agent permanent, un-scoped, un-attributed access to production systems — and agents are the one workload class that combines non-determinism with tool use. Okta's March 2026 press release cites research finding that 88% of organizations report suspected or confirmed AI agent security incidents, while only 22% treat agents as independent, identity-bearing entities. That gap is the entire story: fleets of agents are being deployed with the credential hygiene of a 2013 cron job. The stat comes from Okta's Agent SSO announcement — and the vendor has a commercial reason to make it scary, which is exactly why the number deserves attention: even discounted, it describes an industry giving production access to workloads it cannot name.

This guide maps the patterns that replace static keys for agent authentication and authorization — OAuth client credentials, RFC 8693 token exchange, the MCP authorization spec, SPIFFE/SPIRE workload identity, and A2A security schemes — each with an honest weakness list and a who-should-skip verdict. It assumes you already run agents on Kubernetes or an equivalent fleet platform; if not, start with our sandbox-and-egress guide for agents on Kubernetes and the fleet architecture patterns piece.

Why API Keys Break at Agent Scale

A static API key fails four ways at once when the holder is an autonomous agent:

The replacement is not a single technology. It is a stack: short-lived, audience-bound OAuth tokens for sessions; token exchange for delegation chains; an attested workload identity underneath the fleet; and per-request policy at the tool boundary. Here is the shape of it:

flowchart TB
    subgraph IDP["Identity provider / OAuth authorization server"]
        AS["OAuth 2.1 AS - short-lived, audience-bound tokens"]
    end
    subgraph FLEET["Agent fleet on Kubernetes"]
        SPIRE["SPIRE agents - attest pods, deliver SVIDs"]
        P["Planner agent"]
        E["Executor agent"]
        X["Specialist agent"]
    end
    subgraph TOOLS["Downstream systems"]
        MCP["MCP tool server"]
        API["Vendor APIs"]
    end
    U["Human user"] -->|"OIDC login + consent"| AS
    AS -->|"auth code + PKCE"| P
    P -->|"token exchange - act chain"| E
    E -->|"audience-bound token"| MCP
    E -->|"A2A security scheme"| X
    X -->|"OBO token exchange"| API
    SPIRE -.->|"X.509 / JWT-SVID, no secret"| P
    SPIRE -.-> E
    SPIRE -.-> X

Pattern 1 — OAuth Client Credentials: The Autonomous Baseline

A fully autonomous agent — scheduled triggers, no human in the loop — maps cleanly to the OAuth 2.0 client credentials grant: the agent authenticates as itself, and gets a token that identifies the agent, not any user. Microsoft's Entra Agent ID documentation describes exactly this mode: "Agent identities use client_credentials for app-only autonomous operations, enabling independent functionality without user context," while agents acting for a user use the on-behalf-of flow instead. The spec-relevant point is that client credentials gives you identity and rotation, but not delegation — the token says "agent X is acting," never "agent X is acting for user Y."

The reason this pattern exists in the stack is credential lifecycle: the agent presents a secret (or better, a federated workload credential — see Pattern 4) to the authorization server and receives a short-lived access token. Revocation is a policy action against the agent's registration, not a key hunt across the estate.

Honest weaknesses.

Who should skip: nobody entirely — client credentials is table stakes for background agents. But if your agent acts on user-visible data (documents, tickets, records), client credentials alone is the wrong pattern even when it works; skip to token exchange. And if your "agent" is really a scheduled script with one API to call, a scoped, rotated key in a managed secret store remains the pragmatic answer — OAuth machinery for a single-caller integration is over-engineering.

Pattern 2 — RFC 8693 Token Exchange: Delegation Chains That Name the Actor

OAuth 2.0 Token Exchange turns an authorization server into a Security Token Service: a client presents a subject_token (the user's token — the mandate) and optionally an actor_token (its own credential — the acting party), and receives a new, scoped token for a downstream audience. RFC 8693 could not describe the agent use case better if it had been written for it — the RFC's own words: "with delegation semantics, principal A still has its own identity separate from B... In a sense, A is an agent for B."

The output is a composite token. The sub claim stays the user; an act claim names the current actor; nested act claims preserve the prior actors as a history trail. This is the audit primitive that API keys cannot produce:

{
  "iss": "https://as.example.com",
  "sub": "user@example.net",
  "aud": "urn:example:cooperation-context",
  "scope": "status feed",
  "act": {
    "sub": "https://agent-executor.example.com",
    "act": {
      "sub": "https://agent-planner.example.com"
    }
  }
}
sub          user@example.net                    <- the mandate: who authorized this
act.sub      https://agent-executor.example.com  <- current actor: who acts NOW
act.act.sub  https://agent-planner.example.com   <- prior actor: delegation history

RFC 8693 rule: access control uses only the top-level
claims and the CURRENT actor. Prior actors are
informational — an audit trail, not an authorization input.

The may_act claim closes the loop on the other side: it lets a token declare who is authorized to become its actor, so the authorization server can reject an exchange attempt by an unlisted agent before any downstream call happens.

Real deployments. This is now shipped vendor infrastructure, not theory. Amazon Bedrock AgentCore Identity supports on-behalf-of (OBO) token exchange natively — generally available in 14 AWS Regions as of April 2026 — with the agent never touching client secrets: the credential provider stores them in AWS Secrets Manager, performs the exchange, and returns a user-scoped token. AWS's security blog walks the full pattern with a named external system: an agent operating on Salesforce data, where the OBO-exchanged token lets Salesforce's own sharing rules enforce per-user record access, resolved via a Salesforce token-exchange handler mapping the inbound user identity. In the multi-tenant variant against Okta, AWS's implementation guide documents the sharp edge every adopter hits: Okta requires subject_token_type=access_token while AgentCore defaults to jwt, and the exchange fails with invalid_request until you override it per credential provider. Microsoft's Entra agent flows cover the same ground with Federated Identity Credentials, including a third mode where an agent gets its own user principal ("agents having their own mailbox") — a pragmatic concession that some systems simply will not accept non-human principals.

aws bedrock-agentcore get-resource-oauth2-token \
  --resource-credential-provider-name sample-obo-provider \
  --oauth2-flow ON_BEHALF_OF_TOKEN_EXCHANGE \
  --scopes "sample-scope" \
  --workload-identity-token "workload-access-token"

Honest weaknesses.

Who should skip: agents with no user mandate — a monitoring or indexing agent acting purely on its own behalf needs client credentials, not exchange. Also skip if your IdP has no token-exchange support at all: home-rolled "token forwarding with a header" is worse than a well-scoped static credential because it creates the illusion of delegation. The IETF is also drafting OAuth Transaction Tokens for agents, which add actor and principal context fields for exactly this call-graph problem — watch that space rather than building bespoke claim schemas.

Pattern 3 — MCP Authorization: What the Spec Covers, and What It Leaves Open

Agents reach tools through MCP, and the 2026-07-28 revision of the MCP authorization spec is far more prescriptive than most tutorial coverage admits. The normative core (we covered the transport-side changes in our stateless-spec production guide):

The real gaps are the parts the spec does not say:

Who should skip: stdio and in-cluster MCP servers with a trusted caller can read credentials from the environment per the spec's own guidance without standing up an OAuth 2.1 apparatus — do not build an AS for a tool server only your orchestrator calls. Conversely, if you operate MCP servers that any third-party agent can connect to, none of this is optional: unauthenticated tool servers with production scopes are the unpatched CVE you have not found yet.

Pattern 4 — SPIFFE/SPIRE: Attested Workload Identity Under the Fleet

Everything above still needs an answer to "how does the agent authenticate to the IdP in the first place?" The CNCF answer is SPIFFE: every workload gets a stable identity URI (a SPIFFE ID like spiffe://prod.example.com/ns/inference/sa/agent-worker), delivered as a short-lived X.509-SVID or JWT-SVID by a SPIRE agent that attests the workload from platform facts — namespace, service account, pod labels — instead of a pre-shared secret. There is nothing in the credential for an attacker to steal from your repo, and nothing to rotate by hand; X.509-SVIDs default to roughly an hour and rotate automatically.

Production precedent. Uber runs SPIRE across a fleet of over a quarter-million nodes in multiple clouds; their engineering post documents the scale problems that matter for AI fleets specifically — SPIRE Agent caching thousands of SVIDs per host group, solved with an LRU cache that let them register ~2.5× more workloads per host while cutting SPIRE Server CPU by 40%. Indeed runs a nested SPIRE topology (root CA in an infrastructure cluster, intermediates per Kubernetes cluster) across a 3,000-pod estate, and their post carries the warning every federation adopter should read first: AWS accepted about 100 JWT signing keys while Confluent accepted only a handful, and neither vendor documents the limit. And the vendor direction is telling: Google's Agent Identity is explicitly SPIFFE-based — every agent gets a SPIFFE ID with an auto-provisioned X.509 certificate (24-hour validity) and access tokens cryptographically bound to that certificate, so a stolen token cannot be replayed from outside the agent's runtime.

The bridge from SPIFFE to the OAuth world is JWT-SVIDs: the SPIRE OIDC Discovery Provider publishes a standard /.well-known/openid-configuration and JWKS for the trust domain, and any OIDC-federating system accepts JWT-SVIDs as issuer tokens. Anthropic documents exactly this for the Claude API — a SPIRE-issued JWT-SVID (audience https://api.anthropic.com) is exchanged at Anthropic's token-exchange endpoint for a short-lived API token, with SPIRE's five-minute default JWT-SVID TTL comfortably inside Anthropic's one-hour identity-token ceiling. That is the full pattern in one integration: attested workload identity in, scoped API credential out, zero static secrets anywhere in the chain.

spire-server entry create \
  -spiffeID spiffe://prod.example.com/ns/inference/sa/agent-worker \
  -parentID spiffe://prod.example.com/k8s-workload/cluster/nodes \
  -selector k8s:ns:inference \
  -selector k8s:sa:agent-worker \
  -selector k8s:pod-label:app:inference-agent

Honest weaknesses.

Who should skip: single-team fleets on one managed Kubernetes service — the cloud's native workload identity (EKS/GKE/AKS projected tokens) gives you 80% of the benefit with none of the control plane. SPIFFE/SPIRE earns its cost when you are multi-cloud, multi-cluster, or need one identity system across VMs and Kubernetes. If your agents all run inside one cluster and call one vendor API, a managed workload identity plus token exchange is the pragmatic stack.

Pattern 5 — A2A: Declarative Security Schemes, Out-of-Band Credentials

Agent-to-agent protocols (A2A) take the opposite tack from MCP: instead of specifying the OAuth machinery, A2A delegates. An A2A server publishes an Agent Card — a JSON document at a well-known URI — declaring which security schemes it accepts: API key, HTTP auth (basic/bearer), OAuth 2.0, OpenID Connect, or mutual TLS. Credential acquisition is explicitly out-of-band: the client agent obtains tokens "through processes external to the A2A protocol itself," and identity travels in HTTP headers, never inside the JSON-RPC payload. The security field composes schemes as an OR-of-ANDs — "callers must use OAuth, or an API key plus mTLS" — which is expressive enough for real enterprise posture.

{
  "name": "compliance-reviewer",
  "url": "https://agents.internal.example.com/a2a/v1",
  "securitySchemes": {
    "oauth": {
      "oauth2SecurityScheme": {
        "type": "oauth2",
        "flows": {
          "clientCredentials": {
            "tokenUrl": "https://auth.example.com/token",
            "scopes": { "a2a:invoke": "Invoke this agent" }
          }
        }
      }
    },
    "mtls": { "mtlsSecurityScheme": { "type": "mutualTLS" } }
  },
  "security": [ { "oauth": ["a2a:invoke"] }, { "mtls": [] } ]
}

Honest weaknesses.

Who should skip: internal fleets where agents are built by one team — direct service-to-service auth (SPIFFE mTLS, Patterns 1–2) is simpler than discovering each other's cards. A2A's declarative model earns its keep when agents from different owners/vendors must interoperate without prior integration.

The Vendor Layer Is Converging — Fast

Eighteen months ago "agent identity" was a conference talk; as of October 2026 it is a SKU category with shipping GA products. The convergence is on the same primitives this guide describes — OAuth exchange, SPIFFE attestation, IdP-brokered consent:

VendorProduct (Oct 2026)Standards anchorCommercial shapeThe honest catch
MicrosoftEntra Agent ID (in Agent 365 / M365 E7)OAuth client credentials + OBO via Federated Identity CredentialsAgent 365 $15/user/mo standalone; M365 E7 $99/user/mo; foundational agent capabilities free with any Microsoft Cloud subscription (as of Oct 2026, microsoft.com)Licensed per human user, not per agent — cheap at scale, but full governance rides on an E5-class baseline
OktaOkta for AI Agents + Agent SSOCross App Access (IETF ID-JAG draft) + MCP Enterprise-Managed Authorization extensionAgent SSO included in core Okta SSO; the full for-AI-Agents suite is a separate subscription (no public list price)The free tier governs only agents that speak Cross App Access; shadow-agent discovery and the runtime kill switch land through the paid suite (gateway GA planned Q3 2026 and expanded kill switch Q4 2026, per Oktane announcements)
AWSBedrock AgentCore IdentityRFC 8693 token exchange + RFC 7523 JWT-bearer OBOUsage-based AWS service pricing — verify current rates on the Bedrock AgentCore pricing page before committingPer-IdP integration variance is real (the Okta subject_token_type mismatch ships in the default config); 14 GA Regions at announcement, not global
Google CloudAgent Identity (with Agent Gateway / Gemini Enterprise)SPIFFE IDs, cert-bound tokens, mTLS + DPoP, IAM/PAB/VPC-SC integrationBundled with Google's agent platform rather than metered standaloneDeeply GCP-anchored — the strongest token-binding story of the four, and the least portable

Two things stand out. First, per-user licensing (Microsoft) vs per-subscription suites (Okta) is a real cost-model fork — on a 1,000-employee estate, Agent 365 standalone is $15,000/month at list, which is $180,000/year before the E5-class baseline most of its advanced features assume. Second, every one of these products assumes agents connect through their gateway or registry; if your fleet spans clouds, the IdP-neutral patterns in this guide (raw RFC 8693, SPIFFE) are the only layer that does not lock you to one vendor's agent platform. The managed offerings are a control plane on top of the same primitives — worth renting when your estate is single-vendor, worth bypassing when it is not.

The Zero-Trust Checklist for Agent Fleets

Compressed to what actually changes in production:

ControlAPI-key fleetZero-trust agent fleet
Bootstrap credentialStatic key in env/secrets storeAttested identity (SPIFFE SVID or managed workload identity) — no secret to leak
Session credentialSame key, foreverShort-lived, audience-bound OAuth token per downstream system
DelegationNone — agent borrows the user's power invisiblyRFC 8693 composite tokens: sub = mandate, act = actor, nested chain for audit
Downstream validation"Key matches → allow"Audience check (RFC 8707), current-actor policy, per-request scopes where supported
RevocationHunt the key across every consumerDeactivate the agent identity at the IdP/gateway — one switch, sessions die at next token refresh
Audit question"Someone with this key did it""Agent X, actor Y, acting for user Z, audience W, at time T"
OwnershipNobodyA named human owner per agent identity — the control both Okta and Microsoft lead with

None of this requires adopting every pattern at once. The honest sequencing for most fleets: kill shared static keys first (client credentials or managed workload identity), add token exchange where agents act on user data, adopt the MCP authorization mandates before your tool servers multiply, and reserve SPIFFE/SPIRE for the multi-cluster reality that makes attestation worth its operational price. What is not on the table is standing pat — the window between agents gaining production access and organizations giving them real identities is exactly where the incidents Okta's research measured are happening.