JWT 인증과 토큰 재발급
작성일 : 2025.01.02
시작: Fetch 함수 분리
처음에는 기능별로 분리하여 구현했습니다:
- 기본 Fetch 함수
export const Fetch = async (input: RequestInfo | URL, init?: RequestInit) => {
return fetch(input, init);
};
- 쿠키를 처리하는 FetchWithCookie
export const FetchWithCookie = async (
input: RequestInfo | URL,
init?: RequestInit
) => {
if (process.env.NODE_ENV === 'production' && isServer) {
try {
const cookies = await getServerCookies();
const cookieString = cookies().toString();
return Fetch(input, {
...init,
headers: {
...init?.headers,
'Content-Type': 'application/json',
Cookie: cookieString,
},
credentials: 'include',
});
} catch (error) {
console.error('Failed to get server cookies:', error);
return Fetch(input, {
...init,
credentials: 'include',
});
}
}
return Fetch(input, {
...init,
credentials: 'include',
});
};
- JWT 토큰 처리를 하는 FetchWithJWT
export const FetchWithJWT = async (
input: RequestInfo | URL,
init?: RequestInit
) => {
const res = await FetchWithCookie(input, init);
if (res.status === 401) {
const tokensRequest = await fetch('api/reissue', init);
if (!tokensRequest.ok) return redirect('/login');
if (process.env.NODE_ENV === 'production' && isServer) {
const cookies = await getServerCookies();
const newCookies = tokensRequest.headers.getSetCookie();
newCookies.forEach((cookie) => {
const [name, value] = cookie.split('=');
cookies().set(name, value);
});
}
return FetchWithCookie(input, init);
} else {
return res;
}
};
문제점 발견
코드를 리뷰하면서 다음과 같은 문제점을 발견했습니다:
FetchWithCookie는 사실상FetchWithJWT안에서만 사용되는 중간 단계의 함수FetchWithJWT가FetchWithCookie의 기능을 포함하여 처리할 수 있음- 불필요한 함수 분리로 인한 코드 복잡도 증가
결론
FetchWithCookie함수는 불필요한 중간 단계였음- 쿠키 처리와 토큰 재발급 모두
FetchWithJWT에서 한번에 처리 가능 - 결국
FetchWithJWT만 사용하면 되는 상황
실제 사용 예시
// API 호출 시
const response = await FetchWithJWT('/recommend', {
next: { revalidate: 1200 },
});
if (response.ok) {
const data = await response.json();
// 데이터 처리
}
이렇게 구현하면 JWT 인증이 필요한 모든 API 요청에서:
- 쿠키에 저장된 JWT 토큰을 포함하여 요청
- 토큰 만료 시(401 에러) 자동으로 재발급
- 재발급 실패 시 로그인 페이지로 리다이렉트
- 프로덕션 환경에서의 서버사이드 쿠키 처리
모든 과정이 FetchWithJWT 하나로 처리됩니다.