diff --git a/gifs/kakao.gif b/gifs/kakao.gif index 79005cd6..1e910d27 100644 Binary files a/gifs/kakao.gif and b/gifs/kakao.gif differ diff --git a/src/app/_components/AuthInitializer.tsx b/src/app/_components/AuthInitializer.tsx index 6aaf306a..4c5c13d9 100644 --- a/src/app/_components/AuthInitializer.tsx +++ b/src/app/_components/AuthInitializer.tsx @@ -1,5 +1,7 @@ 'use client'; +import { useEffect } from 'react'; + import { useUser } from '@/domain/Auth/hooks/useUser'; /** @@ -10,7 +12,12 @@ import { useUser } from '@/domain/Auth/hooks/useUser'; * 이 컴포넌트는 UI를 렌더링하지 않습니다. */ export default function AuthInitializer() { - useUser(); + const { refetch } = useUser(); // 쿼리 객체를 받아서 + + useEffect(() => { + // 앱 로드시 강제로 한번 요청 실행 + refetch(); + }, [refetch]); return null; } diff --git a/src/domain/Auth/hooks/useUser.ts b/src/domain/Auth/hooks/useUser.ts index c57c055d..2656d6ca 100644 --- a/src/domain/Auth/hooks/useUser.ts +++ b/src/domain/Auth/hooks/useUser.ts @@ -57,7 +57,8 @@ export const useUser = () => { queryKey: ['user', 'me'], queryFn: getMe, retry: 1, - staleTime: 1000 * 60 * 5, + refetchOnWindowFocus: true, + refetchOnReconnect: true, }); // 2. useEffect를 사용하여 쿼리 결과에 따른 부가 작업을 처리합니다. diff --git a/src/domain/Auth/utils/setAuthCookies.ts b/src/domain/Auth/utils/setAuthCookies.ts index 943f5834..87c76406 100644 --- a/src/domain/Auth/utils/setAuthCookies.ts +++ b/src/domain/Auth/utils/setAuthCookies.ts @@ -35,9 +35,8 @@ export default function setAuthCookies( sameSite: 'lax', path: '/', - // maxAge: 60 * 60, //! 테스트를 위해 15초로 - maxAge: 10, - + maxAge: 60 * 60, + // maxAge: 10, }); response.cookies.set({ diff --git a/src/middleware.ts b/src/middleware.ts index 882a8196..ff329eed 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -127,6 +127,7 @@ export async function middleware(request: NextRequest) { headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${refreshToken}`, + Cookie: `refreshToken=${refreshToken}`, }, }, ); @@ -147,14 +148,15 @@ export async function middleware(request: NextRequest) { signal: AbortSignal.timeout(30000), }); - return setAuthCookies( - new NextResponse(response.body, { - status: response.status, - statusText: response.statusText, - headers: response.headers, - }), - tokens, - ); + const responseText = await response.text(); + + const finalResponse = new NextResponse(responseText, { + status: response.status, + statusText: response.statusText, + headers: response.headers, + }); + + return setAuthCookies(finalResponse, tokens); } else { console.log('[Middleware] Refresh Token 만료 또는 갱신 실패'); } diff --git a/src/shared/libs/apiClient.ts b/src/shared/libs/apiClient.ts index 598ef31e..1ab7e93a 100644 --- a/src/shared/libs/apiClient.ts +++ b/src/shared/libs/apiClient.ts @@ -33,6 +33,6 @@ export const apiClient = ky.create({ headers: { 'Content-Type': 'application/json', }, - + credentials: 'same-origin', hooks: formatErrorResponseHooks, }); diff --git a/src/shared/libs/formatErrorResponseHooks.ts b/src/shared/libs/formatErrorResponseHooks.ts index ead00af6..56f9b468 100644 --- a/src/shared/libs/formatErrorResponseHooks.ts +++ b/src/shared/libs/formatErrorResponseHooks.ts @@ -14,26 +14,30 @@ const beforeErrorHook = async (error: HTTPError) => { if (response.status === 401) { console.error('클라이언트 측에서 401 에러 감지. 세션이 만료되었습니다.'); - const { clearUser } = useRoamReadyStore.getState(); - clearUser(); + const { user, clearUser } = useRoamReadyStore.getState(); - queryClient.invalidateQueries({ queryKey: ['user', 'me'] }); + if (user) { + console.error('세션 만료 처리 시작'); + clearUser(); + queryClient.invalidateQueries({ queryKey: ['user', 'me'] }); - const currentPathname = window.location.pathname; - const isCurrentlyOnProtectedPage = protectedPageRoutes.some((route) => - currentPathname.startsWith(route), - ); - - if (response.status === 401 && isCurrentlyOnProtectedPage) { - console.error( - '클라이언트 측에서 401 에러 감지. 보호된 페이지에서 세션이 만료되었습니다.', - ); - const redirectUrl = new URL( - ROUTES.ACTIVITIES.ROOT, - window.location.origin, + const currentPathname = window.location.pathname; + const isCurrentlyOnProtectedPage = protectedPageRoutes.some((route) => + currentPathname.startsWith(route), ); - redirectUrl.searchParams.set('error', ERROR_CODES.SESSION_EXPIRED); - window.location.href = redirectUrl.toString(); + + if (isCurrentlyOnProtectedPage) { + const redirectUrl = new URL( + ROUTES.ACTIVITIES.ROOT, + window.location.origin, + ); + redirectUrl.searchParams.set('error', ERROR_CODES.SESSION_EXPIRED); + window.location.href = redirectUrl.toString(); + } else { + window.location.reload(); + } + } else { + console.log('[401] 로그인 안된 상태에서 발생한 요청이므로 무시'); } }