reference/provider implements all of this and e2e/ checks it.
Covers the PACT Identity profile only. Delegated authority is in spec §5.
1 · Register personal agents
Keep a record per personal agent:issuer (the exact iss string), jwksUri, enabled.
Pick one audience string and give it to every personal agent. Allowlisting personal agents or
accepting any iss that serves a JWKS is your policy
(spec §3.1).
Done when you can look up a personal agent by iss and get its JWKS URL and enabled
state.
2 · Serve one Agent Card per Brand
brandId → 404. The card
(spec §2.1) lists a supportedInterfaces entry with
protocolBinding: "HTTP+JSON", protocolVersion: "1.0" and the url the
other routes hang off; declares httpAuthSecurityScheme
{ scheme: "Bearer", bearerFormat: "JWT" }. Personal agents reach it from the
Brand’s own /.well-known/agent-card.json (which serves this card or redirects
here), or from a link or registry entry.
Done when a Brand’s card is served and an unknown id returns 404.
3 · Verify the personal-agent JWT on every other route
Match the route first (unknown path →404/405), then
(spec §3.2):
algisES256orRS256; reject anything else.issis a known, enabled personal agent.- Signature verifies against that personal agent’s JWKS (cache; refetch on unknown
kid). audis your audience;expis in the future;iat≤ 30 s in the future.subis present. The caller is(iss, sub).
aud, expired, HS256,
and a disabled personal agent all get that 401, and a good token passes.
4 · Answer message:send
POST {interfaceUrl}/message:send (spec §4). Require
role: "ROLE_USER" and a non-blank text part. Key conversations by
(iss, sub, brandId):
Reply synchronously with a
ROLE_AGENT message carrying the contextId,
Content-Type: application/a2a+json. The token says which personal agent is calling for
sub, not who the User is. The agent verifies the User as it would in a chat
widget.
Done when two messages with one contextId continue one conversation,
and that contextId from another sub or Brand gets INVALID_PARAMS.
5 · Other routes, errors, limits
Generic A2A clients will call other operations; return the result listed in spec §2.2 (TASK_NOT_FOUND; GET tasks → an empty
list), and A2A’s errors for operations you don’t support. A2A errors use the
envelope in spec §6 with the reason in
error.details[0].reason. Plain HTTP for 401, 404/405, and 429 +
Retry-After when you rate-limit.
Done when each operation returns its listed error after a valid token.
6 · Run the conformance suite
You need two Brand IDs and a personal agent you trust;pnpm gen-keys makes
one (see conformance tests). PA_* variables
describe that personal agent. CUSTOMER_ID is a Brand ID, since the code calls
Brands customers.
auth.brand.example, so the User sees the Brand’s
domain where they grant access. You can move the Brand’s OAuth endpoints there
too; its RFC 8414 issuer then uses that domain. Never let consent be framed:
send frame-ancestors 'none'.