2.3

Extended cards and signatures

GetExtendedAgentCard returns a fuller card to an authenticated caller, and signatures lets any caller check that a card is the one its publisher signed.

The planner holds a bearer token and reads the public card of deployer. That card carries a signature, and its extendedAgentCard flag says that an authenticated caller sees more.

When you finish this section, you can fetch an extended card, and sign and verify a card as the spec prescribes.

GetExtendedAgentCard

Extended card: the fuller card an agent returns to an authenticated caller through GetExtendedAgentCard, with more details or skills than the public card has.

The call needs credentials. The client must authenticate the request with one of the schemes that the public card declares in AgentCard.securitySchemes and AgentCard.security. That rule still names security, which 1.0 replaced with securityRequirements (conflict D6). PR #2046 fixed the §8.5 sample on main, and the §3.1.11 prose still says security.

Appendix A.2.2 calls the 0.3 flag supportsExtendedAgentCard, and the migration guide says supportsAuthenticatedExtendedCard (conflict D40). It gives the new flag field 5, and the proto uses 4 (conflict D7).

Figure 2.3 shows deployer refusing the call without a token, then returning the public card plus a second skill, without signatures.

Fig. 2.3earning the extended cardsequence
Earning the extended card Three lifelines: the platform team outside A2A, the planner, and the deployer. Seven steps appear in order. The planner reads the public card, which declares extendedAgentCard true and a bearer scheme. It calls GetExtendedAgentCard without an Authorization header and gets HTTP 401 with WWW-Authenticate: Bearer realm="deployer". The platform team issues a bearer token outside A2A. The planner calls again with the token and receives the extended card, whose skills are deploy and rollback and which carries no signature. platform team outside A2A planner client deployer port 41243 1 GET /.well-known/agent-card.json 2 public card extendedAgentCard: true, scheme bearer 3 GetExtendedAgentCard no Authorization header 4 HTTP 401 Unauthorized WWW-Authenticate: Bearer realm="deployer" 5 bearer token issued outside A2A 6 GetExtendedAgentCard Authorization: Bearer dpl_test_7c1e4b 7 extended card skills deploy and rollback, unsigned
The same GetExtendedAgentCard call fails with HTTP 401 before any A2A method runs, then returns a card with a second skill once a token is attached. Time runs down. Steps 1 and 2 come from the captured agent cards. Steps 3 and 4 are exchange 1 of the extended-card capture, and steps 6 and 7 are exchange 2. The token comes from the platform team, outside A2A.
GetExtendedAgentCard with a token, and the skill it addshttpFull log
### 2 · GetExtendedAgentCard: with a token
…
Authorization: Bearer dpl_test_7c1e4b
…
HTTP/1.1 200 OK
…
      {
        "id": "rollback",
        "name": "Roll back a deploy",
        "description": "Return staging to the previous build. Shown only to authenticated callers.",
        "tags": [
          "deploy",
          "rollback"
        ]
      }
Exchange 2, cut to the token and the second skill. The rest of the card equals the public card, without its signatures.

A client should use the extended card in place of its cached public card. That holds for the rest of the authenticated session, or until the version of the card changes. Such a card should not hold sensitive information that an attacker could use after a leak. A declared flag with no card behind it answers ExtendedAgentCardNotConfiguredError, -32007.

The official SDKs leave the credential check to the host, and the table says who receives the card when the host adds nothing.

SDKWho receives the extended card without a host check
Python 1.2.2Any caller. The extended_card_modifier hook receives the call context and can vary the card.
Go v2.6.0Any caller. A CallInterceptor or the card producer can reject the call.
Java v1.4.0.FinalAny caller in the core handlers, by design. The Quarkus reference servers mark the route @Authenticated.
JS v1.3.0An authenticated user when the card is a static object, and anyone else gets the public card with no error. A provider function decides itself.
.NET v1.0.0-preview2Nobody by default, because the method throws ExtendedAgentCardNotConfiguredError. An application overrides it and adds its own check.
Rust a2a-server-lf-v0.5.1Any caller. A resolver sees the request headers and can vary the card.

Signing a card

Card signature: an optional entry in signatures that holds a JSON Web Signature, as RFC 7515 defines it, over the card.

