Security schemes and in-task authorization
The card declares which credentials an agent accepts, HTTP checks them on every request, and a running task can still stop to ask for an approval.
The planner's last delegation goes to deployer, the only agent in the kit that guards its endpoint. A request without a token gets HTTP 401 before any A2A method runs. A request with the token starts a deploy that stops again, in TASK_STATE_AUTH_REQUIRED, until an operator approves it.
Figure 6.1 follows that credential from the card to the approval. When you finish this section, you can read a card's security fields, send what they ask for, and scope tasks to their owner.
What the card declares
Only the deployer's card carries security fields, so test-runner and code-reviewer accept any caller.
"securitySchemes": {
"bearer": {
"httpAuthSecurityScheme": {
"description": "A token issued by the platform team.",
"scheme": "Bearer"
}
}
},
"securityRequirements": [
{
"schemes": {
"bearer": {
"list": []
}
}
}
],Security scheme: one entry in the card's securitySchemes map. The key, here bearer, is a name the agent picks. The value holds exactly one of five variants: apiKeySecurityScheme, httpAuthSecurityScheme, oauth2SecurityScheme, openIdConnectSecurityScheme, or mtlsSecurityScheme.
Security requirement: one entry in securityRequirements. Its schemes map names schemes from securitySchemes, and each name maps to "the required scopes" in a StringList whose only field is list. The deployer names bearer with an empty list, so the token alone is enough.
The §8.5 sample card still says security where the proto says securityRequirements (conflict D6). The migration guide calls the implicit and password flows removed, while the proto keeps both as deprecated (conflict D11), so offer neither.
How credentials travel
The client gets the credential outside A2A and sends it in the headers or metadata of the transport on every A2A request. That header carries a secret, so a production deployment must encrypt its traffic: HTTPS for the HTTP bindings, and TLS for gRPC. The specification recommends TLS 1.3 or later, and the enterprise guide TLS 1.2 or later (conflict D18).
Without it, deployer answers HTTP 401 with a WWW-Authenticate challenge before any A2A method runs, as extended cards and signatures shows.
Authorization scope: a task you cannot see does not exist
Each implementation decides its own authorization logic. The specification fixes how a refusal looks: a server must not reveal that a resource exists when the client has no access to it. So another caller's task gets the same TaskNotFoundError as a task that never existed. The same section lists one case for an authorization error: access to a task that another user created. That error would confirm that the task exists (conflict D36). Answer with the not-found error.
The check runs first: authorization checks must happen before any database query or operation that could leak information. ListTasks must scope its results to the caller even when the request has no filter. The SDKs differ on who the owner is:
| Implementation | Owner scope | Another caller's task |
|---|---|---|
| Kit | none, and the deployer needs one shared bearer token | returned |
| a2a-python 1.2.2 | task stores keyed by the call context's user_name, and every unauthenticated caller has the empty name | TaskNotFoundError |
| a2a-js 1.3.0 | tenant and owner in every store, with unknown for an anonymous caller | TaskNotFoundError |
| a2a-java 1.4.0.Final | a TaskAuthorizationProvider interface with no implementation in the release, and without one every task operation fails closed | TaskNotFoundError |
| a2a-go 2.6.0 | the in-memory store records the call's user name, and an empty name makes ListTasks fail with ErrUnauthenticated | ErrTaskNotFound once a name is set |
| a2a-dotnet 1.0.0-preview2 | none, because the store and the handler carry no principal | returned |
| a2a-rs a2a-server-lf-v0.5.1 | none in the stores, and an opt-in RequestAuthorizer sees only the headers and the task id | returned |
Without an authentication middleware that fills in the user, every task is visible to every caller.
In-task authorization
In-task authorization: an agent's request for permission partway through a task, through TASK_STATE_AUTH_REQUIRED, which interrupted states follows frame by frame. The kit's POST /approve/<task id> checks no credentials, so anyone who learns the task id can approve. A real approval channel authenticates the operator and records who approved.
A client that is itself an agent can pass the request up a chain of tasks in TASK_STATE_AUTH_REQUIRED. An in-band credential then passes through every agent in the chain. So bind it to the agent that asked, and only that agent can use it.
PR #2081 added §7.6.4 to main on 2026-07-30, after v1.0.1, and no release carries it yet. It says that an agent must not treat the move to TASK_STATE_AUTH_REQUIRED on its own as permission for any operation. A credential obtained there does not authorize later messages unless the implementation, the issuer, or an extension says so. The kit keys each approval by task id, so one approval resumes one deploy, and its bearer check runs on every later request.
A2A protocol 1.0.1 · 3303592 · 2026-05-28 · Edition 2026.10