corvix.web.middleware¶
Token-based authentication middleware for the Corvix web app.
When CORVIX_SECRET_TOKEN (or CORVIX_SECRET_TOKEN_FILE) is set:
/api/*routes (except/api/health) and/metricsrequire anAuthorization: Bearer <token>orX-Corvix-Token: <token>header, or a validcorvix_sessioncookie (so the browser SPA works after logging in via the web UI without needing to inject headers; Prometheus scrape configs use the bearer-token form).UI routes (
/,/dashboards/*) require acorvix_sessioncookie; requests without a valid cookie are redirected to/login./api/health,/assets/*,/login, and/logoutare always public.
When the environment variable is not set, the middleware is a no-op and the app behaves exactly as before (backward compatible).
Fail-closed misconfiguration¶
If both CORVIX_SECRET_TOKEN and CORVIX_SECRET_TOKEN_FILE are set,
corvix.env.get_env_value() cannot determine which one wins. This is
treated as a hard misconfiguration, never as “auth disabled”: the app
refuses to start (see _validate_secret_config in corvix.web.app),
and as defense in depth this middleware also rejects every non-public
request with 500 instead of passing it through.
HTTPS detection¶
The corvix_session cookie is marked Secure only when the request
arrives over HTTPS. The scheme is read from request.url.scheme, which
reflects the real protocol when uvicorn is started with --proxy-headers
(trusting X-Forwarded-Proto from a reverse proxy). Without that flag,
direct HTTPS connections are still detected correctly via the connection
scheme. Do not rely on raw X-Forwarded-Proto header inspection from
application code: untrusted clients can spoof it.
Attributes¶
Exceptions¶
Raised when CORVIX_SECRET_TOKEN and CORVIX_SECRET_TOKEN_FILE are both set. |
Classes¶
Optional token-based authentication middleware. |
Functions¶
|
Return a signed, time-limited session cookie value. |
|
Return True when value is a valid, unexpired session token. |
|
Parse a raw |
|
Return the configured secret token, or an empty string if not set. |
|
Return True when path should never require authentication. |
|
Send a complete ASGI HTTP response (start + body events). |
|
Send a minimal JSON 401 Unauthorized response via ASGI. |
|
Send a minimal JSON 500 response for a misconfigured secret (fail closed). |
|
Send a 302 redirect response via ASGI. |
|
Extract and normalise HTTP headers from an ASGI scope. |
|
Return True when the request carries valid API credentials. |
|
Return True when the request carries a valid |
Module Contents¶
- corvix.web.middleware._make_session_cookie(secret: str) str[source][source]¶
Return a signed, time-limited session cookie value.
Format:
{expiry_unix_timestamp}:{hmac_sha256_hex}The HMAC covers both the fixed context string and the expiry timestamp so that the expiry cannot be extended without knowing the secret.
- corvix.web.middleware._verify_session_cookie(secret: str, value: str) bool[source][source]¶
Return True when value is a valid, unexpired session token.
Validates the HMAC signature and rejects tokens whose expiry timestamp is in the past. Uses
hmac.compare_digest()to prevent timing attacks.
- corvix.web.middleware._parse_cookies(cookie_header: str) dict[str, str][source][source]¶
Parse a raw
Cookieheader value into a name→value dict.Uses
http.cookies.SimpleCookiefrom the standard library to handle quoted values and other edge cases correctly.
- exception corvix.web.middleware.SecretConfigError[source][source]¶
Bases:
RuntimeErrorRaised when CORVIX_SECRET_TOKEN and CORVIX_SECRET_TOKEN_FILE are both set.
- corvix.web.middleware._MISCONFIGURED_MESSAGE = 'CORVIX_SECRET_TOKEN misconfigured: both CORVIX_SECRET_TOKEN and CORVIX_SECRET_TOKEN_FILE are...[source][source]¶
- corvix.web.middleware._get_secret() str[source][source]¶
Return the configured secret token, or an empty string if not set.
Results are cached for
_SECRET_CACHE_TTLseconds so that deployments usingCORVIX_SECRET_TOKEN_FILEdo not incur a synchronous disk read on every request. A configuration change takes effect within one TTL window.- Raises:
SecretConfigError: when both
CORVIX_SECRET_TOKENandCORVIX_SECRET_TOKEN_FILEare set. This is a hard failure — callers must fail closed (deny the request) rather than treat it as “no auth configured”. Logs an error once per process to avoid flooding logs under load; the misconfigured state is itself cached for the TTL so repeated requests do not re-read the environment.
- corvix.web.middleware._is_public(path: str) bool[source][source]¶
Return True when path should never require authentication.
- async corvix.web.middleware._send_asgi_response(send: litestar.types.asgi_types.Send, status: int, body: bytes, headers: list[tuple[bytes, bytes]]) None[source][source]¶
Send a complete ASGI HTTP response (start + body events).
- async corvix.web.middleware._send_json_401(send: litestar.types.asgi_types.Send) None[source][source]¶
Send a minimal JSON 401 Unauthorized response via ASGI.
- async corvix.web.middleware._send_json_500(send: litestar.types.asgi_types.Send) None[source][source]¶
Send a minimal JSON 500 response for a misconfigured secret (fail closed).
- async corvix.web.middleware._send_redirect(send: litestar.types.asgi_types.Send, location: bytes) None[source][source]¶
Send a 302 redirect response via ASGI.
- corvix.web.middleware._parse_request_headers(scope: litestar.types.asgi_types.Scope) dict[bytes, bytes][source][source]¶
Extract and normalise HTTP headers from an ASGI scope.
RFC 7230 §3.2.4: header field values are ISO-8859-1 (latin-1); using latin-1 decoding (rather than strict UTF-8) means malformed byte sequences never raise
UnicodeDecodeErrorand produce a clean 401/redirect instead of a 500.RFC 6265 §5.4: a request may carry multiple
Cookieheaders; they must be treated as if joined by"; ". A plain dict comprehension would silently drop all but the last occurrence, so Cookie header bytes are accumulated separately and joined before being stored.
- corvix.web.middleware._check_api_auth(raw_headers: dict[bytes, bytes], secret: str) bool[source][source]¶
Return True when the request carries valid API credentials.
Checks
Authorization: BearerandX-Corvix-Tokenheaders first (programmatic clients, curl, etc.). Falls back to thecorvix_sessioncookie so browser SPAs work after logging in via the web UI without needing to inject custom headers into everyfetch()call.
- corvix.web.middleware._check_ui_auth(raw_headers: dict[bytes, bytes], secret: str) bool[source][source]¶
Return True when the request carries a valid
corvix_sessioncookie.
- class corvix.web.middleware.TokenAuthMiddleware[source][source]¶
Bases:
litestar.middleware.base.ASGIMiddlewareOptional token-based authentication middleware.
Reads the secret from
CORVIX_SECRET_TOKEN(orCORVIX_SECRET_TOKEN_FILE) with a 60-second TTL cache so that config changes take effect without a restart while avoiding per-request file I/O. When the variable is absent the middleware is a transparent pass-through.