Observed since 20 Oct, 21:31 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
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.
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
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:
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.
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)
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).
python3 -m unittest discover -s tests # 28 tests
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.1.6 | 14 Jun 2026 | 1 |
This describes our collected data; it is not a security assessment.
Shared repository data · GitHub
Observed since 20 Oct, 21:31 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:f58b189977c1159d818697befae1e91feac66faa44cfa44c427bbbbc5486a910