Each entry holds a base64url protected header and signature, and a verifier rebuilds the signed bytes from the received card under three rules:

  1. Field presence. A field marked REQUIRED must always be present, even when its value is the default. A field with the optional keyword stays whenever it was set, and any other field at its default value is dropped.
  2. RFC 8785. The JSON Canonicalization Scheme sorts object keys, fixes one form for each value, and removes whitespace.
  3. No signatures. The signatures field must be left out of the signed content, because a signature cannot cover itself.

The protected header holds alg, typ, and kid, and the line for typ says SHOULD under a MUST heading (conflict D20). An optional jku points to a JSON Web Key Set with the public key.

To sign, join the base64url header and canonical payload with a period, and sign that input with the key that kid names.

the deployer card, canonicalized, signed, and checkedtextFull log
# 1. canonical payload (RFC 8785): the card without signatures, keys sorted, no spaces
{"capabilities":{"extendedAgentCard":true,"streaming":true},…"version":"1.4.1"}

# 2. protected header, decoded
{"alg": "HS256", "typ": "JOSE", "kid": "deployer-key-1"}

# 3. JWS signing input: BASE64URL(header) '.' BASE64URL(payload)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpPU0UiLCJraWQiOiJkZXBsb3llci1rZXktMSJ9.eyJjYXBhYmlsaXRpZXMiOnsi…

# 4. the signature entry published in the card
{
  "protected": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpPU0UiLCJraWQiOiJkZXBsb3llci1rZXktMSJ9",
  "signature": "yPk834ji_dOVmxElhzV3yTYBT9NVp8Bx1j5K0LQmOww"
}

# 5. verify the published card: True
# 6. verify after changing the description to name production: False
The payload and the signing input are cut inside their lines. Step 2 prints the header with spaces, and the encoded bytes have none.

The kit signs with HS256, as the kit README lists. Real cards use ES256 or RS256, because an HMAC verifier holds the signing key.

Verifying a card

Verification has six MUST steps. They take a signature, fetch the public key by kid and jku or from a trusted store, and check it against the rebuilt payload.

Apply rule 1 when you rebuild. The signing and verifying steps both say to remove properties that have default values (conflict D21, open as issue #2249).

The kit's check passes on the published card and fails on a copy whose description names production, because the canonical bytes change. Figure 2.4 shows both checks.

Fig. 2.4signing and verifying the deployer cardflow
Signing and verifying the deployer card Top half, signing, in three steps: the deployer card minus its signatures field is canonicalized with RFC 8785 into a 959-byte payload. The protected header {"alg":"HS256","typ":"JOSE","kid":"deployer-key-1"} and the payload are each base64url-encoded and joined with a period into a 1,348-character signing input, which HMAC-SHA256 signs to give signatures[0] with protected eyJhbGci and signature yPk834ji. Bottom half, verifying, in four steps: the published card rebuilds the same payload and its signature matches, so verification returns True. An edited copy whose description reads "Deploys a tagged build to production." rebuilds a different payload, and verification returns False. SIGN VERIFY deployer card 11 members, plus signatures canonical payload, RFC 8785 sorted keys, no spaces, no signatures 959 bytes, from capabilities to version canonicalize rules 1 to 3 protected header {"alg":"HS256","typ":"JOSE", "kid":"deployer-key-1"} JWS signing input BASE64URL(header) '.' BASE64URL(payload) 1,348 characters on one line base64url base64url signatures[0] protected "eyJhbGci" signature "yPk834ji" HMAC-SHA256 HS256, key deployer-key-1 the kit: HS256, one shared key real cards: ES256 or RS256, with a public key in a JWKS at jku published card description as signed recompute "yPk834ji" rebuild True step 5 match edited copy "Deploys a tagged build to production." recompute new payload, another value rebuild False step 6 differs
The signature covers the RFC 8785 bytes of the card without signatures, so an edit to the description changes those bytes and verification fails. Read the top half left to right and down, then the bottom half left to right. Steps 5 and 6 are the last two lines of the signed-card capture. Values are shortened to 8 characters.

A client should verify at least one signature before it trusts an Agent Card, and never with an expired or revoked key. Give your verifier an explicit list of allowed algorithms, as the reference SDK does, to prevent algorithm confusion attacks. Security requirements covers card spoofing.

A2A protocol 1.0.1 · 3303592 · 2026-05-28 · Edition 2026.10