사용자가 로그인 상태를 유지하게 하는 방법은 웹 애플리케이션의 핵심적인 기능이다.
HTTP 프로토콜은 기본적으로 '상태가 없기(Stateless)' 때문에, 매 요청마다 사용자가 누구인지 알려줄 장치가 필요하다.
이를 해결하는 대표적인 두 가지 방식이 바로 세션(Session) 기반 인증과 토큰(JWT) 기반 인증이다.
두 방식 모두 인증을 위한 훌륭한 도구이지만, 동작 방식과 철학에 근본적인 차이가 존재한다. 관련 프로젝트를 진행하며 두 가지 방식을 모두 고려해 보았고, 그 과정에서 얻은 결론을 공유하고자 한다.
1. 세션(Session) 기반 인증: 서버가 모든 것을 기억한다 (Stateful)
세션 기반 인증은 서버가 사용자의 로그인 상태를 직접 저장하고 관리하는 'Stateful(상태 유지)' 방식이다. SessionUser 같은 객체는 이 방식에서 사용된다.
동작 흐름
- 로그인 시도: 사용자가 아이디와 비밀번호로 서버에 로그인을 요청한다.
- 세션 생성 및 저장: 서버는 요청이 유효한지 확인한 후, 해당 사용자를 위한 고유한 세션 ID를 생성한다. 그리고 SessionUser와 같은 사용자 정보를 서버의 메모리나 별도의 세션 저장소(e.g. Redis)에 세션 ID와 함께 저장한다.
- 세션 ID 전달: 서버는 응답 헤더에 Set-Cookie를 사용하여, 생성된 세션 ID를 클라이언트(브라우저)에게 전달한다.
- 인증 요청: 이후 클라이언트는 서버에 요청을 보낼 때마다, 브라우저가 자동으로 세션 ID가 담긴 쿠키를 함께 보낸다.
- 상태 확인: 서버는 클라이언트가 보낸 쿠키의 세션 ID를 보고, 자신의 세션 저장소에서 해당 ID에 맞는 사용자 정보(SessionUser)가 있는지 확인하여 인증 상태를 판단한다.
핵심 특징
- 상태 유지(Stateful): 로그인한 사용자의 정보가 서버 측에 저장된다.
- 서버 의존성: 인증을 위해 서버는 반드시 세션 저장소를 조회해야 한다.
- 확장성 문제: 사용자가 많아져 서버를 여러 대로 늘릴 경우, 모든 서버가 세션 정보를 공유할 수 있는 별도의 중앙 세션 저장소가 필요해지는 등 구조가 복잡해질 수 있다.
2. JWT(JSON Web Token) 기반 인증: 서버는 아무것도 기억하지 않는다 (Stateless)
JWT 기반 인증은 서버가 사용자의 상태를 저장하지 않는 'Stateless(상태 없음)' 방식이다. 인증에 필요한 모든 정보를 클라이언트가 토큰의 형태로 직접 들고 다니는 방식이다.
동작 흐름
- 로그인 시도: 사용자가 소셜 로그인 등으로 서버에 로그인을 한다.
- JWT 생성 및 발급: 서버는 요청이 유효한지 확인한 후, 사용자의 식별 정보와 권한 등을 담은 암호화된 JWT를 생성하여 클라이언트에게 직접 전달한다. (이때 서버는 아무것도 저장하지 않는다.)
- 토큰 저장: 클라이언트(브라우저)는 전달받은 JWT를 localStorage나 Cookie 같은 안전한 곳에 저장한다.
- 인증 요청: 이후 클라이언트는 보호된 API에 요청을 보낼 때마다, HTTP 헤더의 Authorization 필드에 Bearer [JWT] 형식으로 토큰을 담아 보낸다.
- 서명 검증: 서버는 클라이언트가 보낸 JWT의 서명(Signature)이 유효한지 자신의 비밀키로 검증합니다. 서명이 유효하면, 서버는 그 안에 담긴 사용자 정보를 신뢰하고 요청을 처리합니다. 별도의 저장소를 조회할 필요가 없다.
핵심 특징
상태 없음(Stateless): 서버는 사용자의 로그인 상태를 저장하거나 기억하지 않는다.
자기 완결성(Self-contained): 토큰 자체가 사용자를 식별하는 데 필요한 모든 정보를 담고 있다.
확장성(Scalability): 서버가 상태를 관리할 필요가 없으므로, 서버를 여러 대로 늘리기가 매우 용이하다. 마이크로서비스 아키텍처나 모바일 앱 연동에 매우 적합하다.
결론
두 방식의 가장 큰 차이는 "로그인 상태 정보를 어디서 관리하는가?" 다.
| 기준 | 세션 기반 인증 | JWT 기반 인증 |
| 상태 유지 | Stateful (서버가 상태 기억) | Stateless (서버가 상태 기억 안 함) |
| 정보 저장 위치 | 서버 메모리 또는 세션 저장소 | 클라이언트 (브라우저 등) |
| 확장성 | 상대적으로 복잡함 | 상대적으로 용이함 |
| 주요 사용처 | 전통적인 웹 애플리케이션 (Thymeleaf 등) | 분리된 프론트엔드(SPA), 모바일 앱 |
현재 진행하는 프로젝트는 Spring Boot API 서버와 Next.js 프론트엔드가 분리된 아키텍처를 유지하고 있다.
이러한 구조에서는 서버가 화면을 직접 그리지 않고 데이터(JSON)만 제공하므로, 상태를 저장할 필요가 없는 JWT 방식이 훨씬 더 적합하다.
'Spring이당' 카테고리의 다른 글
| [WEB] 서블릿(Servlet)과 동시성, 그리고 스레드 풀의 모든 것 (3) | 2025.08.29 |
|---|---|
| WAS만 쓰면 안 되나요? 웹 서버와 WAS를 함께 쓰는 진짜 이유 (1) | 2025.08.26 |
| 그래서 JPA 하이버네이트가 뭔데? 라이브러리! (1) | 2025.08.03 |
| JPA를 왜 써야 할까 - 패러다임의 불일치 (2) | 2025.08.02 |
| Spring : Cannot access ~~.repository 이슈 (해결) (1) | 2025.06.02 |