Skip to main content

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:

  1. Extracts the Bearer token from the Authorization header
  2. Verifies the RS256 signature against the Grantex JWKS endpoint
  3. Returns a typed VerifiedGrant object with principal, agent, scopes, and timestamps
  4. 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

grantex_fastapi-0.1.5.tar.gz (6.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

grantex_fastapi-0.1.5-py3-none-any.whl (5.4 kB view details)

Uploaded Python 3

File details

Details for the file grantex_fastapi-0.1.5.tar.gz.

File metadata

  • Download URL: grantex_fastapi-0.1.5.tar.gz
  • Upload date:
  • Size: 6.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for grantex_fastapi-0.1.5.tar.gz
Algorithm Hash digest
SHA256 de8f3413eea1b4bd8f7e5914f740b3ace27430ea5f18a26288d81827df006fd6
MD5 7cd9584251aa87c3a3a2905a62a50bf0
BLAKE2b-256 51775cf784a06b18e315257164091ebf3df18b4862de444ec113e352056e0523

See more details on using hashes here.

File details

Details for the file grantex_fastapi-0.1.5-py3-none-any.whl.

File metadata

File hashes

Hashes for grantex_fastapi-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 06c1968a2c9871d31cafc22b761aa71bcc9ab31dbeb322a1cf5a3d3240136d75
MD5 8b2b0e4c12ebe9fc0f7044b8622698f8
BLAKE2b-256 79bea40dbe669c0af16c7dd3e0f0e08b7908f967a9c86fada305e9b4217ed7b7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page