How does authentication work with A2A protocol?
how does authentication work on this protocol? say i'm using next.js and i wanna implement this from two different next.js apps. one of them will call the agent in app A and tell it "hey i'm available for this [agent] turn"
Now I have a comprehensive understanding. Let me put this all together for you.
##How Authentication Works in A2A
The A2A protocol does not invent its own auth. It delegates entirely to standard web authentication mechanisms (OAuth 2.0, API keys, OpenID Connect, mTLS, etc.) and passes credentials via normal HTTP headers. Here's the full picture:
###1. Agent Card Declares Auth Requirements
Every A2A server publishes an Agent Card — a JSON metadata document (think of it as a "business card" for your agent). This card declares its securitySchemes and security requirements. From the spec (specification/a2a.proto L383-386):
// The security scheme details used for authenticating with this agent.
map<string, SecurityScheme> security_schemes = 8;
// Security requirements for contacting the agent.
repeated SecurityRequirement security_requirements = 9;
The supported scheme types (specification/a2a.proto L498-511) are:
| Scheme | Use Case |
|---|---|
APIKeySecurityScheme | Simple API key (in header, query, or cookie) |
HTTPAuthSecurityScheme | HTTP auth like Bearer tokens |
OAuth2SecurityScheme | Full OAuth 2.0 flows (Authorization Code w/ PKCE, Client Credentials, Device Code, etc.) |
OpenIdConnectSecurityScheme | OpenID Connect Discovery |
MutualTlsSecurityScheme | mTLS |
A concrete example from the spec looks like this:
{
"securitySchemes": {
"google": {
"openIdConnectSecurityScheme": {
"openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration"
}
}
},
"security": [{ "google": ["openid", "profile", "email"] }]
}
###2. The Auth Flow (Three Steps)
From the spec (Section 7.3):
- Discovery: Client fetches the Agent Card (e.g.
GET /.well-known/agent-card.json) and reads thesecuritySchemesfield to learn how to authenticate. - Credential Acquisition (Out-of-Band): The client obtains credentials outside of the A2A protocol. This means your standard OAuth 2.0 token exchange, API key distribution, etc.
- Credential Transmission: Client includes credentials in HTTP headers (e.g.
Authorization: Bearer <TOKEN>) on every A2A request.
Critical principle: No identity in the payload. A2A JSON-RPC messages never carry user/client identity. Identity is established entirely at the HTTP transport layer (enterprise-ready.md L34-36):
A2A protocol payloads, such as
JSON-RPCmessages, don't carry user or client identity information directly. Identity is established at the transport/HTTP layer.
###3. Server Validates Every Request
The server MUST authenticate every incoming request. On failure, it returns:
401 Unauthorized(withWWW-Authenticateheader) — missing/invalid creds403 Forbidden— valid creds but insufficient permissions
###4. In-Task Auth (AUTH_REQUIRED state)
There's also a mid-task authentication mechanism. If during task execution, the agent needs additional credentials (e.g., to access a third-party service on the user's behalf), it transitions the task to TASK_STATE_AUTH_REQUIRED — an interrupted state. The client then obtains those secondary credentials out-of-band and provides them in a subsequent message.
##Your Next.js Two-App Scenario
Say you have:
- App A (Next.js) — hosts Agent A (an A2A server)
- App B (Next.js) — hosts Agent B (an A2A server), and also acts as an A2A client calling Agent A
Here's how "App B tells Agent A: hey I'm available for this turn" would work:
###Step 1: Agent A publishes its Agent Card
App A serves an Agent Card at https://app-a.example.com/.well-known/agent-card.json:
{
"name": "Agent A",
"supportedInterfaces": [
{ "url": "https://app-a.example.com/a2a", "protocolBinding": "JSONRPC", "protocolVersion": "1.0" }
],
"version": "1.0.0",
"capabilities": { "streaming": true },
"securitySchemes": {
"bearer": {
"httpAuthSecurityScheme": {
"scheme": "Bearer",
"bearerFormat": "JWT"
}
}
},
"security": [{ "bearer": [] }],
"defaultInputModes": ["text/plain"],
"defaultOutputModes": ["text/plain"],
"skills": [{ "id": "some-skill", "name": "Some Skill", "description": "..." }]
}
###Step 2: App B discovers Agent A and obtains credentials
App B fetches the agent card, reads the securitySchemes, sees it needs a Bearer token, and obtains one through whatever mechanism you've set up (e.g., client credentials OAuth flow against your shared auth server, or a pre-shared API key — it's all out-of-band from A2A's perspective).
###Step 3: App B sends a message to Agent A
App B makes a JSON-RPC call to Agent A's endpoint with the auth token in the Authorization header:
POST /a2a HTTP/1.1
Host: app-a.example.com
Authorization: Bearer eyJhbG...
Content-Type: application/json
{
"jsonrpc": "2.0",
"method": "SendMessage",
"id": "1",
"params": {
"message": {
"role": "user",
"parts": [{ "text": "Hey, I'm Agent B and I'm available for task X" }]
}
}
}
###Step 4: Agent A validates and responds
Agent A's server validates the Bearer token, authorizes the request, and processes it. It can scope what Agent B sees based on the authenticated identity (per Section 13.1 — all operations must be scoped to the authenticated caller's authorization boundaries).
###The Key Thing to Understand
A2A doesn't define a "registration" or "I'm available" mechanism — agents discover each other via Agent Cards, and the protocol is essentially task-based (SendMessage → creates/continues a Task). So "I'm available for this turn" would be modeled as:
- Agent B calls Agent A using
SendMessage(B is the client, A is the server) - Or if Agent A needs to call back to B, Agent A acts as a client and discovers Agent B's Agent Card, authenticates, and sends messages to B
Each direction requires its own auth. If both apps need to call each other, each publishes its own Agent Card with its own security requirements, and each obtains credentials for the other. There's no bidirectional channel — it's standard HTTP request/response (or SSE for streaming).
For push-based callbacks (e.g., Agent A notifying Agent B when a task changes), the protocol has Push Notifications with their own AuthenticationInfo — the client (B) provides a webhook URL + auth details, and the server (A) authenticates itself to that webhook when pushing notifications.
END OF POST