Skip to main content
For engineers adding PACT to a platform that hosts support agents for Brands (a Provider). The rules are in the specification; 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

Unauthenticated; unknown 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):
  1. alg is ES256 or RS256; reject anything else.
  2. iss is a known, enabled personal agent.
  3. Signature verifies against that personal agent’s JWKS (cache; refetch on unknown kid).
  4. aud is your audience; exp is in the future; iat ≤ 30 s in the future.
  5. sub is present. The caller is (iss, sub).
Any failure, with no A2A body:
Done when missing token, bad signature, wrong 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.
Done when all 10 tests pass. That is PACT Identity conformance. Delegated authority (spec §5) is optional and advertised on the card. It adds per-Brand scopes and login, device-code OAuth, delegation tokens, step-up and receipts. Consent is your page, reached from the Brand’s login (spec §5.3). Serve it from a Brand subdomain pointed at you, such as 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'.