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/add — missing /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?
Code of Conduct
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 sendingX-Forwarded-Prefix), the FAB-rendered Security pages (/auth/roles/list/,/auth/users/list/) generate "Add" / "Edit" / "Show" action links that are missing the/authblueprint prefix.For example, with subpath
/myns/myrelease:/myns/myrelease/auth/roles/add/myns/myrelease/roles/addSince 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 forroles/userspaths 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/authprefix — it's specifically the row/page "Add", "Edit", and "Show" action links produced by FAB's ModelView machinery that drop the prefix, and only whenX-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
/authblueprint 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.12Docker image, FAB auth manager, defaultwebserver_config.pywithAUTH_TYPE = AUTH_DB.Control (no subpath) — works correctly:
Log in at
http://localhost:18080/auth/login/, navigate tohttp://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 browsinghttp://localhost:18080/myns/myrelease/auth/roles/list/.The "Add" button's href is now
/myns/myrelease/roles/add— missing/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 matchingroles/userspaths.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 = Trueand[api] base_urlset to the subpath, andX-Forwarded-Prefixset 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?
Code of Conduct