A2A SecurityScheme: Declaring How Clients Authenticate

A2A SecurityScheme: Declaring How Clients Authenticate

An A2A Agent Card does not authenticate anything by itself. It declares how: securitySchemes defines named authentication methods, and securityRequirements says which of them a client must satisfy. The client reads both from the Agent Card , obtains credentials out-of-band, and sends them with every request. The server MUST authenticate every incoming request.

This page covers the objects. For the runtime rules, such as authorization scoping and in-task authorization, read Authentication, Authorization, and Security Considerations .

Three fields, three jobs

WhereFieldTypeJob
Agent CardsecuritySchemesmap of name to SecuritySchemeDefine the methods you accept, under names you choose
Agent CardsecurityRequirementslist of SecurityRequirementState which defined schemes, and scopes, a client must satisfy
AgentSkillsecurityRequirementslist of SecurityRequirementThe same, for one skill (see AgentSkill )

A SecurityRequirement has one field, schemes: a map from a scheme name to { "list": [...] }, the list of required scopes. This is the specification’s sample card, which defines an OpenID Connect scheme named google and requires it with three scopes:

"securitySchemes": {
  "google": {
    "openIdConnectSecurityScheme": {
      "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration"
    }
  }
},
"securityRequirements": [{ "schemes": { "google": { "list": ["openid", "profile", "email"] } } }]

The specification does not say how several entries in securityRequirements combine, so do not assume AND or OR semantics from the structure alone.

The five scheme types

SecurityScheme is a discriminated union (a protobuf oneof) based on the OpenAPI 3.2 Security Scheme Object. Each entry in securitySchemes sets exactly one of these keys:

JSON keyRequired fieldsOptional fields
apiKeySecuritySchemelocation (query, header, or cookie) and name (the parameter’s name)description
httpAuthSecuritySchemescheme (an RFC 7235 scheme name such as Bearer, which should be in the IANA registry)bearerFormat (for example JWT, documentation only) and description
oauth2SecuritySchemeflowsoauth2MetadataUrl (RFC 8414 authorization server metadata, TLS required) and description
openIdConnectSecuritySchemeopenIdConnectUrl (the OpenID Connect Discovery URL)description
mtlsSecuritySchemenonedescription

The specification gives a JSON example only for OpenID Connect. The next snippet is illustrative: it is built from the proto field names in the table, not copied from the official documents, and shows an HTTP Bearer scheme.

"securitySchemes": {
  "bearerAuth": {
    "httpAuthSecurityScheme": { "scheme": "Bearer", "bearerFormat": "JWT" }
  }
},
"securityRequirements": [{ "schemes": { "bearerAuth": { "list": [] } } }]

OAuth 2.0 flows

OAuthFlows is also a oneof: an oauth2SecurityScheme sets one flow under flows. In the v1.0.1 proto:

JSON keyRequired fieldsOptional fieldsStatus
authorizationCodeauthorizationUrl, tokenUrl, scopesrefreshUrl, pkceRequiredCurrent
clientCredentialstokenUrl, scopesrefreshUrlCurrent
deviceCodedeviceAuthorizationUrl, tokenUrl, scopesrefreshUrlCurrent; for CLI tools and input-constrained devices (RFC 8628)
implicitnone markedauthorizationUrl, refreshUrl, scopesDeprecated: “Use Authorization Code + PKCE instead”
passwordnone markedtokenUrl, refreshUrl, scopesDeprecated: “Use Authorization Code + PKCE or Device Code”

scopes maps a scope name to a short description. pkceRequired says whether PKCE (RFC 7636) is mandatory for the flow; the proto adds that PKCE should always be used for public clients and is recommended for all clients.

This second illustrative snippet declares an Authorization Code flow with PKCE required. The URLs are placeholders, and the scope is the one the migration guide uses in its own example.

"securitySchemes": {
  "oauth": {
    "oauth2SecurityScheme": {
      "flows": {
        "authorizationCode": {
          "authorizationUrl": "https://auth.example.com/authorize",
          "tokenUrl": "https://auth.example.com/token",
          "pkceRequired": true,
          "scopes": { "read": "Read access" }
        }
      }
    }
  }
},
"securityRequirements": [{ "schemes": { "oauth": { "list": ["read"] } } }]

Three pitfalls in the official material

An old sample is still around. The copy of the sample card in the v1.0.1 tag of the specification wrote the requirement in the v0.3 shape, "security": [{ "google": ["openid", "profile", "email"] }]. The official repository corrected it after the release (pull request #2046, July 2026), and the shape used on this page is the one a2a.proto defines for v1.0. If you copy a card from an older copy of the specification, check this field first.

JSON keys follow the proto field names. The specification requires camelCase JSON names derived from the proto field names (section 5.5). The OAuth example in the v1.0 migration guide writes authorizationCodeFlow and implicitFlow, but the proto fields are authorization_code and implicit, so the keys are authorizationCode and implicit, as in the tables above. When the sources disagree, the specification names the proto as “the single authoritative normative definition” (section 1.4).

“Removed” flows are still in the proto. The migration guide lists ImplicitOAuthFlow and PasswordOAuthFlow as removed. The v1.0.0 and v1.0.1 protos still declare them as members 3 and 4 of OAuthFlows, marked deprecated, and section 4.5 of the specification documents only the three current flows. Do not declare Implicit or Password flows in new cards; treat them as deprecated rather than gone when you parse cards from other agents.

Coming from v0.3?

These are the differences between the a2a.proto files of v0.3.0 and v1.0.1:

ChangeDetail
Security renamedNow SecurityRequirement, with the same structure. AgentCard.security became securityRequirements (field 9) and AgentSkill.security became securityRequirements (field 8)
Device Code flow addedOAuthFlows.device_code (field 5) with DeviceCodeOAuthFlow
PKCE flag addedAuthorizationCodeOAuthFlow.pkce_required (field 5)
Implicit and Password flowsStill oneof members 3 and 4, now marked deprecated
Required fieldsNone of the security messages in the v0.3.0 proto carries a REQUIRED annotation; v1.0.1 marks the fields shown as required in the tables above
UnchangedThe five SecurityScheme members keep fields 1 to 5, and MutualTlsSecurityScheme exists in both versions

The official migration guide covers the OAuth flow changes but not the security rename.

Related pages

Source: A2A official specification: Security Objects, JSON Field Naming Convention, Authentication and Authorization ; What’s New in A2A Protocol v1.0 ; a2a.proto at v1.0.1 and v0.3.0