When one AI agent calls another, the receiving agent has to decide who is calling, on whose behalf and with what rights, and a static shared API key answers none of those questions well. Agent-to-agent traffic is service-to-service traffic with two extra problems: requests often carry a human user's authority through several hops, and agents discover each other dynamically from published descriptions rather than fixed configuration. This guide covers how the Agent2Agent (A2A) protocol handles authentication, how to choose between API keys, OAuth client credentials, mutual TLS, DPoP and SPIFFE identities, how to carry user context safely across a chain with token exchange, and how to verify Agent Cards and callbacks. It is for architects, identity engineers and platform teams building or connecting backend agents. Broader multi-agent risks such as trust boundaries and orchestration are covered in the Multi-Agent and A2A Security Guide; this page stays on proving identity.
Key takeaways
- A2A does not invent its own identity layer. The specification puts identity at the transport and HTTP layer: the server declares schemes in its Agent Card, the client gets credentials out of band, and the server must authenticate every request.
- Prefer proof of possession over bearer secrets. RFC 9700 recommends sender-constrained tokens (mTLS under RFC 8705 or DPoP under RFC 9449) and asymmetric client authentication, so a stolen token cannot simply be replayed.
- Two identities usually travel together. The calling agent's workload identity and the user it acts for should be separate, verifiable claims, for example an mTLS or SPIFFE identity plus an exchanged token with an
actclaim. - Audience restriction stops token forwarding. A token minted for agent B must be rejected by agent C. Mint one token per hop with a single audience instead of passing the original token down the chain.
- Agent Cards and webhooks are attack surface. Verify JWS signatures on Agent Cards, require authentication for the extended card, and authenticate and SSRF-check push notification callbacks.
What agent-to-agent authentication has to prove
A single call between agents raises four separate questions. Mixing them up is the root of most designs that look secure but are not.
| Question | Proved by | Typical mechanism |
|---|---|---|
| Is the server the agent I meant to reach? | Server authentication | TLS certificate validation against trusted CAs; SPIFFE ID check in mTLS |
| Which agent or workload is calling? | Client (agent) authentication | mTLS client certificate, private_key_jwt, JWT-SVID, OAuth client credentials |
| Whose authority is being used? | Delegation | OAuth token exchange (RFC 8693) with sub for the user and act for the agent |
| Is the description or message authentic? | Integrity | JWS signature on the Agent Card; TLS for messages in transit |
Authentication only establishes identity. What the caller may do is a separate decision the receiving agent must make on every request, based on the authenticated identity, the requested skill and the data involved. See the AI Agent Authorisation Guide.
How A2A handles authentication
The A2A specification (latest released version 1.0.0) treats agents as standard enterprise applications. The enterprise guidance states that A2A payloads such as JSON-RPC messages do not carry user or client identity; identity is established at the transport or HTTP layer.
- Transport: production deployments must use encrypted communication (HTTPS for HTTP bindings, TLS for gRPC), with TLS 1.3 or later recommended in the specification. Clients should validate the server's TLS certificate against trusted CAs.
- Discovery of requirements: the client reads the server's
securitySchemesandsecurityRequirementsfrom the Agent Card, normally served athttps://{server_domain}/.well-known/agent-card.json. - Out-of-band credentials: the client obtains credentials (for example an OAuth token) through a process outside A2A and sends them in protocol headers on every request, such as
Authorization: Bearer. - Server duties: the server must authenticate every incoming request. The enterprise guidance says to return
401 Unauthorizedwith aWWW-Authenticateheader for missing or invalid credentials and403 Forbiddenwhen valid credentials lack permission. - Authorisation: implementation specific, and may consider the requested skill, the actions attempted, data access policies and OAuth scopes. The guidance suggests scopes that grant some skills and not others.
- Versioning: clients send the
A2A-Versionheader; an empty value is interpreted as 0.3. Pin the version you have reviewed rather than allowing silent fallback.
| A2A security scheme | What it declares | Assessment for agent-to-agent use |
|---|---|---|
APIKeySecurityScheme | Static key in a header, query or cookie | Weakest: no expiry, no proof of possession, no user context. Acceptable only for low-risk internal pilots |
HTTPAuthSecurityScheme | HTTP authentication such as Bearer | Depends on the token behind it; bearer tokens are replayable if stolen |
OAuth2SecurityScheme | Authorisation code, client credentials or device code flows | Client credentials for agent identity; authorisation code where a user consents; combine with token exchange for delegation |
OpenIdConnectSecurityScheme | OIDC discovery URL | Useful where the calling agent presents a user's identity; ID tokens are not access tokens |
MutualTlsSecurityScheme | Client certificate at the TLS layer | Strong workload authentication, pairs well with SPIFFE X.509 SVIDs and certificate-bound tokens |
Choosing a credential for the calling agent
| Option | Replay resistance | Secret to protect | User context | Best fit |
|---|---|---|---|---|
| Static API key | None | Shared symmetric secret | No | Short pilots only |
OAuth client credentials with client_secret | Low (bearer token) | Client secret plus tokens | No | Simple internal calls with short token lifetimes |
OAuth with private_key_jwt (RFC 7523) | Token is still bearer unless also constrained | Private key, never sent | Via token exchange | Cross-organisation agents with their own authorisation server registration |
| mTLS client auth and certificate-bound tokens (RFC 8705) | High: token bound by cnf x5t#S256 | Private key | Via token exchange | Service mesh and data centre traffic where you control TLS termination |
| DPoP (RFC 9449) | High: per-request proof bound by cnf jkt | Private key | Via token exchange | Agents behind TLS-terminating proxies, or across networks where mTLS is hard |
| SPIFFE X.509-SVID | High at transport layer | Short-lived key issued by the platform | No | Agents running as workloads inside one or federated trust domains |
| SPIFFE JWT-SVID | Low (bearer), limited by aud and exp | None stored long term | No | Layer 7 hops where mTLS cannot be end to end |
Decision guidance
- Inside one platform you control: use mTLS with SPIFFE X.509-SVIDs for agent identity. An X.509-SVID must contain exactly one URI SAN, and validators must reject certificates with more than one, so the authorisation decision keys on a single
spiffe://trust-domain/pathvalue. See the SPIFFE and SPIRE Guide and the mTLS Guide. - Across organisations: use OAuth at the receiving organisation's authorisation server with asymmetric client authentication (
private_key_jwtortls_client_auth) and sender-constrained access tokens. RFC 9700 names mTLS and DPoP as the two sender-constraining methods. - When TLS terminates at a gateway: certificate binding is lost at the proxy unless the gateway forwards and the backend trusts the client certificate. DPoP survives this because the proof travels in the
DPoPheader. - When the caller acts for a user: add token exchange on top of whichever workload credential you choose; do not try to encode the user in the workload credential.
- Small versus large organisations: a small team with a few agents can run OAuth client credentials with
private_key_jwt, tokens of minutes not hours, and a gateway that checks audience. A large estate should invest in a workload identity platform (SPIFFE or cloud-native workload identity) so no agent holds a long-lived secret. See the Cloud Workload Identity Guide and the Machine-to-Machine OAuth (Client Credentials) Guide.
Proof-of-possession details that matter
- RFC 8705: with
tls_client_auththe server validates the certificate chain and matches one registered subject value, such astls_client_auth_san_uri, which can hold a SPIFFE ID. Withself_signed_tls_client_auththe client registers certificates throughjwksorjwks_uri. Servers advertisetls_client_certificate_bound_access_tokens; a resource server that sees a certificate mismatch returns 401 withinvalid_token. - RFC 9449: each request carries a fresh proof JWT with
typdpop+jwt, an asymmetricalg, and claimsjti,htm,htu,iat, plusath(hash of the access token) when a token is presented. Servers can issue aDPoP-Nonceto limit pre-generated proofs, and must reject a DPoP-bound token presented as a plain Bearer token. DPoP does not protect the message body and cannot stop code running inside the client. - JWT-SVID:
audandexpare mandatory and tokens without them must be rejected. The specification warns that a token with audiences Bob and Chuck lets Chuck impersonate the caller to Bob, so single-audience tokens are strongly recommended.
Carrying user context across agent chains
The riskiest pattern in multi-agent systems is forwarding the user's original access token from agent to agent. Every agent that sees it can use it anywhere its audience allows, and the final service cannot tell which agent made the call.
- Exchange at each hop: the calling agent sends the incoming token as
subject_tokenand its own credential asactor_tokento the token endpoint withgrant_type=urn:ietf:params:oauth:grant-type:token-exchange, naming the next agent inaudienceorresource. - Record the chain: the issued token's
actclaim identifies the current actor; nestedactclaims record earlier actors. RFC 8693 says only top-level claims and the current actor should be used for access control, with earlier actors informational. Log the whole chain anyway. - Pre-authorise delegation: use the
may_actclaim or authorisation server policy so only named agents may act for a subject. - Narrow every hop: request fewer scopes than the incoming token held, and use
authorization_details(RFC 9396) where the action needs fine-grained limits. - Keep lifetimes short: exchanged tokens should live for the task, not the session.
See the OAuth Token Exchange and Delegation Guide.
In-task authorisation in A2A
TASK_STATE_AUTH_REQUIRED: an agent that needs extra authorisation mid-task (an OAuth token for another API, or human approval) moves the task to this state, and the client can fulfil, negotiate or reject the request, or pass it up its own chain.- Out of band by default: the specification says agents should receive these credentials out of band over a secure channel. If in-band exchange is negotiated, credentials should be bound to the originating agent and encrypted so only that agent can read them, because in-band credentials are otherwise exposed to every agent in the chain.
- The state is not a grant: agents must not treat the state transition as authorisation, and a credential obtained this way must not be assumed to authorise later messages on the task unless the implementation defines it.
Pair high-impact steps with a human approval. See the Human-in-the-Loop for AI Agents Guide.
Verifying Agent Cards, extended cards and callbacks
- Signed Agent Cards: cards may be signed with JWS (RFC 7515) after canonicalisation with JCS (RFC 8785), excluding the
signaturesfield. The protected header must includealg,typandkid, and may includejku. Clients should verify at least one signature before trusting a card, fetch keys over HTTPS, and must not use expired or revoked keys. Pin trusted keys per provider rather than trusting anyjkuthe card names. - Treat card content as untrusted input: skill descriptions flow into a calling model's context, so a tampered or malicious card is an indirect prompt injection route (ATLAS AML.T0051.001). See the Prompt Injection Guide.
- Extended Agent Card: the authenticated card (available when
capabilities.extendedAgentCardis true) must require authentication using a scheme from the public card. Do not put anything in the public card you would not publish. - Push notifications: the agent must include authentication credentials in webhook requests and should validate webhook URLs against SSRF by rejecting 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, localhost and link-local addresses. The receiving client must validate webhook authenticity and should check the task ID matches a task it created. Use a unique, single-purpose token per push configuration and rotate it.
Implementation roadmap
- Inventory (weeks 1 to 2): list every agent endpoint, its Agent Card, declared schemes, credential type, token lifetime and who issues it. Flag API keys, long-lived secrets and forwarded user tokens.
- Establish workload identity (weeks 2 to 6): issue SPIFFE IDs or cloud workload identities to agents, with a path convention such as
spiffe://example.org/agents/billing. Start mTLS in permissive mode and log which callers would fail. - Move to OAuth with constrained tokens: register each agent as a client with
private_key_jwtortls_client_auth, enable certificate-bound or DPoP-bound tokens, and set audience per receiving agent. Run resource servers in dual mode (accept old and new) for a fixed window. - Add delegation: introduce token exchange for user-context calls, enforce
may_actpolicy and reduce scopes per hop. - Enforce: switch mTLS to strict, reject bearer use of bound tokens, retire API keys. Roll back per agent by re-enabling dual mode at the gateway, not by reissuing long-lived secrets.
- Sign and pin cards: sign Agent Cards in the release pipeline and configure clients to verify against pinned keys.
Detection and measurement
- Log on both sides: the A2A enterprise guidance recommends logging task IDs, session IDs, correlation IDs and trace context, and propagating W3C Trace Context with OpenTelemetry. Add the authenticated agent identity (SPIFFE ID or client ID), the subject, the full
actchain and the token'sjti. - Alert on: 401 and 403 spikes per caller; the same token
jtior DPoP proofjtiseen twice; tokens presented to the wrong audience; a client certificate or key used from a new network location; Agent Card signature failures; webhook registrations pointing at internal or unexpected hosts. - Watch the authorisation server: token exchange requests where
may_actpolicy was denied, and new client registrations.
| Metric | Target |
|---|---|
| Agent-to-agent calls using sender-constrained tokens or mTLS | 100% of production traffic |
| Agents still authenticating with static API keys | Zero, tracked to a date |
| Median access token lifetime on agent hops | Minutes, not hours |
User-context calls carrying an act claim instead of a forwarded token | 100% |
| Agent Cards signed and verified by callers | All external-facing agents |
| Wrong-audience or replay rejections investigated | Every event triaged within one working day |
See the AI Agent Observability and Incident Response Guide.
Framework mapping
| Threat | ATT&CK / ATLAS | NIST SP 800-53 Rev. 5 | NIST CSF 2.0 | Control in this guide |
|---|---|---|---|---|
| Stolen agent token replayed | T1528 Steal Application Access Token, T1550.001 Application Access Token | IA-5, SC-23 | PR.AA-03 | mTLS or DPoP binding, short lifetimes |
| Impersonated or spoofed agent endpoint | T1557 Adversary-in-the-Middle | IA-9, SC-8, SC-17 | PR.DS-02 | TLS validation, SPIFFE ID checks, signed cards |
| Forged tokens or cards | T1606 Forge Web Credentials | SC-12, IA-5 | PR.AA-01 | Key management, pinned signing keys |
| Abuse through a trusted partner agent | T1199 Trusted Relationship | AC-6, AC-4 | PR.AA-05 | Audience restriction, per-hop scopes, may_act |
| Injected instructions from peer agents or cards | AML.T0051.001 Indirect | SI-10 | DE.CM-09 | Treat card and message content as untrusted |
| Missing attribution in chains | Not applicable | AU-2, AU-12 | DE.CM-03 | act chain logging, trace context |
OWASP LLM06:2025 Excessive Agency lists a malicious or compromised peer agent in multi-agent systems as a trigger, which is why receiving agents must authorise each request rather than trusting the caller. In CIS Controls v8.1 this work sits under Control 5 (Account Management) and Control 6 (Access Control Management); in ISO/IEC 27001:2022 Annex A under A.5.17 (Authentication information), A.8.5 (Secure authentication) and A.8.15 (Logging).
Common failure patterns
- Forwarding the user's token: the orchestrator passes the user's access token to every sub-agent. Any compromised sub-agent can call any service in that token's audience as the user.
- One shared key across agents: every agent in a mesh uses the same API key or client secret, so logs cannot attribute calls and revoking one agent means revoking all of them.
- Multi-audience tokens: a token valid for several agents lets any recipient replay it to the others, exactly the scenario the JWT-SVID specification warns about.
- Trusting the Agent Card URL alone: clients accept any card served over HTTPS, or follow a
jkuto an attacker-controlled key set, instead of pinning provider keys. - Treating
TASK_STATE_AUTH_REQUIREDas consent: an agent proceeds with a destructive action because the client "answered", without checking what was actually authorised. - Unauthenticated callbacks: push notification endpoints that accept any POST, or agents that will call internal URLs supplied by a client.
Lessons from incidents
The Salesloft Drift breach was not an agent-to-agent attack, but it shows what bearer tokens held by an integration mean in practice: the attacker took OAuth tokens from the vendor's environment and called customers' Salesforce APIs as the trusted app, so customer MFA and SSO were never tested. Agent meshes concentrate tokens in the same way. Sender-constrained tokens, short lifetimes, audience restriction and network-bound policies are the controls that would have made those stolen tokens far less useful. See the OAuth Token Theft Incident Playbook.
Practitioner checklist
- Inventory every agent endpoint, its declared
securitySchemesand the credential each caller uses. - Give each agent its own workload identity (SPIFFE ID or cloud workload identity) and its own OAuth client.
- Use asymmetric client authentication (
private_key_jwtortls_client_auth) instead of client secrets. - Issue sender-constrained tokens (mTLS-bound or DPoP) and reject bound tokens presented as Bearer.
- Restrict every token to a single receiving agent's audience and keep lifetimes to minutes.
- Use token exchange with
actandmay_actfor user-context calls; never forward the original token. - Authenticate every A2A request and authorise per skill and per action, returning 401 or 403 correctly.
- Sign Agent Cards in the release pipeline and verify them against pinned keys in clients.
- Authenticate push notifications both ways and block private, loopback and link-local webhook targets.
- Log agent identity, subject,
actchain and trace context, and alert on replay and wrong-audience events.
Standards and references
- A2A Project: Agent2Agent (A2A) Protocol Specification
- A2A Project: Enterprise Implementation of A2A
- IETF: RFC 9700 Best Current Practice for OAuth 2.0 Security
- IETF: RFC 8693 OAuth 2.0 Token Exchange
- IETF: RFC 8705 OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens
- IETF: RFC 9449 OAuth 2.0 Demonstrating Proof of Possession (DPoP)
- SPIFFE: SPIFFE ID, X509-SVID and JWT-SVID standards
- NIST: SP 800-53 Rev. 5
Related NHI Mgmt Group resources: Multi-Agent and A2A Security Guide · NHI Authentication Guide · Securing Agent Frameworks Guide · Credential Vaulting for AI Agents Guide · AI Agent Tool and Plugin Security Guide