enlace_auth.auth.middleware#
Platform auth middleware (pure ASGI).
Runs before any mounted sub-app. Responsibilities:
Normalize the request path and reject known traversal bypasses.
Strip client-provided identity headers so apps can’t be fooled by spoofed
X-User-ID/X-Forwarded-User/ similar.Resolve the access level for the request by longest-prefix match on the route prefix of each mounted app. Deny-by-default: an unmatched path is treated as
protected:user.For
public/local, pass through withuser_id=None.For
protected:shared, look for a per-app signed cookie; on failure return 401 (JSON) or redirect browsers tologin_redirect_path.For
protected:user, look for the platform session cookie, load the session fromSessionStore, setuser_id/user_email; on failure return 401 (JSON) or redirect browsers tologin_redirect_path.
Browser vs. API deny behavior: GET/HEAD navigations that look like a browser
(Accept header contains text/html) get a 303 redirect to the login
page with ?login_required=1&next=<original-path>, so the user lands
somewhere meaningful instead of seeing a raw JSON error. Non-HTML requests
(XHR, fetch with Accept: application/json, curl, etc.) keep getting the
machine-readable 401.
Design notes:
Pure ASGI three-callable pattern. Never
BaseHTTPMiddleware(see CLAUDE.md).Exempts
/auth/*from auth checks so login/register pages stay reachable.
Classes
|
Auth policy for a single mount prefix. |
|
Signed double-submit CSRF for state-changing requests. |
|
Pure-ASGI auth middleware. |
- class enlace_auth.auth.middleware.AccessRule(prefix, level, app_id, shared_password_hash=None, allowed_users=(), deny_signed_in=True)[source]#
Bases:
objectAuth policy for a single mount prefix.
- class enlace_auth.auth.middleware.CSRFMiddleware(app, *, signing_key, cookie_name='enlace_csrf', header_name='X-CSRF-Token', exempt_prefixes=('/auth/callback', '/auth/login/', '/api/'), enforce_prefixes=(), mint_prefixes=None)[source]#
Bases:
objectSigned double-submit CSRF for state-changing requests.
On safe-method requests, sets an
enlace_csrfcookie if one isn’t present. On state-changing requests, requires the cookie and anX-CSRF-Tokenheader to match after signature verification.mint_prefixesnarrows where the cookie is set (not where the check runs): a request outside every prefix never receives one. The default,None, mints on every safe request. The platform plugin passes the places a state-changing request can follow, so apublicapp’s pages set no cookie (i2mint/enlace_auth#31).Exempt paths skip the check entirely. Defaults exempt sub-app APIs under
/api/because theenlace_sessioncookie isSameSite=Lax: a cross-site POST from an attacker site arrives without credentials and is rejected by PlatformAuthMiddleware regardless of CSRF. This keeps pre-enlace apps working out of the box without each having to implement the/auth/csrfdouble-submit flow. The auth endpoints themselves (/auth/login,/auth/register,/auth/logout) stay protected.
- class enlace_auth.auth.middleware.PlatformAuthMiddleware(app, *, access_rules, session_store, signing_key, cookie_name='enlace_session', max_age=86400, auth_path_prefix='/auth', login_redirect_path='/', dynamic_allowed_users=None)[source]#
Bases:
objectPure-ASGI auth middleware. See module docstring for behavior.