This is an automated email from the ASF dual-hosted git repository.
shahar1 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 7a7935754ed Stop airflowctl auth commands sending the stored token to
--api-url (#76280)
7a7935754ed is described below
commit 7a7935754ed60e4bfaf37228c4d479ac77a2f5cd
Author: Andrew Chang <[email protected]>
AuthorDate: Tue Nov 3 02:31:40 2026 +0800
Stop airflowctl auth commands sending the stored token to --api-url (#76280)
`auth login` and `auth token` log in with a username and password.
Before they run, the decorator builds the API client with the token
stored for the current environment. The commands then switch the client
to the URL from `--api-url`, but the client still adds the stored token
to every request.
If the URL is wrong, or points to another server, that server receives
the stored token. The `/auth/token/cli` endpoints of the simple, FAB and
Keycloak auth managers only read the username and password, so the
token is never needed there.
---
airflow-ctl/src/airflowctl/api/client.py | 2 +-
airflow-ctl/tests/airflow_ctl/api/test_client.py | 24 ++++++++++++++++++++++++
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/airflow-ctl/src/airflowctl/api/client.py
b/airflow-ctl/src/airflowctl/api/client.py
index b692c2f2e2d..7aa6de6e8df 100644
--- a/airflow-ctl/src/airflowctl/api/client.py
+++ b/airflow-ctl/src/airflowctl/api/client.py
@@ -426,7 +426,7 @@ class Client(httpx.Client):
**kwargs: Any,
) -> None:
auth: httpx.Auth | None = None
- if kind != ClientKind.NO_AUTH:
+ if kind == ClientKind.CLI:
auth = BearerAuth(token)
kwargs["base_url"] = self._get_base_url(base_url=base_url, kind=kind)
# Connect stays short so an unreachable host fails fast; the rest is
generous because
diff --git a/airflow-ctl/tests/airflow_ctl/api/test_client.py
b/airflow-ctl/tests/airflow_ctl/api/test_client.py
index 17d1f634888..3e5f79f8e05 100644
--- a/airflow-ctl/tests/airflow_ctl/api/test_client.py
+++ b/airflow-ctl/tests/airflow_ctl/api/test_client.py
@@ -254,6 +254,30 @@ class TestClient:
client.refresh_base_url(base_url=base_url, kind=client_kind)
assert client.base_url == URL(expected_base_url)
+ @pytest.mark.parametrize(
+ ("client_kind", "expected_authorization"),
+ [
+ pytest.param(ClientKind.CLI, "Bearer STORED_TOKEN", id="cli"),
+ pytest.param(ClientKind.AUTH, None, id="auth"),
+ ],
+ )
+ def test_authorization_header_by_kind(self, client_kind,
expected_authorization):
+ requests: list[httpx.Request] = []
+
+ def handle_request(request: httpx.Request) -> httpx.Response:
+ requests.append(request)
+ return httpx.Response(201, json={})
+
+ client = Client(
+ base_url="http://other-server",
+ token="STORED_TOKEN",
+ kind=client_kind,
+ transport=httpx.MockTransport(handle_request),
+ )
+ client.post("token/cli", json={})
+
+ assert requests[0].headers.get("Authorization") ==
expected_authorization
+
class TestRequestRetries:
@pytest.fixture(autouse=True)