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.4.tar.gz (6.3 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.4-py3-none-any.whl (5.4 kB view details)

Uploaded Python 3

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

Hashes for grantex_fastapi-0.1.4.tar.gz
Algorithm Hash digest
SHA256 9dd5daa3047f27a5be3c8fd04d2bee7a0cf838969482226038bc658be0b37a65
MD5 e482944d5cd05187dbffba61b969d91b
BLAKE2b-256 920aab8384c14fb9d9d2b80935f7d6a2113baad8745479cd96d309631f1a536c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for grantex_fastapi-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 4e40ca074b72a72c15d00c53a21ac494ec75a8bf3b13765cc205f304fab958fe
MD5 8e3cc8b2501c965afa2e983e63913c4d
BLAKE2b-256 2b3be33760f503e2418ad8e39b044726e819a7eb28da98865af84f8d642ea922

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