Announcing opa-sidecar-a2a: A Reference Implementation for Chain-Aware Agent Authorization
TL;DR
We just open-sourced opa-sidecar-a2a, a reference implementation of chain-aware authorization for agent-to-agent (A2A) traffic. It runs as a single Go binary alongside your agent or gateway, evaluates delegation chains against Rego policies, and returns allow/deny with obligations. MIT licensed, no product to buy, no vendor lock-in. This post explains why we built it, what it actually does, and how it fits into a broader story about the emerging A2A authorization gap.
The problem we kept seeing
Every A2A implementation shipping to production today ends up in one of two spots on authorization, both wrong.
Spot one: API-key trust. Agent B trusts agent A because agent A holds a valid API key. This tells B nothing about whether A is authorized to call B on behalf of the specific user or workflow that originated the request. A compromised or misbehaving agent can call anywhere its key allows, and the callee has no way to know whether the request actually originated with a user who granted this specific action.
Spot two: bearer-token pass-through. Agent A forwards the user's original bearer token to agent B. B checks it, and if it's valid, allows. This assumes agent A is trusted enough to hold the user's credentials and eliminates the ability to distinguish "the user allowed A to do X" from "A decided to do X on the user's behalf without telling them."
Neither model survives contact with a real delegation chain. Think about how a typical planner-executor pattern looks: user delegates to planner, planner delegates to executor, executor invokes a tool, tool calls a downstream API. Four hops, four different trust relationships. API-key trust collapses them all into "does the caller hold a valid key." Bearer-token pass-through collapses them all into "does the caller have the user's token."
What actually happens in a real delegation is more like: user grants planner permission to book_flight. Planner grants executor permission to invoke_tool:flight_booking_v1. Executor calls the tool. At each hop the grant is narrower than the previous one, and the callee should be able to verify the whole chain before allowing.
That's chain-aware authorization. And nothing in the OSS ecosystem was implementing it in a way we could point at.
What we built
opa-sidecar-a2a is a single Go binary that runs alongside an agent or a gateway. It exposes one production endpoint (POST /authorize), takes a delegation chain and a proposed action as input, and returns allow/deny plus obligations.
The moving parts:
Signature verification. Every grant in the chain carries an ed25519 signature from its issuer. The sidecar verifies each signature against a trust dir of public keys before the policy sees the input. If any signature fails, the grant is marked sig_verified: false and the reference policy denies.
Chain linking. Adjacent hops must link: grant N+1's issuer must equal grant N's subject. The user grants to planner, planner grants to executor, executor is the caller. Any break in that chain is a deny.
Scope matching. The chain must cover the action being attempted. If the user granted book_flight but the caller attempts send_email, the chain doesn't cover it, deny.
Time bounds. Every grant carries an exp. If any grant in the chain is expired, deny.
Policy evaluation. Once the chain is verified, the Rego policy makes the final call. This is where deployment-specific rules land: rate limits, sensitive-resource restrictions, per-user allowlists, obligations to attach to the response.
Obligations. A policy can return allow WITH obligations. Common shapes: "MUST redact PII from response," "MUST log to audit stream X," "MUST cap response bytes." The caller is responsible for honoring them.
Why a reference implementation and not a product
We could have built this into Leanroute directly and marketed it as a feature. We chose not to, for three reasons.
First, chain-aware authorization is a standard that needs to exist, not a differentiator we should keep to ourselves. If we bury the pattern inside our proxy nobody else can look at it, learn from it, or push it forward. As a standalone reference implementation, anyone building an A2A stack (with or without us) can adopt the shape.
Second, we do not currently proxy A2A traffic through Leanroute. Building the authorization layer without the transport is architecturally weird if we called it a Leanroute feature. As a reference implementation it makes sense: publish the "correct" pattern first, plug our own proxy into it when that ships.
Third, and honestly: we are a small team. Product surface area is expensive. Standalone reference implementations get to be minimal and understandable in a way that in-product features never do. This repo is meant to be read in an afternoon by anyone who wants to understand the pattern.
What's in the repo
Compact but complete for v0.1:
- Single Go binary (
cmd/opa-sidecar) with SIGHUP hot-reload. - Reference Rego policies covering the common cases: baseline chain verification, scoped tool invocation, time-bound restrictions, obligations.
- Worked planner-executor demo (two Go agents plus a shell script) that exercises three scenarios: happy path, scope-creep attack, tampered chain.
- Full protocol docs, policy-authoring guide, architecture notes.
- CI covering build, test, gofmt, vet, golangci-lint, and OPA policy syntax.
- MIT licensed.
How it fits into the broader picture
Two things are converging that make chain-aware authorization urgent, not academic.
Regulated agent deployments. EU AI Act Article 12 and DORA Article 11 (both in force through 2026) require auditable evidence trails for agent actions in regulated industries. That means when a bank's customer service agent invokes a tool that transfers funds, the audit log needs to show not just "agent X did Y" but "user U delegated to agent X, agent X delegated to agent Y, agent Y invoked tool Z, and here's the signed chain proving it." OPA sidecar produces the enforcement side of that story. Its natural complement is a transparency log for the evidence side (see MCP Transparency Log, which we're prototyping next).
MCP tool invocation at scale. As MCP becomes the standard way for agents to invoke external tools, "who authorized this tool call" becomes the question. Chain-aware authorization gives MCP servers a way to answer it that doesn't require them to trust every agent that talks to them.
What comes next
v0.1 is the reference. v0.2 will add revocation, OpenTelemetry, and Envoy ext_authz gRPC support so it works cleanly in service-mesh deployments. v0.3 will add W3C Verifiable Credentials 2.0 compatibility for the credential format.
If you're building A2A workflows today and hitting the authorization gap, please try it and open issues. Especially if:
- You're on the Google Agent2Agent SDK and want to see what a compatible authorization sidecar looks like.
- You're running MCP tool servers and need to authorize incoming tool calls by more than "does the caller have a valid session."
- You're in a regulated industry and need to produce audit evidence that current API-key models can't.
Repo: github.com/leanroute/opa-sidecar-a2a. Everything is MIT, no signup needed.
Sources:
Top comments (0)