This is an automated email from the ASF dual-hosted git repository. ephraimanierobi pushed a commit to branch v3-1-test in repository https://gitbox.apache.org/repos/asf/airflow.git
commit a67604716d7e933cfae65377e0dbdcbec4be05f2 Author: Pierre Jeambrun <[email protected]> AuthorDate: Tue Oct 21 14:47:06 2025 +0200 Fix refresh token middleware error handling (#56892) (cherry picked from commit d7174df9b813996a6e21c49707a626e51bdb98ce) --- .../api_fastapi/auth/middlewares/refresh_token.py | 38 ++++++++++++---------- .../auth/middlewares/test_refresh_token.py | 14 ++++++++ 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/airflow-core/src/airflow/api_fastapi/auth/middlewares/refresh_token.py b/airflow-core/src/airflow/api_fastapi/auth/middlewares/refresh_token.py index 81ed8448734..5705d14ba99 100644 --- a/airflow-core/src/airflow/api_fastapi/auth/middlewares/refresh_token.py +++ b/airflow-core/src/airflow/api_fastapi/auth/middlewares/refresh_token.py @@ -18,6 +18,7 @@ from __future__ import annotations from fastapi import HTTPException, Request +from fastapi.responses import JSONResponse from starlette.middleware.base import BaseHTTPMiddleware from airflow.api_fastapi.app import get_auth_manager @@ -41,25 +42,28 @@ class JWTRefreshMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): new_user = None current_token = request.cookies.get(COOKIE_NAME_JWT_TOKEN) - if current_token: - new_user = await self._refresh_user(current_token) - if new_user: - request.state.user = new_user - - response = await call_next(request) + try: + if current_token: + new_user = await self._refresh_user(current_token) + if new_user: + request.state.user = new_user - if new_user: - # If we created a new user, serialize it and set it as a cookie - new_token = get_auth_manager().generate_jwt(new_user) - secure = bool(conf.get("api", "ssl_cert", fallback="")) - response.set_cookie( - COOKIE_NAME_JWT_TOKEN, - new_token, - httponly=True, - secure=secure, - samesite="lax", - ) + response = await call_next(request) + if new_user: + # If we created a new user, serialize it and set it as a cookie + new_token = get_auth_manager().generate_jwt(new_user) + secure = bool(conf.get("api", "ssl_cert", fallback="")) + response.set_cookie( + COOKIE_NAME_JWT_TOKEN, + new_token, + httponly=True, + secure=secure, + samesite="lax", + ) + except HTTPException as exc: + # If any HTTPException is raised during user resolution or refresh, return it as response + return JSONResponse(status_code=exc.status_code, content={"detail": exc.detail}) return response @staticmethod diff --git a/airflow-core/tests/unit/api_fastapi/auth/middlewares/test_refresh_token.py b/airflow-core/tests/unit/api_fastapi/auth/middlewares/test_refresh_token.py index e87b7c3fd2f..834f864e409 100644 --- a/airflow-core/tests/unit/api_fastapi/auth/middlewares/test_refresh_token.py +++ b/airflow-core/tests/unit/api_fastapi/auth/middlewares/test_refresh_token.py @@ -53,6 +53,20 @@ class TestJWTRefreshMiddleware: call_next.assert_called_once_with(mock_request) mock_refresh_user.assert_not_called() + @patch.object( + JWTRefreshMiddleware, + "_refresh_user", + side_effect=HTTPException(status_code=403, detail="Invalid JWT token"), + ) + @pytest.mark.asyncio + async def test_dispatch_invalid_token(self, mock_refresh_user, middleware, mock_request): + mock_request.cookies = {COOKIE_NAME_JWT_TOKEN: "valid_token"} + call_next = AsyncMock(return_value=Response()) + + response = await middleware.dispatch(mock_request, call_next) + assert response.status_code == 403 + assert response.body == b'{"detail":"Invalid JWT token"}' + @patch("airflow.api_fastapi.auth.middlewares.refresh_token.get_auth_manager") @patch("airflow.api_fastapi.auth.middlewares.refresh_token.resolve_user_from_token") @pytest.mark.asyncio
