// 저장
sessionStorage.setItem('token', accessToken);
// 조회
sessionStorage.getItem('token');
인증 방식의 종류에는 '세션/쿠키 방식'과 'JWT(JSON Web Token)' 방식이 있습니다.
세션/쿠키 방식: 서버가 세션 정보를 보관하고 관리(서버 부하)
- 사용자 로그인
- 서버가 세션 생성 및 세션 ID 발급
- 세션 ID를 쿠키에 저장해서 클라이언트에 요청마다 쿠키 전달
JWT(JSON Web Token)방식: 서버가 상태를 저장하지 않음(Stateless)
- 사용자 로그인
- 서버가 JWT 토큰 발급(토큰 자체에 필요한 정보가 담겨 있음)
- 클라이언트가 토큰 저장
- 서버는 토큰이 유효한지만 확인
Q. 쿠키, 세션, 토큰은 각각 무엇을 말하는 것인가요?
- 쿠키
- 브라우저에 저장되는 작은 데이터 조각
- 서버가 클라이언트에 보내는 key-value 데이터
- 모든 HTTP 요청에 자동으로 포함됨
- 세션
- 서버에서 유저의 정보를 저장하고 관리
- 클라이언트는 세션ID만 가지고 있음
- 서버 메모리를 사용하므로 서버에 부담
- 토큰
- 정보를 암호화하여 담은 문자열
- 서버가 상태를 저장할 필요 없음
- 클라이언트가 직접 관리
Q. Access token과 Refresh token은 왜 존재하나요?
Access Token: 메모리(Zustand, Context) 저장 권장
- 실제 리소스에 접근할 때 사용하는 토큰
- 짧은 유효기간(보통 30분 ~ 2시간)
- 탈취 위험을 줄이기 위해 짧게 유지
Refresh Token: HttpOnly 쿠키 저장 권장
- Access Token을 재발급 받기 위한 토큰
- 긴 유효기간(보통 2주 ~ 1달)
- Access Token이 만료되었을 때 새로 로그인하지 않고도 갱신 가능
Q. 각 token은 어디에 저장해야 안전한가요?
1. localStorage
// 저장
localStorage.setItem('token', accessToken);
// 사용
const token = localStorage.getItem('token');
특징:
- 브라우저를 닫아도 데이터 유지
- 명시적으로 삭제하기 전까지 영구 보존
- 도메인별로 약 5~10MB 저장 가능
- 다른 탭에서도 데이터 공유
1-1. sessionStorage
// 저장
sessionStorage.setItem('token', accessToken);
// 조회
sessionStorage.getItem('token');
특징:
- 브라우저/탭을 닫으면 데이터 삭제
- 같은 도메인이라도 다른 탭과 데이터 공유 안됨
- 페이지 새로고침해도 데이터 유지
- 도메인별로 약 5~10MB 저장 가능
Storage 선택 기준:
- localStorage: 장기간 보관이 필요한 데이터 (사용자 설정, 테마 등)
- sessionStorage: 임시 데이터나 민감한 정보 (일회성 인증 코드 등)
2. Zustand
const useAuthStore = create((set) => ({
token: null,
setToken: (token) => set({ token }),
}));
- 장점: XSS에 비교적 안전
- 단점: 새로 고침시 초기화
3. Tanstack query
const useAuth = () => {
const { data: token } = useQuery(['auth'], () => null);
const setToken = (newToken) =>
queryClient.setQueryData(['auth'], newToken);
};
- 장점: 캐싱 시스템 활용
- 단점: 새로 고침시 초기화, 과도한 설정
4. HttpOnly 쿠키
Set-Cookie: token=xxx; HttpOnly; Secure
- 장점: 가장 안전(JS 접근 불가)
- 단점: CSRF 공격 가능성
4-1. HttpOnly, Secure 옵션의 의미
A. HttpOnly
- JavaScript로 쿠키 접근 불가능
- document.cookie로 읽기 불가
- XSS 공격 방지
B. Secure
- HTTPS 프로토콜에서만 쿠키 전송
- 암호화된 통신만 허용
- 네트워크 상의 토큰 탈취 방지
지금 제 프로젝트로 보았을 때, Zustand로 토큰을 관리하는게 적절해보입니다.
크게 4가지 이유가 있습니다.
1. 과제의 API 스펙과 매칭
// 로그인 API 응답 형태
{
"accessToken": "eyJhbGci...", // JWT 토큰
"userId": "유저 아이디",
"success": true,
"avatar": "프로필 이미지",
"nickname": "유저 닉네임"
}
- 서버가 토큰을 response body로 전달
- HttpOnly 쿠키 설정을 지원하지 않음
- 따라서 클라이언트에서 직접 토큰 관리가 필요함
2. 요구사항과 적합성
// Zustand store 예시
const useAuthStore = create((set) => ({
token: null,
user: null,
setAuth: (token, user) => set({ token, user }),
logout: () => set({ token: null, user: null })
}));
- 과제에서 요구하는 zustand 상태관리 실습 가능
- 권한별 라우팅 제어를 위한 전역 상태 관리 용이
- 다른 컴포넌트에서도 쉽게 접근 가능
3. 구현의 편의성
// API 호출시 토큰 사용 예시
const { token } = useAuthStore();
const response = await axios.get('/user', {
headers: { Authorization: `Bearer ${token}` }
});
- 간단한 코드로 구현 가능
- Tanstack query와 함께 사용하기 좋음
- 상태 업데이트가 간편함
- 작은 규모의 프로젝트에 적합한 복잡도
- 빠른 개발 가능
'개인과제' 카테고리의 다른 글
프론트엔드 에러 모니터링 Sentry로 서비스 품질 높이기 & vercel 배포 (0) | 2025.01.19 |
---|---|
React 프로젝트 유닛 테스트: 필요성과 실제 구현 경험 (0) | 2025.01.19 |
Riot API를 활용하여 리그 오브 레전드 정보 앱 만들기⭐︎ (5) | 2024.10.08 |
[ Troubleshooting🛠️ ] 리그오브레전드 정보앱: props 오류 (0) | 2024.10.01 |
[ Troubleshooting🛠️ ] 리그오브레전드 정보앱: type 오류 (0) | 2024.10.01 |