From d3b79d48dd5a462f97c4642010468a506da1cabb Mon Sep 17 00:00:00 2001 From: Subham Sangwan Date: Sun, 8 Mar 2026 22:53:39 +0530 Subject: [PATCH 1/5] Fix regression in security iframe navigation logic with basename --- airflow-core/src/airflow/ui/src/pages/Security.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/airflow-core/src/airflow/ui/src/pages/Security.tsx b/airflow-core/src/airflow/ui/src/pages/Security.tsx index 011c101868697..bdb75daba329d 100644 --- a/airflow-core/src/airflow/ui/src/pages/Security.tsx +++ b/airflow-core/src/airflow/ui/src/pages/Security.tsx @@ -43,8 +43,16 @@ export const Security = () => { const onLoad = () => { const iframe: HTMLIFrameElement | null = document.querySelector("#security-iframe"); - if (iframe?.contentWindow && !iframe.contentWindow.location.pathname.startsWith("/auth/")) { - void Promise.resolve(navigate("/")); + if (iframe?.contentWindow) { + const baseUrl = document.querySelector("base")?.href ?? "http://localhost:8080/"; + const basename = new URL(baseUrl).pathname.replace(/\/$/u, ""); + + const iframePath = iframe.contentWindow.location.pathname; + const pathWithoutBase = iframePath.startsWith(basename) ? iframePath.slice(basename.length) : iframePath; + + if (!pathWithoutBase.startsWith("/auth/")) { + void Promise.resolve(navigate("/")); + } } }; From 516d25bc60dce2586cfac2b3c40e7d1213f3c047 Mon Sep 17 00:00:00 2001 From: Subham Sangwan Date: Mon, 9 Mar 2026 17:22:38 +0530 Subject: [PATCH 2/5] style: apply formatting to Security.tsx --- airflow-core/src/airflow/ui/src/pages/Security.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/airflow-core/src/airflow/ui/src/pages/Security.tsx b/airflow-core/src/airflow/ui/src/pages/Security.tsx index bdb75daba329d..5cdfe31948fd1 100644 --- a/airflow-core/src/airflow/ui/src/pages/Security.tsx +++ b/airflow-core/src/airflow/ui/src/pages/Security.tsx @@ -48,7 +48,9 @@ export const Security = () => { const basename = new URL(baseUrl).pathname.replace(/\/$/u, ""); const iframePath = iframe.contentWindow.location.pathname; - const pathWithoutBase = iframePath.startsWith(basename) ? iframePath.slice(basename.length) : iframePath; + const pathWithoutBase = iframePath.startsWith(basename) + ? iframePath.slice(basename.length) + : iframePath; if (!pathWithoutBase.startsWith("/auth/")) { void Promise.resolve(navigate("/")); From 90e868eacdf1b629738280361bdf365780fdb658 Mon Sep 17 00:00:00 2001 From: Subham Sangwan Date: Mon, 9 Mar 2026 19:26:23 +0530 Subject: [PATCH 3/5] fix(ui): remove hardcoded localhost fallback from Security iframe navigation --- airflow-core/src/airflow/ui/src/pages/Security.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/airflow-core/src/airflow/ui/src/pages/Security.tsx b/airflow-core/src/airflow/ui/src/pages/Security.tsx index 5cdfe31948fd1..0fb95d72391c3 100644 --- a/airflow-core/src/airflow/ui/src/pages/Security.tsx +++ b/airflow-core/src/airflow/ui/src/pages/Security.tsx @@ -44,8 +44,8 @@ export const Security = () => { const iframe: HTMLIFrameElement | null = document.querySelector("#security-iframe"); if (iframe?.contentWindow) { - const baseUrl = document.querySelector("base")?.href ?? "http://localhost:8080/"; - const basename = new URL(baseUrl).pathname.replace(/\/$/u, ""); + const baseHref = document.querySelector("base")?.href; + const basename = baseHref === undefined ? "" : new URL(baseHref).pathname.replace(/\/$/u, ""); const iframePath = iframe.contentWindow.location.pathname; const pathWithoutBase = iframePath.startsWith(basename) From ee4be680cf1b242ca1e8002c4b3a1b43fe219da8 Mon Sep 17 00:00:00 2001 From: Subham Sangwan Date: Mon, 9 Mar 2026 19:38:07 +0530 Subject: [PATCH 4/5] Add newsfragment for security iframe basename fix --- airflow-core/newsfragments/63141.bugfix.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 airflow-core/newsfragments/63141.bugfix.rst diff --git a/airflow-core/newsfragments/63141.bugfix.rst b/airflow-core/newsfragments/63141.bugfix.rst new file mode 100644 index 0000000000000..c9855b3f5e49b --- /dev/null +++ b/airflow-core/newsfragments/63141.bugfix.rst @@ -0,0 +1 @@ +Fix security iframe navigation when AIRFLOW__API__BASE_URL basename is configured From acd496fc7ac0c343822e7a90cdc359b5a9976c5c Mon Sep 17 00:00:00 2001 From: Subham Sangwan Date: Tue, 10 Mar 2026 21:35:04 +0530 Subject: [PATCH 5/5] Address review feedback: simplify security iframe navigation logic and handle basename --- .../src/airflow/ui/src/pages/Security.tsx | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/airflow-core/src/airflow/ui/src/pages/Security.tsx b/airflow-core/src/airflow/ui/src/pages/Security.tsx index 0fb95d72391c3..c3b0fb89309d4 100644 --- a/airflow-core/src/airflow/ui/src/pages/Security.tsx +++ b/airflow-core/src/airflow/ui/src/pages/Security.tsx @@ -17,8 +17,7 @@ * under the License. */ import { Box } from "@chakra-ui/react"; -import { useParams } from "react-router-dom"; -import { useNavigate } from "react-router-dom"; +import { useNavigate, useParams } from "react-router-dom"; import { useAuthLinksServiceGetAuthMenus } from "openapi/queries"; import { ProgressBar } from "src/components/ui"; @@ -44,16 +43,10 @@ export const Security = () => { const iframe: HTMLIFrameElement | null = document.querySelector("#security-iframe"); if (iframe?.contentWindow) { - const baseHref = document.querySelector("base")?.href; - const basename = baseHref === undefined ? "" : new URL(baseHref).pathname.replace(/\/$/u, ""); + const base = new URL(document.baseURI).pathname.replace(/\/$/u, ""); // Remove trailing slash if exists - const iframePath = iframe.contentWindow.location.pathname; - const pathWithoutBase = iframePath.startsWith(basename) - ? iframePath.slice(basename.length) - : iframePath; - - if (!pathWithoutBase.startsWith("/auth/")) { - void Promise.resolve(navigate("/")); + if (!iframe.contentWindow.location.pathname.startsWith(`${base}/auth/`)) { + void navigate("/"); } } };