"""Resolve the application-relative request path behind a reverse proxy. A reverse proxy may forward requests under a path prefix, e.g. ``/xxx/api/v1/auth/login/token``. FastAPI strips that prefix for **routing** when it is told about it via the ASGI ``root_path`` (uvicorn ``--root-path`` / ``--proxy-headers``, or ``X-Forwarded-Prefix`` from the proxy) — which is why the route still matches and the request reaches a handler. Starlette middleware, however, runs *before* routing and sees the full, prefixed ``request.url.path``. Middlewares that match that raw path against fixed whitelists — the CSRF-exempt auth paths and the AuthMiddleware public paths — then mis-match, so login and ``/api/public/*`` endpoints get wrongly rejected (``CSRF token missing`` / ``401``) on a prefixed deployment. ``app_relative_path`` returns the path with the proxy prefix removed so that whitelist matching is prefix-agnostic. It is a no-op when no prefix is present (direct deployment), and tolerates the prefix already being stripped from the path (it only strips when the path actually starts with the prefix). """ from fastapi import Request def app_relative_path(request: Request) -> str: """Return ``request.url.path`` with any reverse-proxy prefix removed. Prefix source order: ASGI ``root_path`` (set by the server when the proxy forwards it), then the ``X-Forwarded-Prefix`` header (proxies that add a prefix without informing the ASGI server). Returns ``"/"`` for an empty result so downstream ``rstrip("/")`` / ``startswith`` checks stay sane. """ path = request.url.path or "/" prefix = (request.scope.get("root_path") or request.headers.get("x-forwarded-prefix") or "").rstrip("/") if prefix and path.startswith(prefix): stripped = path[len(prefix):] if not stripped: return "/" return stripped if stripped.startswith("/") else "/" + stripped return path