This is an automated email from the ASF dual-hosted git repository.

pierrejeambrun pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 3e3b44cd4fe UI: Block polling requests to endpoints that returned 403 
Forbidden (#64333)
3e3b44cd4fe is described below

commit 3e3b44cd4fefba2beef91c7468f5dc678ab21f59
Author: Pierre Jeambrun <[email protected]>
AuthorDate: Mon Mar 30 18:19:18 2026 +0200

    UI: Block polling requests to endpoints that returned 403 Forbidden (#64333)
    
    * UI: Block polling requests to endpoints that returned 403 Forbidden
    
    Adds axios interceptors to track URLs that return 403 and abort
    subsequent requests to those URLs. Permissions don't change mid-session,
    so this prevents wasted polling traffic without requiring per-component
    changes.
    
    * UI: Only block polling for permission-based 403s, not auth-related ones
    
    Narrow the 403 URL tracking to responses with detail "Forbidden"
    (missing permissions). Auth-related 403s like "Invalid JWT token"
    are left alone to trigger the login redirect.
    
    ---------
    
    Co-authored-by: Rahul Vats <[email protected]>
---
 airflow-core/src/airflow/ui/src/main.tsx | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/airflow-core/src/airflow/ui/src/main.tsx 
b/airflow-core/src/airflow/ui/src/main.tsx
index 44d9934f75e..9fb55690e4c 100644
--- a/airflow-core/src/airflow/ui/src/main.tsx
+++ b/airflow-core/src/airflow/ui/src/main.tsx
@@ -48,6 +48,23 @@ Reflect.set(globalThis, "ReactRouterDOM", ReactRouterDOM);
 Reflect.set(globalThis, "ChakraUI", ChakraUI);
 Reflect.set(globalThis, "EmotionReact", EmotionReact);
 
+// URLs that returned 403 Forbidden. Permissions won't change mid-session,
+// so we block further requests to avoid spamming the server with polling.
+const forbidden403Urls = new Set<string>();
+
+// Block outgoing requests to URLs that previously returned 403.
+// The request is aborted immediately so no network traffic occurs.
+axios.interceptors.request.use((config) => {
+  if (config.url !== undefined && forbidden403Urls.has(config.url)) {
+    const controller = new AbortController();
+
+    controller.abort();
+    config.signal = controller.signal;
+  }
+
+  return config;
+});
+
 // redirect to login page if the API responds with unauthorized or forbidden 
errors
 axios.interceptors.response.use(
   (response) => response,
@@ -64,6 +81,16 @@ axios.interceptors.response.use(
       globalThis.location.replace(`${loginPath}?${params.toString()}`);
     }
 
+    // Track permission-based 403 URLs so future polling requests are blocked 
at the request interceptor.
+    // Only block "Forbidden" (missing permissions), not other auth-related 
403s.
+    if (
+      error.response?.status === 403 &&
+      error.response.data.detail === "Forbidden" &&
+      error.config?.url !== undefined
+    ) {
+      forbidden403Urls.add(error.config.url);
+    }
+
     return Promise.reject(error);
   },
 );

Reply via email to