Skip to content

Middleware

sentinel_auth.middleware

Starlette/FastAPI middleware for JWT access token validation.

Add this middleware to your FastAPI app to automatically validate JWT tokens on incoming requests and populate request.state.user with an AuthenticatedUser instance.

JWTAuthMiddleware(app, public_key=None, jwks_url=None, algorithm='RS256', audience='sentinel:access', exclude_paths=None, allowed_workspaces=None)

Bases: BaseHTTPMiddleware

Validates JWT access tokens and sets request.state.user.

For each incoming request (except excluded paths), this middleware:

  1. Extracts the Authorization: Bearer <token> header
  2. Decodes and validates the JWT using the provided public key
  3. Sets request.state.user to an AuthenticatedUser instance
  4. Returns 401 if the token is missing, expired, or invalid

Provide either public_key (PEM string) or jwks_url to specify how the signing key is obtained. When jwks_url is given the key is fetched lazily on the first request and cached.

Parameters:

Name Type Description Default
app ASGIApp

The ASGI application to wrap.

required
public_key str | None

RSA public key (PEM format) used to verify JWT signatures. Obtain this from the identity service's keys/public.pem, or omit and use jwks_url instead.

None
jwks_url str | None

URL of the Sentinel JWKS endpoint (e.g. "http://localhost:9003/.well-known/jwks.json"). The first RSA signing key will be fetched and cached.

None
algorithm str

JWT signing algorithm. Defaults to "RS256".

'RS256'
audience str

Expected JWT audience claim. Defaults to "sentinel:access".

'sentinel:access'
exclude_paths list[str] | None

List of path prefixes to skip authentication for. Defaults to ["/health", "/docs", "/openapi.json"].

None
allowed_workspaces set[str] | None

Optional set of workspace IDs (as strings) that are permitted to access this service. None (default) allows all workspaces. Returns 403 if the JWT's workspace is not in the set.

None

Example using JWKS (recommended)::

app.add_middleware(
    JWTAuthMiddleware,
    jwks_url="http://localhost:9003/.well-known/jwks.json",
)

Example using PEM file::

from pathlib import Path

app.add_middleware(
    JWTAuthMiddleware,
    public_key=Path("keys/public.pem").read_text(),
)
Source code in sdk/src/sentinel_auth/middleware.py
def __init__(
    self,
    app: ASGIApp,
    public_key: str | None = None,
    jwks_url: str | None = None,
    algorithm: str = "RS256",
    audience: str = "sentinel:access",
    exclude_paths: list[str] | None = None,
    allowed_workspaces: set[str] | None = None,
):
    super().__init__(app)
    if not public_key and not jwks_url:
        raise ValueError("Either public_key or jwks_url must be provided")
    self.public_key = public_key
    self.jwks_url = jwks_url
    self.algorithm = algorithm
    self.audience = audience
    self.exclude_paths = exclude_paths or ["/health", "/docs", "/openapi.json"]
    self.allowed_workspaces = allowed_workspaces