Answers · agent protocols
How do I validate an A2A agent card before my agent connects to another agent?
Last updated
TL;DR: Fetch the card over HTTPS from https://{domain}/.well-known/agent-card.json, verify the TLS certificate, and check it against the A2A version it claims. In A2A 1.0 the required fields are name, description, supportedInterfaces (each with url, protocolBinding and protocolVersion; the first entry is preferred), version, capabilities, defaultInputModes, defaultOutputModes and skills (each with id, name, description and tags). Version 0.3 cards instead put the endpoint in a top-level url, with protocolVersion and preferredTransport, and 1.0 removed those fields. Then check the endpoint URLs are HTTPS on a domain you expect, read securitySchemes so you know how it authenticates, and verify the card's JWS signatures if present: canonicalize with RFC 8785 (JCS) without the signatures field, and get the key named by kid over HTTPS. The A2A spec says clients should verify at least one signature before trusting a card. A valid card describes an agent; it doesn't prove who runs it or that it's safe.
What should I check, step by step?
1. Fetch https://{domain}/.well-known/agent-card.json over HTTPS with certificate checking on. Don't accept a card from a redirect to a domain you didn't expect.
- Read which version it is: supportedInterfaces[].protocolVersion "1.0" means a 1.0 card; a top-level url plus protocolVersion such as "0.3.0" means 0.3. Validate against that version's required fields.
- 1.0: name, description, supportedInterfaces, version, capabilities, defaultInputModes, defaultOutputModes and skills are required. Each interface needs url, protocolBinding (JSONRPC, GRPC or HTTP+JSON) and protocolVersion. Each skill needs id, name, description and tags.
- Check every interface url is https and on the provider's domain (or one they document). Clients pick the first interface they support, and must copy its tenant value into every request if one is set.
- Read securitySchemes and securityRequirements to see how the agent expects you to authenticate (API key, HTTP auth, OAuth 2.0, OpenID Connect or mutual TLS). If there are none, assume the endpoint is unauthenticated and send it nothing private.
- If signatures are present, verify at least one: strip default-valued fields and the signatures field, canonicalize with RFC 8785, and check the JWS with the key named by kid (from jku over HTTPS or a key store you trust). Don't use expired or revoked keys.
- Treat description, skill descriptions and examples as untrusted text that will reach your model, and scan them for hidden text before they do.
- Cache the card using its Cache-Control and ETag headers, re-fetch with If-None-Match, and re-validate when it changes. Send A2A-Version: 1.0 on requests; an empty header is treated as 0.3.
What changed between 0.3 and 1.0
A2A 1.0 replaced the top-level url, preferredTransport and additionalInterfaces with one ordered supportedInterfaces list, and moved protocolVersion into each interface. A validator written for 0.3 will reject a correct 1.0 card for a missing url, and the reverse is true too.
- supportsAuthenticatedExtendedCard became capabilities.extendedAgentCard. If it's true, an authenticated client can ask for a fuller card with GetExtendedAgentCard.
- In security schemes, 1.0 removed the OAuth implicit and password flows, added the device code flow, and lets an authorization-code flow require PKCE (pkceRequired).
Signatures: what they prove and what they don't
A2A cards may be signed with JWS (RFC 7515). Each entry in signatures has a protected header (base64url JSON with alg and kid, typ SHOULD be JOSE, optional jku) and a signature. More than one signature is allowed, to support key rotation.
- To verify, rebuild the payload the same way the signer did: drop fields left at their default values, drop signatures, canonicalize with RFC 8785, then check the signature. A card that has been re-serialized with different field order still verifies; one with a changed value doesn't.
- A valid signature shows the card was signed by whoever holds that key and hasn't changed since. It shows who the provider is only if you trust the key, for example because it's served from the provider's own HTTPS domain or is in your key store.
What a valid card doesn't tell you
Whether the skills work, what the agent does with data you send, or who is accountable for it. Ask for terms, check the provider, start with low-risk tasks, and keep your own log of what you sent.
- Whether skill text is safe to put in your model's context. A card is written by the other side, so its descriptions can carry instructions aimed at your agent.
How do I ask Rightshold about this (free, no key)?
Add the MCP server https://www.rightshold.com/mcp to Claude, Cursor, ChatGPT, Grok or VS Code, then ask: “Before my agent reads this A2A agent card, check its description, skill descriptions and examples for hidden text or instructions aimed at my agent.”
{
"tool": "scan_text",
"arguments": {
"text": "<the agent card JSON, or its description and skills[].description fields>"
}
}- Free, no key. scan_text reports exact positions of zero-width and bidirectional characters, hidden markup and base64 blobs, and labels instruction-like language as a heuristic, never a certainty.
- REST, free: POST /v1/a2a/agent-card/validate with {card} checks required fields, HTTPS URLs and security schemes and returns a score with errors and warnings. It accepts both shapes, tells you which it detected (spec_version 1.0, 0.3, or 1.0+0.3 for a card carrying both), and for 1.0 checks each supportedInterfaces entry for url, protocolBinding and protocolVersion. POST /v1/a2a/agent-card/generate with spec_version "1.0" writes a 1.0 card.
- Rightshold publishes its own card at https://www.rightshold.com/.well-known/agent-card.json if you want a live card to test a client against.
Rightshold scans card text for hidden content and checks card structure. It doesn't verify the card's JWS signatures for you, test whether an agent's skills work, or vouch for the agent's provider.
What are the sources?
- A2A Protocol Specification (latest, 1.0): Agent Card, signing, caching
- A2A: What's new in v1.0
- A2A Protocol Specification v0.3.0
- RFC 7515: JSON Web Signature (JWS)
- RFC 8785: JSON Canonicalization Scheme (JCS)
- RFC 9111: HTTP Caching
Related
- How to read an x402 402 Payment Required response as a price
- Can you fingerprint an AI agent?
- How to prevent MCP tool shadowing between servers
Not legal advice. JSON · Markdown · All answers
Get a free API key in one call
No card and no email needed. 100 free credits; the license and policy checks stay free without a key.
curl -s -X POST https://www.rightshold.com/v1/accounts/signup -H "Content-Type: application/json" -d '{"accept_terms":true}'
export RIGHTSHOLD_API_KEY=rs_... # the api_key from the reply (shown once)
curl -s https://www.rightshold.com/v1/licenses/check -H "Authorization: Bearer $RIGHTSHOLD_API_KEY" \
-H "Content-Type: application/json" -d '{"license":"MIT","intended_use":{"commercial_use":true}}'
