Offline verifier + authorizer for Legant delegation tokens (RFC 8693 sub/act), with Tier-B revocation-feed support.
Project description
legant-sdk (Python)
Offline verifier + authorizer for Legant delegation tokens. Its only dependency
is cryptography (Python ≥ 3.9).
from legant_sdk import fetch_jwks, Verifier, Action, fetch_revocation_feed
issuer = "https://auth.example.com"
keys = fetch_jwks(f"{issuer}/.well-known/jwks.json")
# Tier B (optional): reject revoked tokens offline, refreshed in the background.
feed = fetch_revocation_feed(f"{issuer}/.well-known/revoked", issuer, keys)
feed.start_polling(10.0, on_error=print)
verifier = Verifier(issuer, "https://my-api.example/", keys, feed=feed)
# Per request:
claims = verifier.verify(bearer_token) # raises VerifyError / RevokedError on failure
claims.authorize(Action(scope="expenses:submit", amount=120, category="travel")) # raises AuthorizeError on 403
print(claims.provenance()) # "user:alice -> agent:assistant"
verify raises VerifyError (or RevokedError when the token is in the feed);
authorize raises AuthorizeError when a scope or constraint is denied. Catch
them to return 401 / 403.
Guard an agent's tools — any framework
AgentGuard wraps any tool callable so every invocation is authorized against
the agent's delegation token — offline, no callback. The wrapped function is a
plain callable, so it drops into LangChain, CrewAI, LlamaIndex, AutoGen, or your
own loop unchanged. A prompt-injected or buggy agent cannot exceed the scoped,
revocable slice the token carries.
from legant_sdk import Verifier, AgentGuard
verifier = Verifier(issuer, "https://my-api.example/", keys, feed=feed)
guard = AgentGuard(verifier, token=agent_delegation_token) # token may be a callable, to refresh
@guard.tool("expenses:submit", amount_arg="amount", category_arg="category")
def submit_expense(amount: float, category: str) -> str:
... # only runs if the token permits this scope, amount, and category — else AuthorizeError
# LangChain: from langchain_core.tools import tool; lc_tool = tool(submit_expense)
# CrewAI: @tool("Submit expense") def submit_expense(...): ... then wrap with @guard.tool(...)
Or check inline without the decorator: guard.authorize("scope", amount=…) (raises)
or guard.allowed("scope", amount=…) (returns a bool).
Test
python3 -m unittest discover -s tests # runs the shared conformance vectors (see ../conformance)
Project details
Release history Release notifications | RSS feed
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
File details
Details for the file legant_sdk-0.1.1.tar.gz.
File metadata
- Download URL: legant_sdk-0.1.1.tar.gz
- Upload date:
- Size: 13.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
57e279e9bbe17bd23125e054cb5b6ccb088d32d710c03117ec33e641686032d7
|
|
| MD5 |
82657867d9d8c3318d9703331e4c1959
|
|
| BLAKE2b-256 |
05a060a2aad521ae93b75557bef3e1f710f6a8ae26c8d310e00a7a893840b376
|
File details
Details for the file legant_sdk-0.1.1-py3-none-any.whl.
File metadata
- Download URL: legant_sdk-0.1.1-py3-none-any.whl
- Upload date:
- Size: 11.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0bd5b2bf3fb0a878f339940f98f934a0d992d088da3c43d45554ac6094247542
|
|
| MD5 |
bc7044215bfb653d0252edf03a307acc
|
|
| BLAKE2b-256 |
f7ba4435625216eef0c3325ae56358cca44bdb5a98f6c1c916b4d7e77624d2b4
|