Any framework (ASGI / WSGI)¶
Beyond the first-class FastAPI and Flask mounts, deadbolt ships generic ASGI and WSGI apps
that mount onto any Python web framework. They depend only on the standard library — no extra to
install — so the same core serves Starlette, Litestar, Quart, Sanic, aiohttp (ASGI) and Bottle,
CherryPy, or a bare wsgiref server (WSGI).
asgi = auth.asgi_app() # a standard ASGI 3 application
wsgi = auth.wsgi_app() # a standard WSGI application
Each app translates the framework's native request into the normalized
AuthRequest contract, calls the core, and writes the
AuthResponse back — cookies included as real Set-Cookie headers.
Mount at base_path
Unlike the FastAPI/Flask mount(..., prefix=...) helpers, the generic apps take no prefix
argument. They strip the Auth.base_path you configured (default /api/auth) from the incoming
path, so mount them at that same path. Set base_path on Auth to change it.
ASGI¶
auth.asgi_app() returns an ASGI 3 callable. Mount it with your framework's sub-app primitive.
import secrets
import deadbolt as db
from starlette.applications import Starlette
from starlette.routing import Mount
auth = db.Auth(
adapter=db.MemoryAdapter(), # swap for db.SQLAlchemyAdapter(engine)
secret=secrets.token_urlsafe(32),
email_and_password=db.EmailPassword(enabled=True),
base_path="/api/auth",
)
app = Starlette(routes=[Mount("/api/auth", app=auth.asgi_app())])
The app also answers the ASGI lifespan protocol, so it can be served directly by any ASGI server
(uvicorn module:asgi) as well as mounted. WebSocket scopes are rejected — auth is HTTP only.
WSGI¶
auth.wsgi_app() returns a WSGI callable that bridges into the async core through
Auth.handle_sync. Mount it with any WSGI dispatcher.
import secrets
from wsgiref.simple_server import make_server
import deadbolt as db
auth = db.Auth(
adapter=db.MemoryAdapter(),
secret=secrets.token_urlsafe(32),
email_and_password=db.EmailPassword(enabled=True),
base_path="/api/auth",
)
# Serve the auth API directly (it strips base_path from the request path itself):
make_server("127.0.0.1", 8000, auth.wsgi_app()).serve_forever()
To mount under a larger WSGI app, put it behind a dispatcher such as
werkzeug.middleware.dispatcher.DispatcherMiddleware; the mount's SCRIPT_NAME is honoured, so the
sub-path still resolves against base_path.
Warning
Because the WSGI app uses the sync bridge, call auth.close() on shutdown to stop the
background loop, and never call it from inside a running event loop.