Skip to content

FastAPI Integration

FastAPI dependencies in Tenauth minimise boilerplate for enforcing bearer authentication and tenant scoping.

Requiring Authentication

from fastapi import Depends, FastAPI
from tenauth.fastapi import require_auth
from tenauth.models import AuthContext

app = FastAPI()

@app.get("/me")
def read_profile(auth: AuthContext = Depends(require_auth)):
    return {"user_id": str(auth.sub), "tenant_id": str(auth.tid)}

require_auth extracts the bearer token, validates the scheme, and returns an AuthContext. Invalid or missing tokens raise HTTPException(status_code=401) automatically.

Tenant-Aware Sessions

from sqlmodel.ext.asyncio.session import AsyncSession
from tenauth.fastapi import build_access_scoped_session_dependency

SessionDep = build_access_scoped_session_dependency(session_factory=my_session_factory)

@app.get("/tenants/{tenant_id}/widgets")
async def list_widgets(session: AsyncSession = Depends(SessionDep)):
    result = await session.execute(...)
    return result.all()

build_access_scoped_session_dependency combines the auth context with the session factory. It applies tenant and user identifiers via Postgres GUCs for the lifecycle of the request and resets them when complete.

Customising Verification

When creating the dependency you can disable runtime GUC verification:

SessionDep = build_access_scoped_session_dependency(
    session_factory=my_session_factory,
    verify=False,
)

Skipping verification removes the extra roundtrip to confirm the settings—but only use it when you trust the database connection pool configuration.

WebSocket Authentication

websocket_access_context mirrors the HTTP dependency flow for websocket handshakes. It inspects the Authorization header, access_token query parameter, or Sec-WebSocket-Protocol entries—accepting either raw tokens or Bearer-prefixed strings.

from fastapi import FastAPI
from starlette.websockets import WebSocket

from tenauth.websocket import websocket_access_context

app = FastAPI()

@app.websocket("/ws")
async def ws_channel(websocket: WebSocket):
    access_ctx = await websocket_access_context(websocket)
    await websocket.accept()
    await websocket.send_json({
        "tenant": str(access_ctx.tenant_id),
        "user": str(access_ctx.user_id),
    })

Tokens rejected by AuthContext.from_token become WebSocketException errors with the same policy-violation code FastAPI uses for missing or malformed authentication.