Delegating work across companies with AAuth
Alice wants a piece of work done, and her organisation pays for it. She gives the job to her assistant, an AI agent. The assistant hands it to a coordinator, and the coordinator splits it between other companies. Some of
Alice wants a piece of work done, and her organisation pays for it. She gives the job to her assistant, an AI agent. The assistant hands it to a coordinator, and the coordinator splits it between other companies. Some of those companies pass part of the job on again.
Every company in that chain has to answer the same questions before it does any work:
- Who is calling me, and do I accept work from them?
- On whose behalf is this request, and did that person actually approve it?
- Who pays, and is that the payer the person agreed to?
- Is this action within what the person approved?
- Is there still money left?
A bearer token or API key answers almost none of these. It says "the holder may do X", and anyone who copies it becomes the holder.
AAuth is an HTTP authorization protocol designed for agents. It is an IETF draft (this series uses draft 11) by Dick Hardt. I built AAuth Network Lab to see how far it gets on this problem, with real signatures and tokens and simulated companies. This series walks through how it works.
darkedges
/
aauth-lab
AAuth (draft-hardt-oauth-aauth-protocol-11) version of the Relay Biscuit lab, with a side-by-side comparison
Relay β AAuth network lab
The Relay Biscuit lab rebuilt on AAuth. It has the same operators, scenarios, budget rules and UI. Biscuit attenuation is replaced by AAuth's signed HTTP requests, person-server tokens and call chaining. Signatures, tokens and HTTP exchanges are real. Operators, work and credits are simulated.
Live demo: aauth.demos.darkedges.com
See COMPARISON.md for a side-by-side analysis of the two solutions.
Run locally
Use Node.js 22 or newer and pnpm 11:
pnpm install pnpm dev
Open http://127.0.0.1:8796. The Biscuit lab uses 8795, so both labs can run side by side. On Windows, run ./start.ps1. The interface starts a demo run automatically.
pnpm check # behaviour, spec-conformance, reference-client interop and debug formatting tests
How the AAuth version works
Each run creates fresh Ed25519 keys and a fresh set of origins, such as https://search.<tag>.relay.example. Requests between parties are real Request/Response objects routed in-process to thatβ¦
Live demo: aauth.demos.darkedges.com
If you read my earlier Biscuit Trust Lab series (code), this is the same network, the same seven scenarios and the same clearinghouse, rebuilt on a different protocol. You don't need to have read it.
The network
Alice (person) / alice-org (payer)
ββ Assistant (Alice's agent)
ββ PlannerCo (coordinator)
ββ ResearchCo [5 credits]
β ββ SearchCo [10 credits]
ββ ComputeCo [25 credits]
All billable calls β shared clearinghouse
Alice's person server issues every token
Alice approves a budget of 100 credits. The happy path costs 40: research 5, search 10, compute 25.
Seven scenarios try to break it:
| Scenario | What goes wrong |
|---|---|
| Authorized delegation | Nothing. Three operations settle for 40 credits. |
| Change payer | ResearchCo asks SearchCo to bill mallory-org
|
| Forbidden operation | ResearchCo asks SearchCo to delete, which SearchCo offers but Alice never approved |
| Untrusted issuer | ResearchCo presents a token signed by a rogue key claiming to be Alice's person server |
| Competing reservations | Two 60-credit calls race for a 100-credit budget |
| Retry | ResearchCo repeats a search with the same operation ID |
| Operation failure | SearchCo reserves credits, then fails |
A trust editor lets you remove a "this company accepts calls from that company" relationship, or stop a company accepting Alice as a requester, and run again.
Four roles
AAuth gives every participant one of a few roles. In the lab:
-
Agents make requests. The Assistant, PlannerCo, ResearchCo and ComputeCo are all agents, because each calls someone else. An agent has a signing key and an agent token that binds that key to an identifier such as
aauth:[email protected]. -
Agent providers vouch for agents. An agent provider publishes
/.well-known/aauth-agent.jsonand a JWKS, and signs agent tokens. In the lab each company is its own agent provider. - Resources receive requests. PlannerCo, ResearchCo, SearchCo, ComputeCo and the clearinghouse are resources. Intermediaries are both: a resource to their caller, an agent to the next company.
- The person server (PS) represents Alice. It knows who she is, records what she approved, and issues the tokens that let agents act for her.
The important design choice is the last one. Authority doesn't live in a token that gets passed down the chain. It lives at the person server, and every hop asks it again.
One hop, five steps
Every call between two companies follows the same pattern. Here is ResearchCo calling SearchCo:
-
Identity call. ResearchCo signs the HTTP request with its own key (RFC 9421 HTTP Message Signatures) and puts its agent token in a
Signature-Keyheader. SearchCo now knows who is calling. It answers401withAAuth-Requirement: requirement=person-token. -
Person token. ResearchCo asks Alice's PS for a person token addressed to SearchCo. Because ResearchCo is an intermediary, it includes the token it was given by PlannerCo as
upstream_token. -
Resource token. ResearchCo repeats the call, presenting the person token. SearchCo answers
401again withrequirement=auth-tokenand a resource token saying what it needs: scopesearch email, billing accountalice-org. - Auth token. ResearchCo takes the resource token to the PS. The PS checks it against what Alice approved, and either mints an auth token or refuses.
- Authorized call. ResearchCo calls SearchCo a third time, presenting the auth token. SearchCo verifies it, applies its own policy, and does the work.
Every request in that list is signed by ResearchCo's key, and every token is bound to that key. A token copied off the wire is useless without the private key.
Before any of this, Alice approves a mission at her PS: what the assistant is trying to do, which tools it will use, and which services it will call. Every token in the run carries the mission's hash.
On the happy path that adds up to 40 signed HTTP requests, 16 of them to the person server.
What the lab adds on top of AAuth
AAuth defines the signatures, tokens and person server. It deliberately doesn't define payers, budgets or billing. The lab adds three things and labels each one as a lab extension in the UI:
-
A
relaymember in the mission that records the payer, the budget and the scopes the PS may issue for each company. The draft allows extra members in the mission. - A clearinghouse that reserves, settles and releases credits, the same as in the Biscuit lab.
- A signed provider assertion on billing calls, because AAuth tokens don't name the calling agent and the clearinghouse needs to know who to pay. Part 5 explains why.
Try it
Open the demo and leave the defaults. Run the network.
The Debug tab lists every signed request in order, with the real Signature, Signature-Input and Signature-Key headers, the decoded token, the AAuth-Requirement challenge and a short narration of what happened. The Decision logic tab shows, for each company, which checks passed and where each fact came from: the HTTP signature, a token the PS signed, the company's own policy, or the mission.
Then try the guided exercises:
- Protect the original payer. The PS refuses to mint the auth token. SearchCo never sees a request it could act on.
- Remove a trust relationship. SearchCo refuses ResearchCo on the very first request, before anyone contacts the PS.
- The person declines the mission. Alice says no at her PS, and nothing runs.
Run it locally
You need Node.js 22 and pnpm 11.
git clone https://github.com/darkedges/aauth-lab
cd aauth-lab
pnpm install
pnpm dev # http://127.0.0.1:8796
pnpm check # 33 tests: behaviour, spec conformance, reference-client interop
All parties run inside one Cloudflare Pages function. Each run creates fresh keys and fresh origins such as https://search.<tag>.relay.example, and requests between them are real Request and Response objects routed in process.
Signing and verification use the official libraries: @aauth/agent signs, @hellocoop/httpsig verifies, @aauth/resource verifies tokens and builds the challenges, and jose signs the tokens the PS mints.
Coming up in this series
- This post: the problem, the network and the shape of a hop.
-
Signed requests and agent identity: RFC 9421 signatures, the
Signature-Keyheader, agent tokens and key discovery. - Missions, consent and three tokens: how Alice approves the work, and how the PS decides each hop.
-
Call chaining: how intermediaries pass authority on with
upstream_token, and what they can't do. - Paying for it, and checking against a real person server: billing without agent identity, and what a live run against HellΕ's person server showed.
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.
