From 516755db97acd4aa37ad054e8f7056e38da4d59c Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sat, 15 Mar 2025 22:36:58 +0100 Subject: [PATCH] refactor(frontend): Do not request token in frontend (#9217) * remove calls that reference tokens * remove call to token endpoint * ensure CSRFToken is always send * bump axios * lower axios * reset axios change * bump reslution down --- src/frontend/src/App.tsx | 11 +++---- src/frontend/src/functions/auth.tsx | 11 +++---- src/frontend/src/states/UserState.tsx | 42 +++++++++++++-------------- 3 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index 739414cf9f..da346b7bf0 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -2,7 +2,6 @@ import { QueryClient } from '@tanstack/react-query'; import axios from 'axios'; import { useLocalState } from './states/LocalState'; -import { useUserState } from './states/UserState'; // Global API instance export const api = axios.create({}); @@ -12,7 +11,6 @@ export const api = axios.create({}); */ export function setApiDefaults() { const { host } = useLocalState.getState(); - const { token } = useUserState.getState(); api.defaults.baseURL = host; api.defaults.timeout = 5000; @@ -22,11 +20,10 @@ export function setApiDefaults() { api.defaults.xsrfCookieName = 'csrftoken'; api.defaults.xsrfHeaderName = 'X-CSRFToken'; - if (token) { - api.defaults.headers.Authorization = `Token ${token}`; - } else { - delete api.defaults.headers['Authorization']; - } + axios.defaults.withCredentials = true; + axios.defaults.withXSRFToken = true; + axios.defaults.xsrfHeaderName = 'X-CSRFToken'; + axios.defaults.xsrfCookieName = 'csrftoken'; } export const queryClient = new QueryClient({ diff --git a/src/frontend/src/functions/auth.tsx b/src/frontend/src/functions/auth.tsx index f475e33552..ec423fecce 100644 --- a/src/frontend/src/functions/auth.tsx +++ b/src/frontend/src/functions/auth.tsx @@ -66,7 +66,8 @@ export const doBasicLogin = async ( navigate: NavigateFunction ) => { const { host } = useLocalState.getState(); - const { clearUserState, setToken, fetchUserState } = useUserState.getState(); + const { clearUserState, setAuthenticated, fetchUserState } = + useUserState.getState(); const { setAuthContext } = useServerApiState.getState(); if (username.length == 0 || password.length == 0) { @@ -94,7 +95,7 @@ export const doBasicLogin = async ( .then((response) => { setAuthContext(response.data?.data); if (response.status == 200 && response.data?.meta?.is_authenticated) { - setToken(response.data.meta.access_token); + setAuthenticated(true); loginDone = true; success = true; } @@ -217,7 +218,7 @@ function observeProfile() { export async function ensureCsrf() { const cookie = getCsrfCookie(); if (cookie == undefined) { - await api.get(apiUrl(ApiEndpoints.user_token)).catch(() => {}); + await api.get(apiUrl(ApiEndpoints.auth_session)).catch(() => {}); } } @@ -251,7 +252,7 @@ export function handleMfaLogin( values: { code: string }, setError: (message: string | undefined) => void ) { - const { setToken, fetchUserState } = useUserState.getState(); + const { setAuthenticated, fetchUserState } = useUserState.getState(); const { setAuthContext } = useServerApiState.getState(); authApi(apiUrl(ApiEndpoints.auth_login_2fa), undefined, 'post', { @@ -260,7 +261,7 @@ export function handleMfaLogin( .then((response) => { setError(undefined); setAuthContext(response.data?.data); - setToken(response.data.meta.access_token); + setAuthenticated(); fetchUserState().finally(() => { observeProfile(); diff --git a/src/frontend/src/states/UserState.tsx b/src/frontend/src/states/UserState.tsx index e85cc70147..883e4b4ddc 100644 --- a/src/frontend/src/states/UserState.tsx +++ b/src/frontend/src/states/UserState.tsx @@ -10,14 +10,13 @@ import type { UserProps } from './states'; export interface UserStateProps { user: UserProps | undefined; - token: string | undefined; + is_authed: boolean; userId: () => number | undefined; username: () => string; + setAuthenticated: (authed?: boolean) => void; + fetchUserToken: () => Promise; setUser: (newUser: UserProps | undefined) => void; getUser: () => UserProps | undefined; - setToken: (newToken: string | undefined) => void; - clearToken: () => void; - fetchUserToken: () => void; fetchUserState: () => Promise; clearUserState: () => void; checkUserRole: (role: UserRoles, permission: UserPermissions) => boolean; @@ -33,6 +32,7 @@ export interface UserStateProps { hasChangePermission: (model: ModelType) => boolean; hasAddPermission: (model: ModelType) => boolean; hasViewPermission: (model: ModelType) => boolean; + isAuthed: () => boolean; isLoggedIn: () => boolean; isStaff: () => boolean; isSuperuser: () => boolean; @@ -43,13 +43,9 @@ export interface UserStateProps { */ export const useUserState = create((set, get) => ({ user: undefined, - token: undefined, - setToken: (newToken: string | undefined) => { - set({ token: newToken }); - setApiDefaults(); - }, - clearToken: () => { - get().setToken(undefined); + is_authed: false, + setAuthenticated: (authed = true) => { + set({ is_authed: authed }); setApiDefaults(); }, userId: () => { @@ -68,8 +64,7 @@ export const useUserState = create((set, get) => ({ setUser: (newUser: UserProps | undefined) => set({ user: newUser }), getUser: () => get().user, clearUserState: () => { - get().setUser(undefined); - get().setToken(undefined); + set({ user: undefined, is_authed: false }); clearCsrfCookie(); setApiDefaults(); }, @@ -79,30 +74,30 @@ export const useUserState = create((set, get) => ({ !document.cookie.includes('csrftoken') && !document.cookie.includes('sessionid') ) { - get().clearToken(); + get().setAuthenticated(false); return; } await api - .get(apiUrl(ApiEndpoints.user_token)) + .get(apiUrl(ApiEndpoints.auth_session)) .then((response) => { - if (response.status == 200 && response.data.token) { - get().setToken(response.data.token); + if (response.status == 200 && response.data.meta.is_authenticated) { + get().setAuthenticated(true); } else { - get().clearToken(); + get().setAuthenticated(false); } }) .catch(() => { - get().clearToken(); + get().setAuthenticated(false); }); }, fetchUserState: async () => { - if (!get().token) { + if (!get().isAuthed()) { await get().fetchUserToken(); } // If we still don't have a token, clear the user state and return - if (!get().token) { + if (!get().isAuthed()) { get().clearUserState(); return; } @@ -161,8 +156,11 @@ export const useUserState = create((set, get) => ({ get().clearUserState(); }); }, + isAuthed: () => { + return get().is_authed; + }, isLoggedIn: () => { - if (!get().token) { + if (!get().isAuthed()) { return false; } const user: UserProps = get().user as UserProps;