"로그인 유지는 어떻게 되는 거지?" 웹 개발을 처음 배울 때 가졌던 질문입니다. HTTP는 상태가 없는(stateless) 프로토콜인데, 서버가 어떻게 나를 기억할까요?
먼저, 세션 방식 이해하기
JWT를 이해하려면 먼저 전통적인 세션 방식을 알아야 합니다.
- 사용자가 로그인
- 서버가 세션 ID를 생성하고 서버 메모리/DB에 저장
- 세션 ID를 쿠키로 브라우저에 전달
- 이후 요청마다 쿠키가 자동 전송
- 서버가 세션 ID로 사용자 정보 조회
문제점: 서버가 모든 세션을 기억해야 합니다. 서버가 여러 대면? 세션 동기화가 필요하고, 이건 복잡합니다.
JWT: 서버가 기억하지 않아도 되는 방식
JWT(JSON Web Token)는 다른 접근법입니다. 서버가 사용자 정보를 기억하는 대신, 토큰 자체에 정보를 담아서 클라이언트에게 줍니다.
토큰에는 서버의 서명이 포함되어 있어서, 나중에 토큰을 받으면 "이거 내가 만든 게 맞네"라고 확인할 수 있습니다.
JWT의 구조: 점 두 개로 나뉜 세 부분
JWT는 이렇게 생겼습니다:
xxxxx.yyyyy.zzzzz
Header.Payload.Signature
1. Header (헤더)
토큰 타입과 서명 알고리즘 정보. Base64Url로 인코딩됩니다.
{"alg": "HS256", "typ": "JWT"}
2. Payload (페이로드)
실제 정보가 담기는 부분입니다. "클레임(claim)"이라고 불립니다.
{
"sub": "1234567890",
"name": "홍길동",
"admin": true,
"exp": 1706234567
}
⚠️ 중요: 페이로드는 암호화되지 않습니다! 누구나 디코딩해서 볼 수 있어요. 민감한 정보 넣지 마세요.
3. Signature (서명)
헤더 + 페이로드 + 비밀키를 조합해서 만든 서명입니다.
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
이 서명 덕분에 토큰이 변조되면 서버가 알 수 있습니다.
JWT 인증 흐름
- 사용자가 로그인
- 서버가 JWT 생성해서 응답
- 클라이언트가 JWT를 저장 (보통 localStorage나 httpOnly 쿠키)
- 이후 요청마다
Authorization: Bearer {token}헤더로 전송 - 서버가 서명 검증 후 payload 정보 사용
세션 vs JWT
| 세션 | JWT | |
|---|---|---|
| 저장 위치 | 서버 | 클라이언트 |
| 확장성 | 세션 동기화 필요 | 서버 간 공유 불필요 |
| 로그아웃 | 세션 삭제하면 끝 | 토큰 무효화 어려움 |
| 보안 | 서버에서 관리 | 토큰 탈취 시 위험 |
JWT 보안 주의사항
1. 만료 시간(exp) 필수
토큰에 만료 시간을 설정하세요. 영구 토큰은 위험합니다. 보통 15분~1시간.
2. Refresh Token 사용
Access Token은 짧게, Refresh Token으로 갱신하는 방식이 안전합니다.
3. HTTPS 필수
HTTP에서는 토큰이 그대로 노출됩니다.
4. localStorage vs httpOnly 쿠키
localStorage는 XSS에 취약하고, 쿠키는 CSRF에 취약합니다. httpOnly 쿠키 + CSRF 토큰 조합이 가장 안전합니다.
언제 JWT를 쓸까?
- 마이크로서비스 아키텍처 (서버 간 인증 공유)
- 모바일 앱 (쿠키 대신)
- Single Sign-On (SSO)
- API 인증
단순한 웹사이트라면 세션이 더 간단할 수 있습니다. 적재적소에 사용하세요.