Module

middleware.auth

Authentication middleware — dual-mode session + token auth.

Authenticates requests via session cookies (browsers) or bearer tokens (API clients). The authenticated user is stored in a ContextVar, accessible viaget_user()from any handler or middleware.

RequiresSessionMiddlewarefor session-based auth. Token auth works independently.

Usage::

from chirp.middleware.auth import AuthConfig, AuthMiddleware, get_user, login, logout
from chirp.middleware.sessions import SessionConfig, SessionMiddleware

app.add_middleware(SessionMiddleware(SessionConfig(secret_key="...")))
app.add_middleware(AuthMiddleware(AuthConfig(
    load_user=my_load_user,       # async (id: str) -> User | None
    verify_token=my_verify_token, # async (token: str) -> User | None
)))

# In a handler:
user = get_user()
if user.is_authenticated:
    ...

# Login/logout:
await login(user)
await logout()

Classes

User 2
Minimal user protocol. Any object with ``id`` and ``is_authenticated`` satisfies this. Developers …

Minimal user protocol.

Any object withid and is_authenticatedsatisfies this. Developers bring their own user model — ORM class, dataclass, etc.

Methods

id 0 str
property
def id(self) -> str
Returns
str
is_authenticated 0 bool
property
def is_authenticated(self) -> bool
Returns
bool
UserWithPermissions 1
Extended user protocol with permission support. Used by ``@requires(*permissions)`` to check acces…

Extended user protocol with permission support.

Used by@requires(*permissions)to check access.

Methods

permissions 0 frozenset[str]
property
def permissions(self) -> frozenset[str]
Returns
frozenset[str]
AnonymousUser 3
Sentinel for unauthenticated requests. Returned by ``get_user()`` when no user is authenticated. E…

Sentinel for unauthenticated requests.

Returned byget_user()when no user is authenticated. Eliminates null checks —get_user() never returns None.

Attributes

Name Type Description
id str
is_authenticated bool
permissions frozenset[str]
AuthConfig 7
Authentication middleware configuration.

Authentication middleware configuration.

Attributes

Name Type Description
session_key str

Session dict key for the user ID.

token_header str

HTTP header for bearer tokens.

token_scheme str

Expected scheme prefix (e.g."Bearer").

load_user Callable[[str], Awaitable[User | None]] | None

Async callback to load a user by ID (session auth).

verify_token Callable[[str], Awaitable[User | None]] | None

Async callback to verify a bearer token (token auth).

login_url str | None

URL to redirect unauthenticated browsers to. Set toNoneto disable redirects (return 401 instead).

exclude_paths frozenset[str]

Paths that skip authentication entirely.

AuthMiddleware 6
Dual-mode authentication middleware. Tries token auth first (stateless, for API clients), then fal…

Dual-mode authentication middleware.

Tries token auth first (stateless, for API clients), then falls back to session auth (stateful, for browsers). Sets the authenticated user in a ContextVar accessible viaget_user().

Middleware ordering::

app.add_middleware(SessionMiddleware(...))  # 1st: sessions
app.add_middleware(AuthMiddleware(...))      # 2nd: auth
app.add_middleware(CSRFMiddleware())         # 3rd: CSRF

Usage::

from chirp.middleware.auth import AuthConfig, AuthMiddleware

app.add_middleware(AuthMiddleware(AuthConfig(
    load_user=db.get_user_by_id,
    verify_token=db.get_user_by_token,
)))

Attributes

Name Type Description
template_globals ClassVar[dict[str, Any]]

Methods

Internal Methods 5
__init__ 1
def __init__(self, config: AuthConfig | None = None) -> None
Parameters
Name Type Description
config Default:None
_extract_token 1 str | None
Extract bearer token from the Authorization header.
def _extract_token(self, request: Request) -> str | None
Parameters
Name Type Description
request
Returns
str | None
_authenticate_token 1 User | None
Try token-based authentication.
async
async def _authenticate_token(self, request: Request) -> User | None
Parameters
Name Type Description
request
Returns
User | None
_authenticate_session 0 User | None
Try session-based authentication.
async
async def _authenticate_session(self) -> User | None
Returns
User | None
__call__ 2 AnyResponse
Authenticate the request, then dispatch.
async
async def __call__(self, request: Request, next: Next) -> AnyResponse
Parameters
Name Type Description
request
next
Returns
AnyResponse

Functions

get_user 0 User
Return the current authenticated user (or ``AnonymousUser``). Raises ``LookupE…
def get_user() -> User

Return the current authenticated user (orAnonymousUser).

RaisesLookupErrorif called outside a request with AuthMiddlewareactive.

Returns
User
login 1 None
Log in a user — regenerate session, set user ID, update ContextVar. Regenerate…
def login(user: User) -> None

Log in a user — regenerate session, set user ID, update ContextVar.

Regenerates the session to prevent session fixation attacks. Call from your login handler after verifying credentials::

user = await verify_credentials(email, password)
if user:
    login(user)
    return Redirect("/dashboard")

RequiresSessionMiddleware and AuthMiddlewareto be active.

Parameters
Name Type Description
user User
logout 0 None
Log out the current user — regenerate session + clear ContextVar. Regenerates …
def logout() -> None

Log out the current user — regenerate session + clear ContextVar.

Regenerates the session to discard all session data (not just the user ID). Call from your logout handler::

logout()
return Redirect("/")

RequiresSessionMiddleware and AuthMiddlewareto be active.

current_user 0 User
Return the current user for templates. Template-friendly alias for ``get_user(…
def current_user() -> User

Return the current user for templates.

Template-friendly alias forget_user(). Returns AnonymousUser if no user is authenticated, never raises.

Registered as a template global whenAuthMiddlewareis active::

{% if current_user().is_authenticated %}
    <a href="/profile">{{ current_user().name }}</a>
{% else %}
    <a href="/login">Sign in</a>
{% endif %}
Returns
User