close
Skip to content

FAB Security views (Add/Edit/Show role/user links) miss /auth prefix when running behind a subpath reverse proxy (enable_proxy_fix + X-Forwarded-Prefix) #70389

Description

@bmatticus

Apache Airflow version

3.3.0

What happened?

When Airflow is deployed behind a reverse proxy under a URL subpath (a documented/supported pattern using [fab] enable_proxy_fix = True + [api] base_url + the proxy sending X-Forwarded-Prefix), the FAB-rendered Security pages (/auth/roles/list/, /auth/users/list/) generate "Add" / "Edit" / "Show" action links that are missing the /auth blueprint prefix.

For example, with subpath /myns/myrelease:

  • Expected: /myns/myrelease/auth/roles/add
  • Actual: /myns/myrelease/roles/add

Since the FAB blueprint is mounted under /auth, the broken link (missing /auth) resolves instead to the new React SPA shell, which has no client-side route for roles/users paths and silently redirects/bounces the user back to the Dashboard — with no visible error. This makes it effectively impossible to add/edit/view Roles or Users from the UI when Airflow is served under a subpath.

Notably, the List/Edit page URLs themselves (e.g. /auth/roles/list/) are correctly generated with the /auth prefix — it's specifically the row/page "Add", "Edit", and "Show" action links produced by FAB's ModelView machinery that drop the prefix, and only when X-Forwarded-Prefix/ProxyFix subpath handling is active.

What you think should happen instead?

The "Add"/"Edit"/"Show" action links on FAB Security views should include the /auth blueprint prefix (consistent with the page's own list/edit URLs), regardless of whether the app is served under a subpath via ProxyFix/X-Forwarded-Prefix.

How to reproduce

Minimal, clean-room repro with no custom Helm chart / ingress / Istio involved — plain apache/airflow:3.3.0-python3.12 Docker image, FAB auth manager, default webserver_config.py with AUTH_TYPE = AUTH_DB.

Control (no subpath) — works correctly:

docker run -d --name airflow-repro -p 18080:8080 \
  -e AIRFLOW__CORE__AUTH_MANAGER=airflow.providers.fab.auth_manager.fab_auth_manager.FabAuthManager \
  -e AIRFLOW__CORE__EXECUTOR=LocalExecutor \
  -e AIRFLOW__DATABASE__SQL_ALCHEMY_CONN=sqlite:////opt/airflow/airflow.db \
  -v /path/to/webserver_config.py:/opt/airflow/webserver_config.py:ro \
  apache/airflow:3.3.0-python3.12 bash -c "airflow db migrate && (airflow scheduler &) && airflow api-server --port 8080"

docker exec airflow-repro airflow users create --username admin --firstname A --lastname B \
  --email admin@example.com --role Admin --password admin

Log in at http://localhost:18080/auth/login/, navigate to http://localhost:18080/auth/roles/list/.
The "Add" button's href is /auth/roles/add — correct.

Subpath repro (same image, add these two envs, and simulate a reverse proxy sending X-Forwarded-Prefix):

docker run -d --name airflow-repro -p 18080:8080 \
  -e AIRFLOW__CORE__AUTH_MANAGER=airflow.providers.fab.auth_manager.fab_auth_manager.FabAuthManager \
  -e AIRFLOW__CORE__EXECUTOR=LocalExecutor \
  -e AIRFLOW__DATABASE__SQL_ALCHEMY_CONN=sqlite:////opt/airflow/airflow.db \
  -e AIRFLOW__FAB__ENABLE_PROXY_FIX=True \
  -e AIRFLOW__API__BASE_URL=https://example.com/myns/myrelease \
  -v /path/to/webserver_config.py:/opt/airflow/webserver_config.py:ro \
  apache/airflow:3.3.0-python3.12 bash -c "airflow db migrate && (airflow scheduler &) && airflow api-server --port 8080"

Then make requests with an added header X-Forwarded-Prefix: /myns/myrelease (e.g. via a browser extension, a small proxy, or Playwright request interception) while browsing http://localhost:18080/myns/myrelease/auth/roles/list/.

The "Add" button's href is now /myns/myrelease/roles/addmissing /auth. Navigating to it loads the SPA shell instead of the FAB add-role form, and the SPA immediately redirects to the Dashboard since it has no client-side route matching roles/users paths.

Same image, same FAB version — only the proxy-fix/subpath config differs between the working and broken case.

Operating System

Debian (apache/airflow official Docker image base), also reproduced on AKS/Kubernetes with Istio ingress

Versions of Apache Airflow Providers

apache-airflow-providers-fab (bundled with Airflow 3.3.0)

Deployment

Other Docker-based deployment

Deployment details

Also reproduced in a Kubernetes deployment behind an Istio Ingress Gateway/VirtualService, with [fab] enable_proxy_fix = True and [api] base_url set to the subpath, and X-Forwarded-Prefix set by the ingress. Confirmed the ingress/VirtualService routing itself is not the cause (verified byte-identical FAB static assets, correct base_url resolution, correct ProxyFix redirect behavior for unauthenticated pages) — isolated the bug down to just the two Airflow-side config values (enable_proxy_fix + base_url/X-Forwarded-Prefix) via the clean-room Docker repro above.

Anything else?

This will affect any Airflow 3.x deployment using the FAB auth manager behind a reverse proxy serving Airflow under a URL subpath — a pattern explicitly documented and supported via [fab] enable_proxy_fix. Since the failure mode is a silent redirect to the Dashboard with no error message, it may be underreported/hard to notice at first (it looks like the button "does nothing").

Are you willing to submit a PR?

  • Yes I am willing to submit a PR!

Code of Conduct

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:UIRelated to UI/UX. For Frontend Developers.area:authkind:bugThis is a clearly a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions