This is an automated email from the ASF dual-hosted git repository.
jason810496 pushed a commit to branch v3-2-test
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/v3-2-test by this push:
new ef5787bc563 [v3-2-test] Revoke JWT on /auth/logout regardless of auth
manager logout URL (#67289) (#67362)
ef5787bc563 is described below
commit ef5787bc563b973831bb45a2667b6e2b8e8ff67a
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Sat May 23 10:27:32 2026 +0800
[v3-2-test] Revoke JWT on /auth/logout regardless of auth manager logout
URL (#67289) (#67362)
Previously, when an auth manager's get_url_logout() returned a URL, the
/auth/logout endpoint short-circuited via early return and never invoked
auth_manager.revoke_token(token_str). The JWT therefore remained valid
after logout for auth managers like FabAuthManager and KeycloakAuthManager
that redirect to an external logout URL.
Move the revoke_token call before the early return so logout reliably
invalidates the JWT token regardless of which auth manager is configured.
(cherry picked from commit b1aec757ce1e3800b629f36d4fbc274a48698412)
Co-authored-by: Pierre Jeambrun <[email protected]>
---
.../api_fastapi/core_api/routes/public/auth.py | 9 ++++----
.../core_api/routes/public/test_auth.py | 24 ++++++++++++++++++++++
2 files changed, 29 insertions(+), 4 deletions(-)
diff --git
a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/auth.py
b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/auth.py
index f85bcec3a61..6cf7529982c 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/auth.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/auth.py
@@ -57,14 +57,15 @@ def login(request: Request, auth_manager: AuthManagerDep,
next: None | str = Non
)
def logout(request: Request, auth_manager: AuthManagerDep) -> RedirectResponse:
"""Logout the user."""
+ # Revoke the current token before any redirect or cookie deletion so the
JWT
+ # is invalidated even when the auth manager redirects to an external
logout URL.
+ if token_str := request.cookies.get(COOKIE_NAME_JWT_TOKEN):
+ auth_manager.revoke_token(token_str)
+
logout_url = auth_manager.get_url_logout()
if logout_url:
return RedirectResponse(logout_url)
- # Revoke the current token before deleting the cookie
- if token_str := request.cookies.get(COOKIE_NAME_JWT_TOKEN):
- auth_manager.revoke_token(token_str)
-
secure = request.base_url.scheme == "https" or bool(conf.get("api",
"ssl_cert", fallback=""))
cookie_path = get_cookie_path()
response = RedirectResponse(auth_manager.get_url_login())
diff --git
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_auth.py
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_auth.py
index ca0c87acd86..0379640f887 100644
--- a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_auth.py
+++ b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_auth.py
@@ -220,3 +220,27 @@ class TestLogoutTokenRevocation:
assert response.status_code == 307
assert RevokedToken.is_revoked("nonexistent-jti") is False
+
+ def test_logout_revokes_token_when_logout_url_redirects(self,
logout_client):
+ """Token must be revoked before the redirect when get_url_logout
returns a URL."""
+ now = int(time.time())
+ auth_manager = logout_client.app.state.auth_manager
+ signer = auth_manager._get_token_signer()
+ token_payload = {
+ "sub": "admin",
+ "jti": "test-jti-redirect-456",
+ "exp": now + 3600,
+ "iat": now,
+ "nbf": now,
+ "aud": "apache-airflow",
+ "iss": signer.issuer,
+ }
+ token_str = jwt.encode(token_payload, signer._secret_key,
algorithm=signer.algorithm)
+
+ logout_client.cookies.set(COOKIE_NAME_JWT_TOKEN, token_str)
+ with patch.object(auth_manager, "get_url_logout",
return_value="http://external/logout"):
+ response = logout_client.get("/auth/logout",
follow_redirects=False)
+
+ assert response.status_code == 307
+ assert response.headers["location"] == "http://external/logout"
+ assert RevokedToken.is_revoked("test-jti-redirect-456") is True