Skip to content

HomePut a secure public front on an A2A agent that lives on your laptop, LAN or tailnet

Updated 2026-10-23 · applies to a2a-exposed 0.8.11

Put a secure public front on an A2A agent that lives on your laptop, LAN or tailnet

In public front mode, a2a-exposed puts a Cloudflare Worker in front of an agent that already speaks A2A on a laptop, LAN or tailnet: it serves the agent card rewritten to the public URL, checks each peer's token, and forwards requests through a Cloudflare Tunnel locked by Cloudflare Access.

Use this when the agent already speaks A2A. An agent that needs a task store uses the task store and wake.

The path

  1. A peer calls the public Worker with its own bearer token, issued by pairing.
  2. The Worker checks that token, then calls your agent with the Worker's own credential.
  3. The Worker calls your agent at a Cloudflare Tunnel hostname. Cloudflare Access admits only the Worker's service token.
  4. cloudflared on your machine delivers the request to the agent.
  5. The Worker also sends UPSTREAM_TOKEN if your agent expects its own bearer, and X-A2A-Peer with the peer's label.
npx -y a2a-exposed@latest init \
  --hostname agent.example.com \
  --upstream https://agent-upstream.example.com/a2a

--upstream must be a public Tunnel hostname. A Tailnet, LAN or localhost URL is refused.

Does this work with Tailscale?

Your agent can live on a tailnet. The Worker reaches the agent through a Cloudflare Tunnel hostname locked by Access. Tailscale is where the agent sits. The tunnel is the transport.

What changes on the agent card

Interfaces point at the public URL. Name, skills and version come from the upstream card unless you override them with --agent-*. These are removed from every string: localhost, private IPs, *.ts.net, *.local, plain http, and the tunnel hostname itself. signatures are dropped. streaming, push notifications and the extended card are advertised as false.

UPSTREAM_TOKEN stays on the Worker. On failure peers get a generic -32603 502. You get a reason code from npx -y a2a-exposed@latest upstream verify or status: access_credentials_missing, access_rejected, upstream_auth_missing, upstream_auth_rejected, tunnel_down, and others listed in troubleshooting.

Peer isolation

Each task and context belongs to the peer that created it. A call on another peer's task is refused before it reaches your agent. ListTasks is refused. Push notification configs are refused, because the upstream would call a peer's URL from inside your network. Peers poll GetTask. Streaming is not proxied.

What the public front adds

The Worker rewrites the agent card to the public URL, issues a token per peer, and removes private URLs from the card. Cloudflare Tunnel is the private hop. The tunnel recipe is in docs/tunnel. The threat model is in security.

Grok Bot is tested end to end. The public-front path is listed on compatibility.