Authorization for AI agents: verifiable, scoped, revocable capability tokens (mandates) with attenuable delegation, for MCP and A2A. The reference implementation of agent authority — zero-dependency TypeScript & Python.
Project description
agent-authority (Python)
Authorization for AI agents — the reference implementation of agent authority (project name: Behalf). Verifiable, scoped, time-bound, revocable capability tokens (mandates) with attenuable, macaroon/biscuit-style delegation, plus MCP and agent-to-agent (A2A) middleware. Capability-based security, OAuth 2.1 on-behalf-of–style grants, and SPIFFE/SVID-style agent identity for multi-agent / LLM systems.
Identical API shape to the TypeScript library, zero dependencies (standard
library only). The optional cryptography extra enables a constant-time Ed25519
backend and sealed credentials:
pip install agent-authority # core, dependency-free
pip install "agent-authority[seal]" # + sealed credentials / hardened crypto
In plain words
Think of a Mandate as a permission slip for an AI agent.
Imagine you hire an assistant to run errands for you. You don't hand over your wallet and house keys — you write a note: "You may read my calendar and spend up to $50, and only for the next hour." That note is a Mandate.
The five verbs are just the things you can do with that note:
- grant — write the permission slip. "This agent may do X, up to this limit, until this time."
- authorize — check the slip before acting. The agent must show the slip (and prove it's really theirs) before it's allowed to do something.
- attenuate — make a smaller copy for a helper. A sub-agent can only get the same powers or fewer — never more.
- revoke — tear the slip up. Cancel it instantly; every copy handed downstream stops working too.
- audit — the logbook. Every check is written down, so you can see exactly what happened.
Two things make the slip safe: it can't be faked or upgraded (it's signed with cryptography, and a helper can only shrink the powers), and holding the paper isn't enough — an agent must prove it's the rightful holder, so a stolen copy by itself is useless.
The rest of this page shows how to do each of these in code.
The five verbs
from agent_authority import create_behalf
b = create_behalf()
# 1. GRANT
mandate = b.grant(
principal="alice",
agent="research-agent",
can=["read:calendar", "spend:usd<=50"],
expires_in="1h",
)
# 2. AUTHORIZE — raises AuthorizationError if denied
mandate.authorize("spend:usd=20")
# 3. ATTENUATE — narrow for a sub-agent; can only shrink
child = mandate.attenuate(can=["read:calendar"], expires_in="10m")
# 4. REVOKE — kills the mandate and its downstream chain
b.revoke(mandate.id)
# 5. AUDIT — every authorize() wrote a hash-chained record
trail = b.audit(mandate.id)
MCP / A2A middleware
from agent_authority.mcp import with_behalf
server = with_behalf(
my_tool_server, # exposes call_tool(name, args, ctx=None)
policy={
"send_email": "write:email",
"read_calendar": "read:calendar",
"transfer_funds": lambda args: f"spend:usd<={args['amount']}",
},
on_denied="throw", # or "prompt" with on_prompt=...
)
# Pass the caller's mandate on the context:
server.call_tool("read_calendar", {}, {"mandate": mandate})
agent_authority.mcp.behalf_mcp_tools() returns the three discovery tools
(request_mandate, present_mandate, check_authority).
Develop
python3 -m unittest discover -s tests # 28 tests
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters