diff --git a/src/api/core/index.ts b/src/api/core/index.ts index 39f33383..d785b493 100644 --- a/src/api/core/index.ts +++ b/src/api/core/index.ts @@ -50,10 +50,18 @@ baseAPI.interceptors.response.use( const isServer = typeof window === 'undefined'; const originalRequest = error.config; + // skipAuthRedirect flag가 지정되어있지 않으면 항상 redirect 되도록 + if (originalRequest.skipAuthRedirect === undefined) { + originalRequest.skipAuthRedirect = true; + } + if (status === 401 && !originalRequest._retry) { originalRequest._retry = true; try { - await API.authService.refresh(originalRequest.skipAuthRedirect); + // refresh - set cookie는 클라이언트 요청만 동작함 + if (!isServer) { + await API.authService.refresh(originalRequest.skipAuthRedirect); + } return baseAPI(originalRequest); } catch (refreshError) { if (!originalRequest.skipAuthRedirect) throw refreshError; diff --git a/src/app/(user)/profile/[userId]/page.test.tsx b/src/app/(user)/profile/[userId]/page.test.tsx index 6fc09d06..8619a5cd 100644 --- a/src/app/(user)/profile/[userId]/page.test.tsx +++ b/src/app/(user)/profile/[userId]/page.test.tsx @@ -6,6 +6,7 @@ import { formatISO } from '@/lib/formatDateTime'; import { server } from '@/mock/server'; import { createMockSuccessResponse } from '@/mock/service/common/common-mock'; import { mockUserItems } from '@/mock/service/user/user-mock'; +import { AuthProvider } from '@/providers'; import ProfilePage from './page'; @@ -33,7 +34,9 @@ const renderWithQueryClient = async (component: React.ReactElement) => { let renderResult; await act(async () => { renderResult = render( - {component}, + + {component} + , ); }); diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 420ca106..2009a22b 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -16,15 +16,19 @@ export const metadata: Metadata = { initMocks(); -export default function RootLayout({ +export default async function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { + const { cookies } = await import('next/headers'); + const cookieStore = await cookies(); + const hasRefreshToken = !!cookieStore.get('refreshToken')?.value; + return ( - +
{children}
diff --git a/src/app/providers.tsx b/src/app/providers.tsx index af070a34..1f7f5e3b 100644 --- a/src/app/providers.tsx +++ b/src/app/providers.tsx @@ -11,13 +11,14 @@ import { interface Props { children: React.ReactNode; + hasRefreshToken: boolean; } -export const Providers = ({ children }: Props) => { +export const Providers = ({ children, hasRefreshToken }: Props) => { return ( - + diff --git a/src/hooks/use-user/use-user-get-me/index.ts b/src/hooks/use-user/use-user-get-me/index.ts index 93bc72e4..37fda0b1 100644 --- a/src/hooks/use-user/use-user-get-me/index.ts +++ b/src/hooks/use-user/use-user-get-me/index.ts @@ -2,6 +2,7 @@ import { useQuery } from '@tanstack/react-query'; import { API } from '@/api'; import { userKeys } from '@/lib/query-key/query-key-user'; +import { useAuth } from '@/providers'; export const useUserGetMe = () => { const query = useQuery({ @@ -18,6 +19,8 @@ export const useUserGetMe = () => { }; export const useUserGetMeSkipRedirect = () => { + const { isAuthenticated } = useAuth(); + const query = useQuery({ queryKey: userKeys.me(), queryFn: () => API.userService.getMeSkipRedirect(), @@ -27,6 +30,8 @@ export const useUserGetMeSkipRedirect = () => { profileMessage: data.profileMessage ?? '', mbti: data.mbti ?? '', }), + retry: false, + enabled: isAuthenticated, }); return query; }; diff --git a/src/providers/provider-auth/index.tsx b/src/providers/provider-auth/index.tsx index b09667d8..b90ec8fe 100644 --- a/src/providers/provider-auth/index.tsx +++ b/src/providers/provider-auth/index.tsx @@ -19,29 +19,30 @@ export const useAuth = () => { interface Props { children: React.ReactNode; + hasRefreshToken: boolean; } -export const AuthProvider = ({ children }: Props) => { +export const AuthProvider = ({ children, hasRefreshToken }: Props) => { const [isAuthenticated, setIsAuthenticated] = useState(false); // 초기값 설정 // 페이지가 새로고침 될 때 accessToken이 없으면 refresh 시도, state update 실행 useEffect(() => { const updateAuthenticated = async () => { - const accessToken = Cookies.get('accessToken'); - if (!accessToken) { + const hasAccessToken = !!Cookies.get('accessToken'); + if (!hasAccessToken && hasRefreshToken) { try { await API.authService.refresh(); setIsAuthenticated(true); } catch { setIsAuthenticated(false); } - } else { + } else if (hasAccessToken) { setIsAuthenticated(true); } }; updateAuthenticated(); - }, []); + }, [hasRefreshToken]); return (