Skip to content

Commit b8af111

Browse files
authored
Update authentication to handle JWT token in backend (#56633)
1 parent 85b5082 commit b8af111

19 files changed

Lines changed: 94 additions & 204 deletions

File tree

airflow-core/docs/core-concepts/auth-manager/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ cookie named ``_token`` before redirecting to the Airflow UI. The Airflow UI wil
166166
response = RedirectResponse(url="/")
167167
168168
secure = request.base_url.scheme == "https" or bool(conf.get("api", "ssl_cert", fallback=""))
169-
response.set_cookie(COOKIE_NAME_JWT_TOKEN, token, secure=secure)
169+
response.set_cookie(COOKIE_NAME_JWT_TOKEN, token, secure=secure, httponly=True)
170170
return response
171171
172172
.. note::

airflow-core/src/airflow/api_fastapi/app.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
init_config,
3030
init_error_handlers,
3131
init_flask_plugins,
32-
init_middlewares,
3332
init_ui_plugins,
3433
init_views,
3534
)
@@ -100,7 +99,6 @@ def create_app(apps: str = "all") -> FastAPI:
10099
init_ui_plugins(app)
101100
init_views(app) # Core views need to be the last routes added - it has a catch all route
102101
init_error_handlers(app)
103-
init_middlewares(app)
104102

105103
init_config(app)
106104

airflow-core/src/airflow/api_fastapi/auth/managers/simple/routes/login.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ def login_all_admins(request: Request) -> RedirectResponse:
9494
COOKIE_NAME_JWT_TOKEN,
9595
SimpleAuthManagerLogin.create_token_all_admins(),
9696
secure=secure,
97+
httponly=True,
9798
)
9899
return response
99100

airflow-core/src/airflow/api_fastapi/core_api/app.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -181,17 +181,6 @@ def init_error_handlers(app: FastAPI) -> None:
181181
app.add_exception_handler(handler.exception_cls, handler.exception_handler)
182182

183183

184-
def init_middlewares(app: FastAPI) -> None:
185-
from airflow.configuration import conf
186-
187-
if "SimpleAuthManager" in conf.get("core", "auth_manager") and conf.getboolean(
188-
"core", "simple_auth_manager_all_admins"
189-
):
190-
from airflow.api_fastapi.auth.managers.simple.middleware import SimpleAllAdminMiddleware
191-
192-
app.add_middleware(SimpleAllAdminMiddleware)
193-
194-
195184
def init_ui_plugins(app: FastAPI) -> None:
196185
"""Initialize UI plugins."""
197186
from airflow import plugins_manager

airflow-core/src/airflow/api_fastapi/core_api/security.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from pydantic import NonNegativeInt
2828

2929
from airflow.api_fastapi.app import get_auth_manager
30+
from airflow.api_fastapi.auth.managers.base_auth_manager import COOKIE_NAME_JWT_TOKEN
3031
from airflow.api_fastapi.auth.managers.models.base_user import BaseUser
3132
from airflow.api_fastapi.auth.managers.models.batch_apis import (
3233
IsAuthorizedConnectionRequest,
@@ -103,14 +104,22 @@ async def resolve_user_from_token(token_str: str | None) -> BaseUser:
103104

104105

105106
async def get_user(
107+
request: Request,
106108
oauth_token: str | None = Depends(oauth2_scheme),
107109
bearer_credentials: HTTPAuthorizationCredentials | None = Depends(bearer_scheme),
108110
) -> BaseUser:
109-
token_str = None
111+
# A user might have been already built by a middleware, if so, it is stored in `request.state.user`
112+
user: BaseUser | None = getattr(request.state, "user", None)
113+
if user:
114+
return user
115+
116+
token_str: str | None
110117
if bearer_credentials and bearer_credentials.scheme.lower() == "bearer":
111118
token_str = bearer_credentials.credentials
112119
elif oauth_token:
113120
token_str = oauth_token
121+
else:
122+
token_str = request.cookies.get(COOKIE_NAME_JWT_TOKEN)
114123

115124
return await resolve_user_from_token(token_str)
116125

airflow-core/src/airflow/ui/src/layouts/Nav/LogoutModal.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import { useTranslation } from "react-i18next";
2222

2323
import { ConfirmationModal } from "src/components/ConfirmationModal";
2424
import { getRedirectPath } from "src/utils/links.ts";
25-
import { TOKEN_STORAGE_KEY } from "src/utils/tokenHandler";
2625

2726
type LogoutModalProps = {
2827
readonly isOpen: boolean;
@@ -38,7 +37,7 @@ const LogoutModal: React.FC<LogoutModalProps> = ({ isOpen, onClose }) => {
3837
onConfirm={() => {
3938
const logoutPath = getRedirectPath("api/v2/auth/logout");
4039

41-
localStorage.removeItem(TOKEN_STORAGE_KEY);
40+
document.cookie = "_token=; Path=/; Max-Age=-99999999;";
4241
globalThis.location.replace(logoutPath);
4342
}}
4443
onOpenChange={onClose}

airflow-core/src/airflow/ui/src/main.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ import { getRedirectPath } from "src/utils/links.ts";
3737
import i18n from "./i18n/config";
3838
import { client } from "./queryClient";
3939
import { system } from "./theme";
40-
import { clearToken, tokenHandler } from "./utils/tokenHandler";
4140

4241
// Set React, ReactDOM, and ReactJSXRuntime on globalThis to share them with the dynamically imported React plugins.
4342
// Only one instance of React should be used.
@@ -55,7 +54,6 @@ axios.interceptors.response.use(
5554
error.response?.status === 401 ||
5655
(error.response?.status === 403 && error.response.data.detail === "Invalid JWT token")
5756
) {
58-
clearToken();
5957
const params = new URLSearchParams();
6058

6159
params.set("next", globalThis.location.href);
@@ -68,8 +66,6 @@ axios.interceptors.response.use(
6866
},
6967
);
7068

71-
axios.interceptors.request.use(tokenHandler);
72-
7369
createRoot(document.querySelector("#root") as HTMLDivElement).render(
7470
<StrictMode>
7571
<I18nextProvider i18n={i18n}>

airflow-core/src/airflow/ui/src/utils/tokenHandler.test.ts

Lines changed: 0 additions & 54 deletions
This file was deleted.

airflow-core/src/airflow/ui/src/utils/tokenHandler.ts

Lines changed: 0 additions & 51 deletions
This file was deleted.

airflow-core/tests/unit/api_fastapi/auth/managers/simple/test_middleware.py

Lines changed: 0 additions & 62 deletions
This file was deleted.

0 commit comments

Comments
 (0)