시큐리티 적용을 위하여 일반적으로 JWT를 이용하여 토큰을 발행하고,
이를 기반으로 시큐리티 검증을 실시한다.
그렇다면 JWT 기반 로그인 설계에서 로그아웃은 어떻게 실행할까?
일단 결론부터 말하자면, JWT 기반의 스프링 시큐리티 환경에서 “완전한 로그아웃”을 구현하는 것은 구조적으로 불가능하다.
JWT의 특성과 서버 비관리성
JWT(Json Web Token)는 기본적으로 서버 비상태(stateless) 인증 방식을 지향한다.
즉, 토큰이 한 번 클라이언트에 발급되면 이후의 인증 과정은 서버의 세션 상태와 무관하게 진행된다.
서버는 토큰의 서명 검증을 통해 유효성을 판단할 뿐, 토큰 자체를 관리하거나 폐기할 수 있는 권한이 없다.
이 구조적 특성 때문에, 한 번 발급된 JWT를 서버에서 ‘무효화’하는 것은 불가능하다.
결국 서버 입장에서는 JWT를 발급한 시점 이후로 그 토큰에 대한 통제력을 상실하게 된다.
현실적인 대안: 만료 시간과 Refresh Token
따라서 현실적으로 취할 수 있는 최선의 접근은 다음과 같다.
- Access Token의 유효 기간을 짧게 설정하여 토큰 탈취 시 피해 범위를 최소화한다.
- Refresh Token을 별도로 운용하여 Access Token을 재발급받을 수 있도록 한다.
이때 Refresh Token은 일반적으로 서버 또는 Redis 같은 저장소에 보관하여,
로그아웃 시 해당 토큰을 삭제함으로써 갱신 자체를 막는 방식으로 관리할 수 있다. ( 그리고 클라이언트는 이를 절대 로컬Storage에 저장해서는 안된다)
대개의 로그인 기반 시스템에서는, 짧은 수명의 Access Token을 브라우저 측에 저장하여 인증에 활용한다.
이때 일반적으로 Access Token은 HTTP-Only 쿠키로 저장하거나,
혹은 클라이언트에서 직접 Authorization 헤더에 Bearer 토큰 형태(Authroization Bearer: ...)로 포함시켜 전송한다.
Access Token의 유효 기간은 보안상 짧게 설정하는 것이 원칙이다.
이 원칙을 지켜야만 토큰이 탈취되더라도 빠른 시간 안에 만료되기 때문에, 피해를 최소화할 수 있다.
이렇게 만료된 Access Token은 더 이상 사용할 수 없게 되며,
대신 서버는 별도의 Refresh Token을 이용해 새로운 Access Token을 재발급하는 구조를 갖는다.
따라서 시스템 설계 시에는 다음 두 가지 API를 명확히 분리하는 것이 좋다.
- Access Token 발급 및 인증용 API
- 로그인 성공 시 발급되는 단기 토큰.
- 모든 인증 요청 시 헤더에 포함되어 전달된다.
- 짧은 유효기간을 가지며, 만료 시 즉시 무효화된다.
- Refresh Token 기반 재발급 API
- Access Token이 만료되었을 때, 저장된 Refresh Token을 검증하여 새로운 Access Token을 재발급한다.
- Refresh Token은 일반적으로 Redis나 DB에 저장되어, 로그아웃 또는 보안 이벤트 발생 시 삭제가 가능하다.
이러한 전략을 통해, JWT의 비상태성이라는 한계를 보완하며
사실상 로그아웃과 유사한 효과를 구현할 수 있다.
로그아웃 처리 방식
- 클라이언트 측 처리
- 브라우저에 저장된 JWT(쿠키, 로컬 스토리지 등)를 제거한다.
- Authorization 헤더에 포함된 토큰 값을 초기화한다.
- 서버 측 처리
- Redis 등 별도의 저장소에 Refresh Token을 저장해두었다면 해당 토큰을 삭제한다.
- 필요 시 Access Token을 블랙리스트 처리하여 일정 기간 동안 인가 요청을 차단할 수도 있다.
(단, 이는 Redis나 메모리 캐시의 추가 부하를 감수해야 한다.)
// 쿠키에 저장된 기록 전부 삭제
cookie.setMaxAge(0);
// Redis에 저장된 Refresh Token 삭제
redisTemplate.delete(refreshTokenKey);
JWT는 근본적으로 “서버가 세션 상태를 기억하지 않는다”는 특징을 기반으로 설계된 것이다.
따라서 완전한 의미의 로그아웃(=서버에서 토큰을 즉시 무효화)은 불가능하다.
그러나 Access Token의 만료 전략과 Refresh Token 저장소 관리,
그리고 클라이언트 측 쿠키/토큰 정리를 조합하여 실질적인 로그아웃 기능을 구현할 수 있다.
REF
'백엔드 > SpringBoot' 카테고리의 다른 글
| [SpringBoot] UnitTest (1) | 2025.08.27 |
|---|---|
| [SpringBoot] Spring에서 비동기 작업과 스케줄링 - ThreadPoolTaskScheduler 편 (0) | 2025.08.22 |
| [Spring Boot] 동시성 제어하기 (5) | 2025.08.10 |
| [Spring Boot] LazyInitializationException 을 알아보자 (5) | 2025.08.09 |
| [JPA] Page와 Slice 클래스 구분하기 (0) | 2025.08.08 |