A2A RFC: actor-chain extension for delegated authority
Upstream repo: a2aproject/A2A
Status: Filed upstream 2026-07-03 as
a2aproject/A2A#2028,
awaiting first response. Verified non-duplicate on
2026-07-03; anchor threads are A2A #1937 (context-binding
profile for delegated authority) and A2A #153 (confused
deputy). Written against A2A v1.0 conventions (a2a.proto normative,
PascalCase operations, ProtoJSON enums).
Authors: Burin Labs
Reference impl: harn_vm::actor_chain::ActorChain
(crates/harn-vm/src/actor_chain.rs) carried through
the harn-serve A2A adapter
(crates/harn-serve/src/adapters/a2a/schema.rs) under
task/message metadata today.
Problem statement
A2A v1.0 carries no identity in the payload. Authentication is
out-of-band: SecurityScheme declarations on the agent card plus
transport-level mechanisms (HTTP auth, mTLS). The canonical data model
has no field on Message, Task, or the agent card for the human (or
upstream agent) a request is made on behalf of. The only
identity-adjacent field is tenant, which is an opaque routing id, not
a principal. The only escape hatch is the untyped metadata map.
That gap matters as soon as agents delegate to agents:
- Attribution. When agent C receives work from agent B, which received it from agent A acting for user U, C sees only B's transport credentials. The full chain A→B→C-for-U exists nowhere on the wire.
- Audit. Post-hoc "who caused this side effect" reconstruction has to join transport logs across every hop, each with its own identity representation.
- Confused deputy (#153): a callee that can't see the originating principal can be tricked into using its own broader authority on behalf of a less-privileged caller.
The OAuth ecosystem already has the vocabulary for this: RFC 8693 token
exchange expresses delegation as nested act (actor) claims, and the
ID-JAG / WIMSE drafts under active development build agent-specific
delegation on the same shape. A2A can interoperate with that work
without inventing a token format — the missing piece is a standard,
optional place in the A2A payload where a chain travels.
#1937 proposes the complementary half: binding an already-valid delegation to a task/session/target/scope. This proposal is about carrying the chain itself in a standard shape. The two compose: a context-binding profile needs a chain representation to bind.
Proposed shape
An A2A extension (v1.0 extension mechanism: an AgentExtension
entry in AgentCard.capabilities.extensions[], keyed by URI), rather
than a core schema change. Peers that support it declare:
{
"capabilities": {
"extensions": [
{
"uri": "https://a2a-protocol.org/extensions/actor-chain/v1",
"required": false
}
]
}
}
The extension defines one reserved metadata member, actorChain, valid
on Message.metadata and echoed on Task.metadata:
{
"actorChain": {
"origin": { "sub": "user:alice@example.com" },
"actors": [
{ "sub": "agent:coordinator", "scopes": ["repo:read", "ci:trigger"] },
{ "sub": "agent:rebase-worker", "scopes": ["repo:read"] }
],
"mayAct": "agent:rebase-worker"
}
}
origin— the outermost principal the work is ultimately for (typically a human).actors— the delegation hops in order, mirroring RFC 8693 nestedactclaims flattened for readability; each hop optionally carries the authority scopes that hop held, so attenuation is visible.mayAct— optional RFC 8693may_actanalogue.
Audit, not authz. The chain is attribution and audit history. It MUST NOT be used to grant access: authorization stays with the transport-level credentials and whatever token the callee validated. This mirrors the position the ID-JAG authors have taken and avoids the "self-asserted identity as capability" trap — a payload field anyone can write must never be a credential.
Compatibility and migration
The extension is additive and optional. Peers that don't declare it ignore the metadata member (A2A metadata is already tolerate-by-default). Peers that do declare it SHOULD echo the chain (with their own hop appended) when they delegate onward.
The reference implementation ships this today under
metadata.actor_chain / metadata.harn.actor_chain with the same
entry shape (sub + scopes), validated on ingest and appended per
hop. Migration to a ratified extension URI and member name is a rename.
Open questions for upstream maintainers
- Extension vs core. Is the v1.0 extension mechanism the intended incubation path for this, or is payload identity in scope for core once #1937 settles?
- Nested vs flattened. RFC 8693 nests
actclaims; the shape above flattens to an ordered array for readability. Should the wire shape stay byte-compatible with RFC 8693 claims instead? - Relationship to signed evidence. A2A v1.0 already does JWS for agent-card signatures. Should hops be signable, or is that deliberately deferred to token-level mechanisms (ID-JAG / WIMSE)?
- Interaction with
tenant. Should the extension state thattenantremains routing-only, to keep it from being repurposed as a principal?