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

vatsrahul1001 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 2723f66d6ed Make CORS allow_credentials configurable (#66503)
2723f66d6ed is described below

commit 2723f66d6ed086eb68fddcdc0798e1ae3df40904
Author: Jarek Potiuk <[email protected]>
AuthorDate: Tue May 19 15:37:55 2026 +0200

    Make CORS allow_credentials configurable (#66503)
    
    * Make CORS allow_credentials configurable
    
    The FastAPI CORS middleware was initialized with allow_credentials=True
    hardcoded. Add a new [api] access_control_allow_credentials boolean
    option (default True to preserve existing behavior) so deployments that
    configure access_control_allow_origins but do not want credentialed
    cross-origin requests can opt out.
    
    * Address review nits: bump version_added to 3.2.2, hoist imports
    
    - config.yml: version_added 3.2.0 -> 3.2.2 to match the backport target
    - test_app.py: move FastAPI, CORSMiddleware, init_config, and conf_vars
      imports to the top of the file instead of inline inside the test method.
    
    ---------
    
    Co-authored-by: vatsrahul1001 <[email protected]>
---
 airflow-core/docs/security/api.rst                 |  5 +++++
 .../src/airflow/api_fastapi/core_api/app.py        |  3 ++-
 .../src/airflow/config_templates/config.yml        | 10 ++++++++++
 .../tests/unit/api_fastapi/core_api/test_app.py    | 23 ++++++++++++++++++++++
 4 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/airflow-core/docs/security/api.rst 
b/airflow-core/docs/security/api.rst
index 811e51084d6..c02033d0b12 100644
--- a/airflow-core/docs/security/api.rst
+++ b/airflow-core/docs/security/api.rst
@@ -86,6 +86,11 @@ from scripts running in the browser.
     access_control_allow_methods = POST, GET, OPTIONS, DELETE
     access_control_allow_origins = https://exampleclientapp1.com 
https://exampleclientapp2.com
 
+The ``Access-Control-Allow-Credentials`` header is included by default. Set
+``access_control_allow_credentials = False`` if you have configured
+``access_control_allow_origins`` and do not want browsers to send credentials
+(cookies, ``Authorization`` header) with cross-origin requests.
+
 Page size limit
 ---------------
 
diff --git a/airflow-core/src/airflow/api_fastapi/core_api/app.py 
b/airflow-core/src/airflow/api_fastapi/core_api/app.py
index c36bb6c978f..20ecbedb236 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/app.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/app.py
@@ -143,12 +143,13 @@ def init_config(app: FastAPI) -> None:
     allow_origins = conf.getlist("api", "access_control_allow_origins")
     allow_methods = conf.getlist("api", "access_control_allow_methods")
     allow_headers = conf.getlist("api", "access_control_allow_headers")
+    allow_credentials = conf.getboolean("api", 
"access_control_allow_credentials", fallback=True)
 
     if allow_origins or allow_methods or allow_headers:
         app.add_middleware(
             CORSMiddleware,
             allow_origins=allow_origins,
-            allow_credentials=True,
+            allow_credentials=allow_credentials,
             allow_methods=allow_methods,
             allow_headers=allow_headers,
         )
diff --git a/airflow-core/src/airflow/config_templates/config.yml 
b/airflow-core/src/airflow/config_templates/config.yml
index 57ddd14a6cb..f93642dd8ed 100644
--- a/airflow-core/src/airflow/config_templates/config.yml
+++ b/airflow-core/src/airflow/config_templates/config.yml
@@ -1797,6 +1797,16 @@ api:
       version_added: 2.2.0
       example: ~
       default: ""
+    access_control_allow_credentials:
+      description: |
+        Whether the FastAPI server includes the 
``Access-Control-Allow-Credentials`` header on
+        CORS responses. Defaults to True to preserve existing behavior; set to 
False if you have
+        configured ``access_control_allow_origins`` and do not want browsers 
to send credentials
+        (cookies, Authorization header) with cross-origin requests.
+      type: boolean
+      version_added: 3.2.2
+      example: ~
+      default: "True"
     grid_view_sorting_order:
       description: |
         Sorting order in grid view. Valid values are: ``topological``, 
``hierarchical_alphabetical``
diff --git a/airflow-core/tests/unit/api_fastapi/core_api/test_app.py 
b/airflow-core/tests/unit/api_fastapi/core_api/test_app.py
index 061ac788d8d..7a999e0f3b3 100644
--- a/airflow-core/tests/unit/api_fastapi/core_api/test_app.py
+++ b/airflow-core/tests/unit/api_fastapi/core_api/test_app.py
@@ -21,15 +21,19 @@ import inspect
 import typing
 
 import pytest
+from fastapi import FastAPI
+from fastapi.middleware.cors import CORSMiddleware
 from fastapi.params import Depends as DependsClass
 from fastapi.responses import StreamingResponse
 from starlette.routing import Mount
 
 from airflow.api_fastapi.app import create_app
+from airflow.api_fastapi.core_api.app import init_config
 from airflow.api_fastapi.core_api.routes.public import authenticated_router
 from airflow.api_fastapi.core_api.routes.ui import ui_router
 from airflow.api_fastapi.core_api.security import get_user
 
+from tests_common.test_utils.config import conf_vars
 from tests_common.test_utils.db import clear_db_jobs
 
 pytestmark = pytest.mark.db_test
@@ -143,3 +147,22 @@ class TestRouterLevelDefaultDeny:
             "ui_router must declare Depends(get_user) at the router level so 
every UI endpoint "
             "default-denies unauthenticated requests."
         )
+
+
+class TestCorsMiddlewareAllowCredentials:
+    @pytest.mark.parametrize(
+        ("config_value", "expected_allow_credentials"),
+        [(None, True), ("True", True), ("False", False)],
+    )
+    def test_init_config_passes_allow_credentials(self, config_value, 
expected_allow_credentials):
+        config = {("api", "access_control_allow_origins"): 
"https://example.com"}
+        if config_value is not None:
+            config[("api", "access_control_allow_credentials")] = config_value
+
+        with conf_vars(config):
+            app = FastAPI()
+            init_config(app)
+
+        cors_middlewares = [m for m in app.user_middleware if m.cls is 
CORSMiddleware]
+        assert len(cors_middlewares) == 1
+        assert cors_middlewares[0].kwargs["allow_credentials"] is 
expected_allow_credentials

Reply via email to