FastAPI middleware for Grantex grant token verification and scope-based authorization
Project description
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
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://grantex-auth-dd4mtrt2gq-uc.a.run.app/.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.100.0
grantex>= 0.1.0
License
Apache-2.0
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
File details
Details for the file grantex_fastapi-0.1.4.tar.gz.
File metadata
- Download URL: grantex_fastapi-0.1.4.tar.gz
- Upload date:
- Size: 6.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9dd5daa3047f27a5be3c8fd04d2bee7a0cf838969482226038bc658be0b37a65
|
|
| MD5 |
e482944d5cd05187dbffba61b969d91b
|
|
| BLAKE2b-256 |
920aab8384c14fb9d9d2b80935f7d6a2113baad8745479cd96d309631f1a536c
|
File details
Details for the file grantex_fastapi-0.1.4-py3-none-any.whl.
File metadata
- Download URL: grantex_fastapi-0.1.4-py3-none-any.whl
- Upload date:
- Size: 5.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4e40ca074b72a72c15d00c53a21ac494ec75a8bf3b13765cc205f304fab958fe
|
|
| MD5 |
8e3cc8b2501c965afa2e983e63913c4d
|
|
| BLAKE2b-256 |
2b3be33760f503e2418ad8e39b044726e819a7eb28da98865af84f8d642ea922
|