Tie Together A2A Security, Tasks, and Tenant Ownership
An Agent Card may declare an API key, HTTP auth, OAuth2, OpenID Connect, or mTLS. But it's easy to relax too early here: a security scheme decides only the method of authentication - who came in. It says nothing about what that subject is allowed to do. So every Task, Message, and Artifact must be tied to a verified principal and tenant, not just pass the entrance.
The scheme is declared in the card roughly like this - through OIDC with a required scope.
{
"securitySchemes": {
"corporateOidc": {
"openIdConnectSecurityScheme": {
"openIdConnectUrl": "https://id.example.com/.well-known/openid-configuration"
}
}
},
"securityRequirements": [
{
"schemes": {
"corporateOidc": {
"list": [
"release.review"
]
}
}
}
]
}And then the real work begins - authorization invariants on every operation.
Object · Authorization invariant
- Agent Card - A public card doesn't reveal private skills/secrets; an extended card requires auth
- SendMessage - The principal has the right to the skill and the input data
- Get/List Task - The task belongs to the principal/tenant; not-found doesn't reveal a foreign id
- Cancel Task - The caller owns the task and the state allows cancel
- Artifact - Parts pass DLP/media/size policy before return
- Push config - The callback is allowed by policy and tied to the task owner
Read the table as a checklist the code must run itself. A public card doesn't reveal private skills and secrets. SendMessage checks the principal's right to the skill and the input data. Get/List Task returns only the tasks of that principal/tenant, and to a foreign id answers not-found, without revealing existence. Cancel checks ownership and the state's admissibility. An artifact passes DLP, media, and size policy before it's returned.
Separately - about versions and bindings. A2A 1.0 separates the common data model, the operations, and the concrete bindings; the client passes service parameters, including the version and extensions, by the binding's rules. Don't mix pre-1.0 examples with the current card: in 1.0, for instance, extendedAgentCard lives inside capabilities.
A task id is not a secret. Even a UUID can't be treated as authorization. Any Get/Cancel/List must check the verified owner - otherwise a leaked id instantly turns into a leak of artifacts.
Both boundaries of the system are assembled and defended separately. The final step is to compose them into one production architecture and prove they're truly independent.
The client knows a taskId (a UUID). Can Get Task be allowed based on it?