diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index cdf6dfee..1097658b 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -5,8 +5,8 @@ import Header from '@/shared/components/header/Header';
import FooterWrapper from '@/shared/components/footer/FooterWrapper';
import ScrollTopBtnWrapper from '@/shared/components/scroll-top/ScrollTopBtnWrapper';
import KaKaoScript from './api/kakao/KaKaoScript';
-import IdleHandler from '@/domains/login/components/IdleHandler';
import Provider from '@/shared/api/Provider';
+import ClientInitHook from '@/domains/login/components/ClientInitHook';
export const metadata: Metadata = {
title: { default: 'SSOUL', template: 'SSOUL | %s' },
@@ -24,7 +24,7 @@ export default function RootLayout({
-
+
{children}
diff --git a/src/domains/login/components/ClientInitHook.tsx b/src/domains/login/components/ClientInitHook.tsx
new file mode 100644
index 00000000..a73a7ba9
--- /dev/null
+++ b/src/domains/login/components/ClientInitHook.tsx
@@ -0,0 +1,11 @@
+'use client';
+
+import { useFetchInterceptor } from '@/shared/hook/useFetchInterceptor';
+import { useIdleLogout } from '../hook/useIdleLogout';
+
+function ClientInitHook() {
+ useIdleLogout();
+ useFetchInterceptor();
+ return null;
+}
+export default ClientInitHook;
diff --git a/src/domains/login/components/IdleHandler.tsx b/src/domains/login/components/IdleHandler.tsx
deleted file mode 100644
index 4edbf6c8..00000000
--- a/src/domains/login/components/IdleHandler.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-'use client';
-
-import { useIdleLogout } from '../hook/useIdleLogout';
-
-function IdleHandler() {
- useIdleLogout();
- return null;
-}
-export default IdleHandler;
diff --git a/src/domains/recipe/components/main/Cocktails.tsx b/src/domains/recipe/components/main/Cocktails.tsx
index c33933e7..4d075d04 100644
--- a/src/domains/recipe/components/main/Cocktails.tsx
+++ b/src/domains/recipe/components/main/Cocktails.tsx
@@ -10,7 +10,6 @@ import CocktailSearchBar from './CocktailSearchBar';
import useSearchControl from '../../hook/useSearchControl';
import CocktailSearch from '../../api/CocktailSearch';
-
function Cocktails() {
const [data, setData] = useState([]);
const [lastId, setLastId] = useState(null);
diff --git a/src/shared/hook/useFetchInterceptor.tsx b/src/shared/hook/useFetchInterceptor.tsx
new file mode 100644
index 00000000..3d8df3ac
--- /dev/null
+++ b/src/shared/hook/useFetchInterceptor.tsx
@@ -0,0 +1,43 @@
+'use client';
+
+import { useEffect } from 'react';
+import { getApi } from '@/app/api/config/appConfig';
+import { useRouter } from 'next/navigation';
+import { useToast } from '@/shared/hook/useToast';
+
+export const useFetchInterceptor = () => {
+ const router = useRouter();
+ const { toastInfo } = useToast();
+
+ useEffect(() => {
+ const originalFetch = global.fetch;
+
+ (global.fetch as typeof global.fetch) = async (input, init?) => {
+ const response = await originalFetch(input, { ...init, credentials: 'include' });
+
+ if (response.status === 401) {
+ try {
+ const refreshRes = await originalFetch(`${getApi}/user/auth/refresh`, {
+ method: 'POST',
+ credentials: 'include',
+ });
+
+ if (refreshRes.ok) {
+ return originalFetch(input, { ...init, credentials: 'include' });
+ } else {
+ toastInfo('로그인 인증 만료로 다시 로그인해주세요.');
+ router.push('/login');
+ }
+ } catch {
+ toastInfo('로그인 인증 만료로 다시 로그인해주세요.');
+ router.push('/login');
+ }
+ }
+ return response;
+ };
+
+ return () => {
+ global.fetch = originalFetch;
+ };
+ }, [router, toastInfo]);
+};