Middleware
TinyauthMiddleware is a pure-ASGI middleware. Add it to your app with a
TinyauthConfig:
from fastapi import FastAPI
from fastapi_simple_tinyauth.config import TinyauthConfig
from fastapi_simple_tinyauth.middleware import TinyauthMiddleware
config = TinyauthConfig(trusted_proxies=["127.0.0.1/32", "::1/128"])
app = FastAPI()
app.add_middleware(TinyauthMiddleware, config=config)
What it does
On each HTTP request:
- It reads the immediate TCP peer (
request.client.host) and checks it against the configured trusted-proxy networks. - If the peer is not trusted, it responds with a plain-text HTTP 403 and never calls your app. The forwarded headers are ignored.
- If the peer is trusted, it parses the identity headers into an
AuthUserand stores it onrequest.state.auth_user.
Non-HTTP scopes (WebSocket, lifespan) pass straight through untouched.
FastAPI or plain Starlette
TinyauthMiddleware is a pure-ASGI middleware and the core package imports only
starlette — nothing in src/ imports FastAPI. So it works the same in a plain
Starlette app; only the wiring syntax differs:
from starlette.applications import Starlette
from starlette.middleware import Middleware
from fastapi_simple_tinyauth.config import TinyauthConfig
from fastapi_simple_tinyauth.middleware import TinyauthMiddleware
config = TinyauthConfig(trusted_proxies=["127.0.0.1/32", "::1/128"])
app = Starlette(middleware=[Middleware(TinyauthMiddleware, config=config)])
Inside your handlers, call the dependencies directly with the
Request instead of using FastAPI's Depends.
The stored user
After the middleware runs, request.state.auth_user is always present:
- An
AuthUserwhenRemote-Useris present. Nonewhen it is absent (anonymous request).
You normally do not read request.state.auth_user directly — use the
dependencies instead — but it is available if you need it in
your own middleware.
Header parsing details
- Each header value is stripped of surrounding whitespace; an empty value
becomes
None. - The groups header is split on commas, each item is trimmed, and empty items
are dropped.
" a , ,b "becomes("a", "b").
The untrusted-proxy response
The 403 for an untrusted peer is emitted directly by the middleware, so it does
not pass through your app's exception handlers (the request never reached
the app). If you want a custom response shape for it, enforce the proxy check
elsewhere too, or handle UntrustedProxyError where you raise it yourself. See
Exceptions.