Skip to main content

로그인은 그냥 토큰만 쓰면 안되나요...

Intro

1. 인증 방식, 무엇을 선택할까?​

Spring Security 설정하다 보면 금방 맞닥뜨린다. Session이냐 JWT냐.

찾아보면 JWT가 요즘 대세처럼 보인다. Stateless, 확장성, MSA 친화적... 근데 직접 요구사항을 따져보니 JWT가 딱 맞지 않는 지점이 있었다.


2. Session vs Token 비교​

Session​

전통적인 웹 서비스 방식이다. 서버가 "모든 것을 기억" 한다.

핵심 메커니즘
  1. 저장: 서버의 메모리(혹은 외부 저장소)에 로그인/인증 정보를 저장한다.
  2. 전송: 클라이언트는 JSESSIONID와 같은 세션 ID만 쿠키로 들고 다닌다.
  3. 검증: 요청이 올 때마다 서버는 세션 ID를 통해 자신이 가지고 있는 정보와 매칭하여 유효성을 검사한다.

서버가 상태를 직접 쥐고 있어서 강제 로그아웃, 계정 차단을 즉각 처리할 수 있다. Spring Security 기본 방식이라 설정도 단순하다.

약점은 확장성이다. 서버를 여러 대 두면 각자 세션이 따로 놀아서 스케일아웃이 안 된다. Redis 같은 공유 저장소가 없으면.


Token (JWT)​

MSA 환경에서 주로 쓰는 방식이다. 서버는 "검증만 할 뿐, 기억하지 않는다."

핵심 메커니즘
  1. 발급: 로그인 성공 시 서버가 사용자 정보가 담긴 암호화된 토큰(JWT) 을 발급한다.
  2. 전송: 클라이언트는 요청 시 헤더(Authorization: Bearer ...)에 토큰을 담아 보낸다.
  3. 검증: 서버는 토큰의 서명(Signature) 만 확인하여 위변조 여부를 체크한다. (별도 저장소 조회 X)

서버에 아무것도 저장하지 않아서 서버를 얼마든지 늘릴 수 있다. 모바일 앱, SPA, SSO 환경에 자연스럽게 맞는다.

문제는 "발급된 토큰은 뺏을 수 없다" 는 것이다. 탈취되든, 강제 로그아웃을 시켜야 하든, 만료 전까지는 방법이 없다. Blacklist로 해결한다고들 하는데 그러면 어차피 Redis 같은 외부 저장소가 필요하다. 그 순간부터 Stateless 장점이 흔들린다.


3. 정리하면​

구분Session 권장Token (JWT) 권장
서비스 유형전통적 웹 서비스, 내부 어드민 시스템MSA, 모바일 앱, SPA, 글로벌 서비스
인프라 환경단일 서버 혹은 소규모 클러스터오토스케일링이 잦은 클라우드/분산 환경
필요 기능강제 로그아웃, 실시간 동시 접속 제어SSO, 다양한 클라이언트(Web/App) 지원
핵심 가치보안 및 중앙 제어 (Control)확장성 및 유연성 (Scalability)
한 줄 요약

웹 기반 내부 서비스에는 Session, 대규모 분산 환경이나 다양한 클라이언트를 지원해야 하면 Token.


4. Session + Redis 조합​

왜 Session을 선택했나?​

이전 프로젝트에서 관리자가 악성 사용자를 즉시 강제 로그아웃시킬 수 있어야 했다. 이게 결정적이었다.

JWT로 구현하면 Blacklist가 필요하고, Blacklist를 관리하려면 어차피 Redis가 필요하다. 그러면 Session + Redis를 쓰는 것과 뭐가 다른가. 같은 수고를 들이면서 JWT의 장점은 없어지는 구조다.

Same Origin 환경이었고 Spring Security 기본 설정이 그대로 맞았다. JWT를 억지로 얹을 이유가 없었다.

단점 극복: Redis로 세션 클러스터링​

세션 방식의 치명적인 약점은 서버 간 세션 불일치다. WAS를 2대 이상 늘리면, A 서버에서 로그인한 사용자가 B 서버로 요청을 보낼 때 로그인이 풀린다.

해결책은 각 서버의 로컬 메모리 대신 Redis에 세션을 저장하는 것이다. Spring Session Data Redis를 쓰면 설정 몇 줄로 끝난다. 어느 서버로 요청이 오든 Redis에서 동일한 세션을 참조하므로 로그인 상태가 유지된다.

세션의 보안 제어는 챙기면서, 확장성 문제는 Redis로 해결하는 구조다.

5. 마치며​

Session이냐 JWT냐보다, 내 서비스에서 "강제 로그아웃이 필요한가" 가 실제로 더 중요한 질문이었다. 그 답이 Yes라면 JWT는 Blacklist 없이는 구현이 어렵고, Blacklist를 쓰면 어차피 외부 저장소가 필요해진다. 그러면 Session + Redis가 더 솔직한 선택이다.