grantex-fastapi
FastAPI dependency injection for Grantex grant token verification and scope-based authorization.
Verify Grantex JWTs and enforce scopes on any FastAPI route with a single Depends().
Install
pip install grantex-fastapi==0.1.6
Quick Start
from fastapi import Depends, FastAPI
from grantex import VerifiedGrant
from grantex_fastapi import GrantexAuth, GrantexFastAPIError, grantex_exception_handler
app = FastAPI()
app.add_exception_handler(GrantexFastAPIError, grantex_exception_handler)
JWKS_URI = "https://api.grantex.dev/.well-known/jwks.json"
grantex = GrantexAuth(jwks_uri=JWKS_URI)
# Verify token — grant is injected automatically
@app.get("/api/calendar")
async def calendar(grant: VerifiedGrant = Depends(grantex.scopes("calendar:read"))):
return {"principalId": grant.principal_id, "scopes": list(grant.scopes)}
How It Works
GrantexAuth is a callable class that acts as a FastAPI dependency:
- Extracts the Bearer token from the
Authorizationheader - Verifies the RS256 signature against the Grantex JWKS endpoint
- Returns a typed
VerifiedGrantobject with principal, agent, scopes, and timestamps - The
.scopes()method adds scope enforcement on top
Token Verification Only
Use Depends(grantex) to verify the token without checking scopes:
@app.get("/api/me")
async def me(grant: VerifiedGrant = Depends(grantex)):
return {"principalId": grant.principal_id, "agentDid": grant.agent_did}
Scope Enforcement
Use Depends(grantex.scopes(...)) to verify the token AND check scopes:
# Single scope
@app.get("/api/calendar")
async def calendar(grant: VerifiedGrant = Depends(grantex.scopes("calendar:read"))):
...
# Multiple scopes — all required
@app.post("/api/email/send")
async def send_email(grant: VerifiedGrant = Depends(grantex.scopes("email:read", "email:send"))):
...
Or check scopes inside the handler:
from grantex_fastapi import require_scopes
@app.get("/api/data")
async def data(grant: VerifiedGrant = Depends(grantex)):
require_scopes(grant, "data:read")
...
Custom Token Extraction
from fastapi import Request
def extract_from_cookie(request: Request) -> str | None:
return request.cookies.get("grant_token")
grantex = GrantexAuth(jwks_uri=JWKS_URI, token_extractor=extract_from_cookie)
Custom Error Handling
Register the built-in exception handler for JSON error responses:
app.add_exception_handler(GrantexFastAPIError, grantex_exception_handler)
Or write your own:
from fastapi import Request
from fastapi.responses import JSONResponse
from grantex_fastapi import GrantexFastAPIError
@app.exception_handler(GrantexFastAPIError)
async def custom_handler(request: Request, exc: GrantexFastAPIError) -> JSONResponse:
if exc.code == "TOKEN_EXPIRED":
return JSONResponse(status_code=401, content={"error": "Session expired"})
return JSONResponse(status_code=exc.status_code, content={"error": exc.code})
Error Codes
| Code | Status | Meaning |
|---|---|---|
TOKEN_MISSING |
401 | No token found in request |
TOKEN_INVALID |
401 | Token signature or format is invalid |
TOKEN_EXPIRED |
401 | Token has expired |
SCOPE_INSUFFICIENT |
403 | Token lacks required scopes |
grant Object
The VerifiedGrant dataclass contains:
| Field | Type | Description |
|---|---|---|
token_id |
str |
JWT jti claim |
grant_id |
str |
Grant record ID |
principal_id |
str |
End-user who authorized the agent |
agent_did |
str |
Agent's DID |
developer_id |
str |
Developer org ID |
scopes |
tuple[str, ...] |
Granted scopes |
issued_at |
int |
Token issued-at (epoch seconds) |
expires_at |
int |
Token expiry (epoch seconds) |
Requirements
- Python 3.9+
- FastAPI >= 0.115.0
grantex>= 0.3.6
License
Apache-2.0
Ownership
Grantex is owned by Orchestrum Technologies LLP. Inventor and owner: Sanjeev Kumar. Ownership contact: sanjeev@orchestrum.in or mishra.sanjeev@gmail.com.
Authority hardening requires Python SDK 0.7.1 (
current_authority), not just a valid JWT signature. Bind the audience and trusted human/agent identities, and check the issuer before every execution. This does not create human consent or automatically consume action decisions/spend caps. Existing offline defaults remain offline. Verify registry availability before installation. See the SDK execution authority guide.
Metadata
Release files for grantex-fastapi 0.1.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| grantex_fastapi-0.1.6.tar.gz | 11.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| grantex_fastapi-0.1.6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 22.1 kB
Release files / grantex_fastapi-0.1.6.tar.gz
| Download URL | grantex_fastapi-0.1.6.tar.gz |
|---|---|
| Size | 11.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
13541b437c0172b9e2e213c54d05ee23ee8c9bc0516217037166bd162b589d15
|
|
BLAKE2b-256 checksum How to use checksums |
297089418a966024d8a7bd00e0bf067ccf9e986c6b12dad570359559ec36e830
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.4
|
Release files / grantex_fastapi-0.1.6-py3-none-any.whl
| Download URL | grantex_fastapi-0.1.6-py3-none-any.whl |
|---|---|
| Size | 10.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8ccec1d59cb483e8926379426b3e602be51499d5c7fa6e0795eb609331eaa388
|
|
BLAKE2b-256 checksum How to use checksums |
21e85872baf6bcbaf1a19ecdbf1b05cb023fe6c5e315b321367634b97d734d20
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.4
|