flip_api.utils.security_headers

HTTP security headers middleware for the flip-api FastAPI application.

Injects defensive headers on every response. These headers are safe for both HTML (SPA) and JSON (API) responses. Content-Security-Policy is included for text/html responses only; the SPA primarily relies on CloudFront edge CSP for HTML assets.

Attributes

logger

Classes

SecurityHeadersMiddleware

Inject standard HTTP security headers on every response.

Module Contents

flip_api.utils.security_headers.logger
class flip_api.utils.security_headers.SecurityHeadersMiddleware

Bases: starlette.middleware.base.BaseHTTPMiddleware

Inject standard HTTP security headers on every response.

These headers are safe for both HTML (SPA) and JSON (API) responses.

Content-Security-Policy is only added for text/html responses because flip-api is JSON-first: the SPA itself is served from CloudFront + S3 and its CSP is set at the CloudFront edge. The CSP header here is defence-in-depth — in production flip-api never emits HTML (main.py sets docs_url=None when ENV == "production"), and the middleware’s own fallback is a PlainTextResponse, not HTML. connect-src, img-src, and font-src are intentionally omitted: they all fall back to default-src 'self', which already blocks third-party loads.

The FastAPI docs routes (/api/docs, /api/redoc, /api/openapi.json) are explicitly excluded from CSP injection: Swagger UI and ReDoc ship inline scripts and load their bundles from cdn.jsdelivr.net, both of which the default script-src 'self' would block. These pages are off in production (main.py sets docs_url=None when ENV == "production"); the exclusion only keeps them usable in dev/stag. All other security headers (HSTS, XFO, XCTO, RP) still apply to docs routes.

SECURITY_HEADERS
DOCS_PATHS = ('/api/docs', '/api/redoc', '/api/openapi.json')
CSP = "default-src 'self'; style-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none';"
async dispatch(request: starlette.requests.Request, call_next) starlette.responses.Response

Apply security headers to every response.

Wraps call_next in try/except so that security headers are injected even when the downstream handler raises an unhandled exception. On the exception path the traceback is logged and a 500 fallback response is returned with the same security headers — this is more secure than re-raising and letting the framework’s outermost error middleware produce a bare response with no headers.

Parameters:
  • request – The incoming HTTP request.

  • call_next – The next middleware or route handler in the chain.

Returns:

Response with security headers injected.