docs: add scoped authorization receipt extension example#1915
Conversation
There was a problem hiding this comment.
Code Review
This pull request adds a new section to the documentation detailing a Scoped Authorization Receipt Extension example. The feedback suggests updating the JSON example to use supportedInterfaces instead of a root-level url field to comply with the core schema, and clarifying the terminology from 'agent-originated action' to 'agent-targeted action' or 'client-requested action' for better accuracy.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| "name": "Expense Approval Agent", | ||
| "description": "An agent that can prepare and submit expense approvals.", | ||
| "version": "1.0.0", | ||
| "url": "https://example.com/agents/expense-approval", |
There was a problem hiding this comment.
The AgentCard schema defined in specification/a2a.proto does not have a root-level url field. Instead, URLs and protocol bindings are specified under the required supported_interfaces field (serialized as supportedInterfaces in ProtoJSON). Updating this example to use supportedInterfaces ensures it is fully compliant with the core schema.
| "url": "https://example.com/agents/expense-approval", | |
| "supportedInterfaces": [ | |
| { | |
| "url": "https://example.com/agents/expense-approval", | |
| "protocolBinding": "HTTP+JSON", | |
| "protocolVersion": "1.0" | |
| } | |
| ], |
| server, while a scoped authorization receipt can show that a specific | ||
| agent-originated action was admitted for a particular task, resource, request | ||
| digest, policy version, and expiry. The A2A server or downstream provider still |
There was a problem hiding this comment.
f334440 to
44ce128
Compare
|
+1 on keeping this non-normative and pushing domain semantics out to 1. Closed vocabulary is the right call. The AlgoVoi payment-compliance profile uses a small closed outcome set, each value tied to a specific regulatory trigger. That closed set is what makes the receipt independently auditable — open-ended status strings don't survive audit. 2. Binding needs a canonicalisation rule, not just a field list. 3. Basis vs. data minimisation. The basis behind a verdict can be privacy-sensitive. We keep it out of the signed bytes and surface only the categorical outcome, holding detail in operator records. The profile might allow basis-by-reference rather than inline. 4. Keep One scope note: this example covers classical JWS/ES256 receipts only — it doesn't address post-quantum signatures or zero-knowledge attestations. Those sit in a separate trust layer in the AlgoVoi deployment and aren't implied by this extension. Flagging so the example isn't read as the full authority/trust surface. Net: matches what we landed on independently. Live agent card / A2A explorer if you want to probe a working deployment: https://dash.algovoi.co.uk/a2a AlgoVoi (chopmob-cloud) -- Acquisition enquiries: https://docs.algovoi.co.uk/acquisition |
44ce128 to
4c5af92
Compare
|
Quick follow-up — we went ahead and wired the extension shape into our live agent card (issuer/verifier side: we produce these receipts rather than require them, so I hope this helps. AlgoVoi (chopmob-cloud) -- Acquisition enquiries: https://docs.algovoi.co.uk/acquisition |
|
Thanks, this is very helpful. The The production config detail also reinforces why the Agent Card should stay generic: it can expose transport, verification metadata, and Once the live card is available, it would be useful implementation evidence for this extension pattern. |
|
It's live now — the extension is being served from production:
You can probe it directly; it passes A2A v0.3 validation with the extension present. The If you need anything else from our side — a different binding, a worked receipt example, or anything to help the example land — just shout. AlgoVoi (chopmob-cloud) -- Acquisition enquiries: https://docs.algovoi.co.uk/acquisition |
|
Thanks, this is excellent implementation evidence. I probed the live card and the extension shape is visible under That is useful validation for keeping the A2A example non-normative: the same extension shape can describe a real producer/verifier deployment while leaving the profile to define the outcome vocabulary and verifier rules. |
|
Here's a live, end-to-end-verifiable receipt for the worked example. Anyone can reproduce it — no auth required. 1. Request a screen ( {"recipient_address":"<addr>","network":"algorand:mainnet","amount_microunits":1000000,"asset":"USDC"}2. The response carries the receipt + its detached signature. The {
"payer_ref": "sha256:45c8fd4b3a75c567b4fb8933e996f77c56d65ce60ae55568282660bd610107c6",
"screen_result": "ALLOW",
"screen_timestamp_ms": 1780689523721,
"screen_provider_did": "did:key:z6MkgExzvcpvxrghf4Q3285xqSdenhRZHcP6wc5UvY6VVaz5",
"jurisdiction_flags": ["UK", "EU"],
"canon_version": "jcs-rfc8785-v1"
}
3. The compact JWS ( 4. Verify it against the published JWKS — the import json, base64, urllib.request
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
b64u = lambda s: base64.urlsafe_b64decode(s + "="*(-len(s)%4))
h, p, sig = JWS.split(".")
kid = json.loads(b64u(h))["kid"]
jwks = json.load(urllib.request.urlopen("https://api.algovoi.co.uk/.well-known/jwks.json"))
key = next(k for k in jwks["keys"] if k["kid"] == kid)
Ed25519PublicKey.from_public_bytes(b64u(key["x"])).verify(b64u(sig), (h+"."+p).encode())
# no exception -> validThis is exactly the Hope this is a useful concrete reference for the example. AlgoVoi (chopmob-cloud) -- Acquisition enquiries: https://docs.algovoi.co.uk/acquisition |
|
I would keep the Agent Card example generic, but make the profile contract slightly sharper. The card can advertise that receipt metadata exists. The profile should define how a verifier reaches the same answer. I would make the example say that
The main thing to avoid is letting the Agent Card imply more than it proves. The card can say where receipt verification metadata lives; it should not imply that every action is authorized, that every interaction requires a receipt, or that the profile's domain vocabulary is part of A2A core. One small docs addition that would help: a "what this extension does not prove" note. For example:
That would preserve the useful discovery layer while keeping authority and verification in the profile. |
4c5af92 to
cb81020
Compare
|
Useful example, and keeping the outcome vocabulary and canonical digest construction in the referenced profile rather than the Agent Card is the right split. For a concrete, resolvable reference: AlgoVoi runs this same extension in production, under the same name and slug. The agent card advertises it and the profile URI actually dereferences:
Two production notes that may be worth folding into the guidance:
Live profile and verifier above if a working reference is useful. AlgoVoi (chopmob-cloud) -- docs.algovoi.co.uk/substrate-2 |
|
Thanks, this is useful production evidence. I pushed a small update that folds in the two guidance points while keeping the Agent Card example generic:
Validation:
|
Summary
receipt_profile_uriwithout changing the core Agent Card schema.Context
Resolves #1909.
This follows the discussion in #1909 around separating generic Agent Card discovery metadata from domain-specific receipt profile semantics.
Validation
git diff --checkdocs/topics/extensions.mdFull MkDocs validation was not run locally because the local Python environment does not have
mkdocsinstalled.