Next.js 인증 상태 유지 전략 완전정복 – JWT, 쿠키, 리프레시 토큰, 자동 로그아웃까지 실전 가이드
Next.js 앱에서 사용자 인증 상태 유지 전략 – 로그인 세션, 토큰 관리, 자동 로그아웃까지 완전 정복
Next.js 기반의 웹 서비스에서 로그인 이후 인증 상태를 어떻게 유지할 것인가는 서비스 안정성과 보안, 사용자 경험을 결정짓는 핵심 요소입니다.
로그인을 했는데 새로고침 시 로그아웃되거나, 브라우저를 닫았다 다시 켜면 상태가 초기화되는 문제를 겪어보셨다면 인증 상태 유지 전략이 제대로 구현되지 않은 것입니다.
이번 글에서는 실전 프로젝트에 바로 활용 가능한 인증 상태 관리 전략을 다음 구조로 정리합니다:
- ✅ 인증 토큰(JWT)의 저장 위치 결정
- ✅ 로그인 후 상태 유지 구조 (쿠키, 로컬스토리지)
- ✅ 클라이언트/서버 인증 동기화
- ✅ 자동 로그아웃, 토큰 만료 처리
- ✅ 보안 강화를 위한 실전 설계 팁
1. 🔐 인증 상태란 무엇인가?
✅ 정의
사용자가 로그인한 뒤, 페이지를 이동하거나 새로고침을 하더라도 로그인 상태가 유지되는 것을 의미합니다.
📦 인증 상태 구성 요소
- 토큰: JWT 또는 세션 ID
- 저장소: localStorage, sessionStorage, cookie
- 사용자 정보: userId, email, role 등
- 상태 관리: Zustand, Context, Redux 등
2. 🧾 인증 토큰 저장 위치 – localStorage vs Cookie
✅ 비교표
구분 | localStorage | cookie |
---|---|---|
접근 범위 | 클라이언트 전용 | 서버/클라이언트 모두 |
자동 전송 | ❌ | ⭕ (httpOnly 쿠키) |
XSS 보안 | ❌ 취약 | ⭕ httpOnly로 보호 가능 |
사용 편의성 | ⭕ 간단함 | △ 쿠키 파싱 필요 |
✅ 권장 전략
- 보안 중심:
httpOnly 쿠키 + 서버 인증
- 간단한 프로젝트:
localStorage + 클라이언트 상태 관리
3. 📦 로그인 후 인증 상태 유지 구조
✅ localStorage 방식
// 로그인 시 토큰 저장
localStorage.setItem('accessToken', token);
✅ Zustand 예시
// store/authStore.ts
import { create } from 'zustand';
export const useAuthStore = create((set) => ({
user: null,
setUser: (user) => set({ user }),
logout: () => set({ user: null }),
}));
📌 로그인 후 상태 초기화
useEffect(() => {
const token = localStorage.getItem('accessToken');
if (token) {
fetch('/api/me', {
headers: { Authorization: `Bearer ${token}` },
}).then(res => res.json()).then(data => {
setUser(data);
});
}
}, []);
➡️ 새로고침 시에도 localStorage에 저장된 토큰을 기준으로 사용자 정보를 다시 불러와 상태를 유지합니다.
4. 🍪 쿠키 기반 인증 상태 유지 전략
✅ 쿠키로 인증 토큰 저장하기
쿠키는 서버에서도 접근할 수 있고, httpOnly
속성을 부여하면 클라이언트 JavaScript에서 접근할 수 없어 XSS 공격에 강한 보안 환경을 제공합니다.
📦 로그인 응답에서 쿠키 설정
// /api/login.ts
import { cookies } from 'next/headers';
export async function POST(req: Request) {
const { email, password } = await req.json();
const token = await authenticate(email, password);
cookies().set('access_token', token, {
httpOnly: true,
maxAge: 3600,
path: '/',
});
return new Response(JSON.stringify({ success: true }));
}
📦 클라이언트에서 토큰 접근 안됨
// localStorage나 getCookie로 접근 ❌
// 반드시 서버사이드에서 쿠키를 읽어야 함
5. 🖥️ SSR 환경에서 인증 상태 유지
✅ getServerSideProps 활용
export async function getServerSideProps(context) {
const { req } = context;
const token = req.cookies['access_token'];
if (!token) {
return {
redirect: {
destination: '/login',
permanent: false,
},
};
}
const user = await verifyToken(token);
return {
props: { user },
};
}
➡️ SSR에서는 클라이언트 상태와 무관하게 서버에서 쿠키를 읽어 인증 상태를 직접 판별할 수 있습니다.
6. ⏳ 자동 로그아웃 구현하기
✅ 왜 필요한가?
- 보안 강화 (PC를 잠깐 비운 사이 세션 유지 방지)
- 토큰 만료 기반 자동 로그아웃 처리
📦 클라이언트 타이머 방식 예시
// 로그인 시 시작
const startAutoLogoutTimer = () => {
setTimeout(() => {
localStorage.removeItem('accessToken');
window.location.href = '/login';
}, 1000 * 60 * 60); // 1시간 후 자동 로그아웃
};
✅ JWT 자체 만료 확인
import jwtDecode from 'jwt-decode';
const token = localStorage.getItem('accessToken');
const decoded = jwtDecode(token);
if (decoded.exp * 1000 < Date.now()) {
localStorage.removeItem('accessToken');
alert('로그인 세션이 만료되었습니다.');
}
➡️ 리프레시 토큰 전략과 함께 적용 시 안정적인 로그인 상태 유지 + 자동 로그아웃 처리가 가능합니다.
7. 🔄 리프레시 토큰 전략 – 긴 세션 유지의 핵심
✅ 리프레시 토큰이란?
Access Token의 유효 시간이 짧을 경우, 사용자가 로그인 상태를 유지하기 위해 보다 긴 만료시간을 가진 Refresh Token을 함께 발급받습니다.
📌 구조 요약
- 🔑 Access Token: 15분 ~ 1시간 (httpOnly 쿠키 or localStorage)
- 🔁 Refresh Token: 7일 이상 (httpOnly + Secure Cookie)
📦 서버에서 토큰 발급 예시
// POST /api/login
cookies().set('access_token', accessToken, { httpOnly: true });
cookies().set('refresh_token', refreshToken, { httpOnly: true, secure: true });
📦 토큰 재발급 흐름
- 1️⃣ access_token 만료 → 401 Unauthorized
- 2️⃣ 클라이언트가 /api/refresh-token 호출
- 3️⃣ 서버가 refresh_token 유효성 확인 후 access_token 재발급
➡️ 이 방식은 보안성과 사용자 경험을 동시에 잡을 수 있습니다.
8. 🚪 인증 리디렉션 UX 설계
✅ 인증이 필요한 페이지 접근 시 UX
// useEffect or SSR에서
if (!user) {
router.replace('/login?redirect=/target-page');
}
📦 로그인 후 원래 페이지로 복귀
const router = useRouter();
const redirectTo = router.query.redirect || '/';
useEffect(() => {
if (loginSuccess) {
router.replace(redirectTo);
}
}, [loginSuccess]);
✅ UX 개선 팁
- 🔁 로그인 후 이전 경로로 복귀
- ⚠️ 비인가 접근 시 "권한 없음" 메시지 제공
- 🔐 로그인 중에는 로딩 스피너 or skeleton UI 제공
9. ✅ 인증 상태 유지 실무 체크리스트
📌 기본 설계 체크
- ✔️ JWT 토큰 사용 여부
- ✔️ 저장소: localStorage vs cookie 결정
- ✔️ 사용자 상태 전역 관리 방식 (Zustand 등)
📌 보안 체크
- ✔️ httpOnly + Secure 쿠키 적용
- ✔️ 토큰 만료 및 재발급 처리
- ✔️ XSS/CSRF 방지 고려
📌 UX 체크
- ✔️ 로그인 유지, 자동 로그아웃 흐름 구현
- ✔️ 로그인 후 리디렉션 UX
- ✔️ 사용자 정보 캐싱 전략 검토
긴 글 읽어주셔서 감사합니다! 공감, 댓글, 공유는 다음 글 제작에 큰 힘이 됩니다 🙌