From fbecc95c8984e36f93316bae18610195902fd2f1 Mon Sep 17 00:00:00 2001 From: xet-a Date: Sun, 25 Aug 2024 12:00:44 +0900 Subject: [PATCH] Update Axios interceptor to handle token expiration and refresh logic --- frontend/src/App.tsx | 78 ++++++++++++---------- frontend/src/pages/auth/callback/Index.tsx | 1 - frontend/src/store/authSlice.ts | 10 +-- 3 files changed, 47 insertions(+), 42 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 59448186..a6abd200 100755 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -52,42 +52,6 @@ if (import.meta.env.PROD) { const router = createBrowserRouter(routes); -axios.interceptors.response.use( - res => { - console.log("inspector test: " + res.data.json); - return res; - }, - async error => { - const state = store.getState(); - const dispatch = useDispatch(); - const originalRequest = error.config; - - if (error.response.status === 401 && !originalRequest._retry) { - originalRequest._retry = true; - - const refreshToken = state.auth.refreshToken; - const response = await axios.post('/auth/refresh', { refreshToken }); - - if (response.status === 200) { - const newAccessToken = response.data.accessToken; - dispatch(setAccessToken(newAccessToken)); - - axios.defaults.headers.common['Authorization'] = `Bearer ${newAccessToken}`; - originalRequest.headers['Authorization'] = `Bearer ${newAccessToken}`; - - return axios(originalRequest); - } else { - dispatch(setAccessToken(null)); - dispatch(setRefreshToken(null)); - dispatch(setUserData(null)); - } - } - - return Promise.reject(error); - } -); - - axios.defaults.baseURL = import.meta.env.VITE_API_ADDR; function SettingLoader() { @@ -97,6 +61,7 @@ function SettingLoader() { function App() { const config = useSelector(selectConfig); + const dispatch = useDispatch(); const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)"); const theme = useMemo(() => { const defaultMode = prefersDarkMode ? "dark" : "light"; @@ -134,6 +99,47 @@ function App() { }); }, [handleError]); + useEffect(() => { + const handleRefreshTokenExpiration = () => { + dispatch(setAccessToken(null)); + dispatch(setRefreshToken(null)); + dispatch(setUserData(null)); + // axios.defaults.headers.common["Authorization"] = ""; + }; + + const interceptor = axios.interceptors.response.use( + (response) => response, + async (error) => { + if (error.response?.status === 401) { + if (error.config.url === "/auth/refresh") { + handleRefreshTokenExpiration(); + return Promise.reject(error); + } else if (!error.config._retry) { + error.config._retry = true; + const refreshToken = store.getState().auth.refreshToken; + try { + const response = await axios.post("/auth/refresh", { refreshToken }); + const newAccessToken = response.data.accessToken; + dispatch(setAccessToken(newAccessToken)); + axios.defaults.headers.common["Authorization"] = + `Bearer ${newAccessToken}`; + error.config.headers["Authorization"] = `Bearer ${newAccessToken}`; + return axios(error.config); + } catch (refreshError) { + handleRefreshTokenExpiration(); + return Promise.reject(refreshError); + } + } + } + return Promise.reject(error); + } + ); + + return () => { + axios.interceptors.response.eject(interceptor); + }; + }, [dispatch]); + return ( diff --git a/frontend/src/pages/auth/callback/Index.tsx b/frontend/src/pages/auth/callback/Index.tsx index d1c338eb..1f7dd193 100644 --- a/frontend/src/pages/auth/callback/Index.tsx +++ b/frontend/src/pages/auth/callback/Index.tsx @@ -20,7 +20,6 @@ function CallbackIndex() { dispatch(setAccessToken(accessToken)); dispatch(setRefreshToken(refreshToken)); - }, [dispatch, navigate, searchParams]); return ; diff --git a/frontend/src/store/authSlice.ts b/frontend/src/store/authSlice.ts index 7e0d0cea..5d3c4cda 100644 --- a/frontend/src/store/authSlice.ts +++ b/frontend/src/store/authSlice.ts @@ -4,12 +4,12 @@ import { RootState } from "./store"; export interface AuthState { accessToken: string | null; - refreshToken: string | null; + refreshToken: string | null; } const initialState: AuthState = { accessToken: null, - refreshToken: null, + refreshToken: null, }; export const authSlice = createSlice({ @@ -19,9 +19,9 @@ export const authSlice = createSlice({ setAccessToken: (state, action: PayloadAction) => { state.accessToken = action.payload; }, - setRefreshToken(state, action: PayloadAction) { - state.refreshToken = action.payload; - }, + setRefreshToken(state, action: PayloadAction) { + state.refreshToken = action.payload; + }, }, });