Legant is an open-source delegated-authorization layer for AI agents. Authority is scoped, constrained, attenuating, revocable, and auditable — and limits like “travel and meals under $500 for the next hour” ride inside the signed token and are enforced offline by the resource server. Any sub-agent it spawns can only ever do less.
Keycloak, Ory, and Zitadel can authenticate an agent and hand it a token. What they can’t express is the sentence that actually matters once an agent is spending your money or calling your tools:
“this agent may act for Alice, only to submit travel and meal expenses under $500 for the next hour, and any sub-agent it spawns can only ever do less.”
A flat OAuth scope can’t carry that — there’s no place to put the per-call dollar cap, the category and tool allow-lists, the time-of-day window, or the user→agent→sub-agent provenance, and no rule that authority can only narrow as it’s re-delegated. Legant’s core is exactly that sentence, made into signed tokens and a pure, unit-tested delegation engine. It’s a full OAuth 2.1 / OIDC provider too — auth code + PKCE, client credentials, refresh, discovery, JWKS, introspection, RFC 8707 resource indicators, RFC 7591 DCR, built on Fosite — so the delegation layer sits on standard substrate, not a fork of one.
RFC 8693 token exchange mints a token where sub is the user and act is the full nested agent chain. The agent acts on behalf of the user, never as the user — and the user→agent→sub-agent provenance is recorded in the token, not inferred.
Max amount, category / tool / resource allow-lists, and a time-of-day window travel inside the signed cnst claim. A resource server authorizes them from the token with zero callback. (One honest exception: a rolling-hour rate cap needs shared state, so Legant enforces that at mint time.)
Re-delegated authority can only narrow. Scopes must be a subset of the parent’s; two disjoint allow-lists intersect to a deny-all sentinel, never the widening empty list; chains are depth-bounded and cycle-checked. A sub-agent can never gain authority a parent lacked.
On tools/call the gateway never forwards the inbound token — it mints a fresh, single-tool, audience-bound downstream token. tools/list is filtered to the delegated tools and fails closed if unparseable; duplicate JSON keys and JSON-RPC batches are rejected to close parser-differential attacks.
Accepting agent tokens in your API takes a few lines: verify + authorize fully offline (RS256 + kid + iss + aud + exp, requires an act chain) plus the Tier-B revocation feed — no Legant dependency, no per-request callback. Three SDKs kept in lockstep by golden conformance vectors minted from the real signer, so they can't drift.
Every audit row is SHA-256 hash-chained inside Postgres under an advisory lock. legant audit verify pinpoints the first edited, reordered, or truncated row against a pinned anchor. Tamper-evident, not tamper-proof — off-box anchors are on the roadmap for the both-tables-compromised case.
Each runs on a pure in-memory engine and prints a faithful end-to-end story. The Conductor page below is a live, faithful replay of its real output — open it.
Watch agents act on behalf of users, tool-call decisions stream in, and a revocation kill a whole chain — the operational console for agent authority.
The gateway mints a fresh single-tool, single-audience token per call instead of forwarding the agent’s. A 60-second token minted for the repo server, replayed against analytics, is rejected 401 (wrong audience). Injected drop_table/charge are 403’d before any upstream, and every allow and deny lands in a hash-chained flight recorder whose verify catches a tampered row.
Limits (≤ $400, travel/rideshare only) are signed constraints enforced offline at each merchant, so an injection buying a $400 gift card or a $900 suite is declined at the merchant. After Alice revokes, the kill-switch bites in two tiers: Legant won’t mint new tokens, and the tokens already held are refused 401 offline because the merchant polls the signed /.well-known/revoked feed.
Re-delegation can only attenuate. When the founder drops Growth’s weekly budget from $500 to $50, re-delegating Bid with a requested $200 cap is clamped to $50 — so the same $150 Bid spend that was approved now bounces offline at the ad platform with full founder→CEO→Growth→Bid provenance. A child can never out-spend its parent.
Honeytools (exfiltrate_secrets, wire_funds) are left visible in tools/list as bait but never delegated. A poisoned document drives the agent to reach for them; each attempt is denied with no data touched and recorded in a tamper-evident tripwire log naming who tried what for whom.
Most agent-auth pitches promise “instant offline revocation,” which is physically impossible without a per-call round-trip. Legant gives you three real tiers and lets you pick the coupling. A stale or missing feed can only ever miss a revoke — it can never forge one — because the token only ever gains a rejection, and its short TTL is the always-present backstop.
| Tier | How | Latency | Coupling |
|---|---|---|---|
| A per-call store check | The MCP gateway and RFC 7662 introspection query the Postgres revocation store (a jti denylist) on every call. Unknown jti fails closed. A revoke takes effect on the very next call. |
Immediate — synchronous indexed point-read per call | Tightest: every verified call needs the issuer’s DB reachable; a store error is treated as not-active (reject). |
| B signed feed /.well-known/revoked |
The issuer publishes a JWS-signed snapshot of revoked-but-unexpired jtis, signed with the same JWKS key (no new trust root). A monotonic version blocks rollback. The SDK polls it on a timer and checks an in-memory set — no per-request callback. |
Within your poll interval; ≤5s server cache; never later than token expiry | Loose: fully offline at request time; the resource server only reaches the feed URL on its own polling timer. |
| C TTL backstop | With no feed configured, the SDK validates signature / iss / aud / exp and the act claim; revocation is bounded by the token’s short TTL alone. This is also the default fail-open behavior when a feed is stale (fail-closed is opt-in). |
Up to the token’s remaining TTL — it simply expires | Zero: no DB, no feed, fully offline. |
Default access-token lifespan is 5m — short and configurable, not a hard ceiling (raising LEGANT_TOKEN_EXCHANGE_ACCESS_TOKEN_LIFESPAN enlarges the Tier-C backstop). Lifetime is clamped at mint to min(now+ttl, grant expiry), so a token never outlives its delegation grant. “Immediate” describes Tier A specifically; Tier B is bounded by your poll interval plus a 5s server cache. Full revocation design →
Legant is an authorization server, so only one role runs a server. To integrate — to accept agent tokens in your API — you need nothing but the SDK: it verifies offline against the issuer's published keys, with no database and no callback.
Stands up legant serve + Postgres in their own cloud (Docker / Kubernetes). It holds the signing keys, sessions, revocation state, and the audit chain. This is the only component that needs Postgres — and docker compose up brings its own.
Builds the AI agent. It does an RFC 8693 token exchange against the issuer to get a short-lived “acting-for-Alice” token, then calls downstream APIs with it. Just app code talking to the issuer.
Builds an API or MCP server that accepts agent tokens. Imports the SDK, fetches the issuer's JWKS once, and verifies + authorizes every token offline. No server to run, no Postgres, no per-request callback.
The human who grants scoped authority to an agent through the browser consent flow, and can revoke it any time from a self-service page. Runs nothing.
Self-hosted today — you run the issuer in your own infrastructure; nothing leaves your environment. A hosted, multi-tenant Legant Cloud (we run the issuer; you only use the SDK) is a separate product on the roadmap.
# 1. Declare authority in a reviewable file and mint signed tokens. No Postgres, no Docker. legant init grants legant apply -f legant.grants.yaml # mints signed tokens into .legant/ legant who-can -f legant.grants.yaml --scope warehouse:query --resource finance # 2. Enforce those tokens at your own API, offline, and watch the whole loop: make demo-protect # define -> mint -> allow / deny / revoke # Or just watch the delegation engine: pure in-memory, no Docker. go run ./examples/leash # consumer kill-switch + offline revocation feed go run ./examples/conductor # MCP gateway: fresh per-call downstream tokens
Full walkthrough: Getting started · all guides: github.com/legant-dev/legant/docs · run the issuer: docker compose -f deployments/docker-compose.yml up -d
Legant is open source and self-hostable: one binary, Postgres, and a pure delegation engine you can read end to end. We name the limits on the page rather than hiding them — “immediate” revocation means Tier A specifically, the 5m TTL is a configurable default not a hard ceiling, and the audit chain is tamper-evident (off-box anchors are roadmap, not shipped). If that precision is what you want from a security layer, clone it and run a demo — leash shows the whole delegation-and-revocation story in under a minute, no database required.