flip_api.utils.security_headers =============================== .. py:module:: flip_api.utils.security_headers .. autoapi-nested-parse:: 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 ---------- .. autoapisummary:: flip_api.utils.security_headers.logger Classes ------- .. autoapisummary:: flip_api.utils.security_headers.SecurityHeadersMiddleware Module Contents --------------- .. py:data:: logger .. py:class:: SecurityHeadersMiddleware Bases: :py:obj:`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 responses with a ``text/html`` content type; for API JSON responses (the norm) CSP is not set by this middleware — only at the CloudFront edge for the SPA. .. py:attribute:: SECURITY_HEADERS .. py:attribute:: DOCS_PATHS :value: ('/api/docs', '/api/redoc', '/api/openapi.json') .. py:attribute:: CSP :value: "default-src 'self'; style-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none';" .. py:method:: dispatch(request: starlette.requests.Request, call_next) -> starlette.responses.Response :async: 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. CSP is skipped on FastAPI docs routes (``/api/docs``, ``/api/redoc``, ``/api/openapi.json``) because Swagger UI and ReDoc load JavaScript and CSS from ``cdn.jsdelivr.net`` and run inline init scripts that the enforcing CSP would block. These routes are disabled in production anyway (see ``flip_api/main.py``), so the gap only affects dev/staging. All other security headers (HSTS, XFO, XCTO, RP) still apply to docs routes. :param request: The incoming HTTP request. :param call_next: The next middleware or route handler in the chain. :returns: Response with security headers injected.