# Cryptographically signed agent card

> Cryptographically signed agent card: A2A v1.0 makes identity verifiable through JWS (RFC 7515). The fix: sign the agent card.

- Source: /checks/a2a-signed
- Site: AgenticWebScore
- Language: English

---
A2A v1.0 makes identity verifiable through JWS (RFC 7515).

| Property | Value |
| --- | --- |
| Check id | `a2a-signed` |
| Dimension | Protocol Discovery (25%) |
| Tier | Emerging — pool 5 pts |
| Weight inside tier | 1 |
| Impact | Medium |
| Maturity | Draft — A published specification that is not yet ratified. |
| Conditional | No |
| Publishing skill | `a2a-card-signing` |
| Standards | RFC 7515 |

## What the scanner requests

- `/.well-known/agent-card.json`
- `/.well-known/agent.json`

## What is measured

The scanner fetches the A2A card and inspects its signatures array. It passes only when a signature is cryptographically verified: at least one entry is a JWS (RFC 7515) object with base64url protected and signature members whose protected header names alg, typ and kid, and the public key published at the jku URL verifies the signature over the card canonicalized per RFC 8785 with the signatures member removed, as A2A v1.0 requires. It partially passes when a signature is structurally complete but was not verified — the referenced JWKS is on another host or outside the probe set so its response was not observed, the JWKS does not publish the key, or the algorithm carries no digest this scanner can check — and it fails when a key from a published JWKS is available and the signature does not verify against it.

## Reproduce it yourself

You do not have to take our word for any of this. Run the same measurement against your own domain:

```bash
DOMAIN=https://your-domain.example
curl -sS "$DOMAIN/.well-known/agent-card.json" | jq -r '.signatures[0].protected' | python3 -c "import sys,base64,json;p=sys.stdin.read().strip();p+='='*(-len(p)%4);print(json.dumps(json.loads(base64.urlsafe_b64decode(p)),indent=2))"
```

## The fix

This is the artifact to ship. It is the complete change, not a description of one.

```javascript
// npm i jose canonicalize  ->  node sign-agent-card.mjs
import { readFileSync, writeFileSync } from 'node:fs';
import canonicalize from 'canonicalize';
import { CompactSign, exportJWK, generateKeyPair } from 'jose';

const card = JSON.parse(readFileSync('agent-card.json', 'utf8'));
const { privateKey, publicKey } = await generateKeyPair('ES256');
const { signatures, ...payload } = card;   // A2A v1.0 excludes signatures
const canonical = canonicalize(payload);   // RFC 8785 canonical JSON

const jws = await new CompactSign(new TextEncoder().encode(canonical))
  .setProtectedHeader({
    alg: 'ES256', typ: 'JOSE', kid: 'key-1',
    jku: 'https://your-domain.example/.well-known/jwks.json'
  })
  .sign(privateKey);

const [protectedHeader, signature] = jws.split('.');
const signed = { ...card, signatures: [{ protected: protectedHeader, signature }] };
writeFileSync('agent-card.signed.json', JSON.stringify(signed, null, 2));
const jwk = { ...(await exportJWK(publicKey)), kid: 'key-1', use: 'sig', alg: 'ES256' };
writeFileSync('jwks.json', JSON.stringify({ keys: [jwk] }, null, 2));
```

> Serve agent-card.signed.json at /.well-known/agent-card.json and jwks.json at the jku URL, and re-sign whenever the card changes; the scanner now verifies the JWS over the RFC 8785 canonical card, so a stale signature over an edited card fails instead of being reported as signed.

## Standards referenced

- `RFC 7515`

## Related checks

| Check | Tier | Impact | Same skill |
| --- | --- | --- | --- |
| `mcp-card` — MCP server card | Essential | High | — |
| `openapi` — OpenAPI definition | Essential | High | — |
| `oauth-discovery` — OAuth discovery documents | Essential | High | — |
| `api-catalog` — API catalog | Recommended | Medium | — |
| `agent-skills` — Agent Skills declaration | Recommended | Medium | — |
| `a2a-card` — A2A agent card | Recommended | Medium | — |
| `auth-md` — /auth.md agent authentication guide | Emerging | Medium | — |
| `webmcp` — WebMCP browser tool declaration | Emerging | Medium | — |
