[버티] JWT로 로그인을 구현했을 때 로그아웃 방법을 어떻게 해야할까?
in ProjectDiary
JWT 로그인 구현 시 로그아웃 방법 고민..
저번 프로젝트에서는 로그아웃을 구현하지 않고, 토큰 만료를 사용했는데 로그아웃을 구현해달라는 요청이 있었어서 이번 프로젝트에서는 제대로 알아보고 구현해보기로 하였다.
- JWT는 기본적으로 상태를 저장하지 않아(stateless) 로그아웃 처리에 어려움이 있다.
로그아웃을 구현하는 방법에는 크게 3가지가 있다.
1. 프론트엔트에서 토큰 삭제 - 가장 구현이 간단하다. - 클라이언트 측에서 토큰을 삭제하여 로그아웃을 구현하는 방법 - 이 방법이 토큰의 `Stateless`한 특징을 최대한 살린 방식 > 'Stateful` : 데이터베이스에 정보를 저장하고 조회하는 경우
‘Stateless`: 데이터베이스를 사용하지 않는 방식
JWT는 데이터베이스에 저장 및 조회가 필요없기 때문에
Stateless
한 특징을 가지고 있다.- 단점 : 서버에선 토큰이 유효하기 때문에, 토큰이 노출되면 보안 문제가 생길 수 있음.
- 토큰 블랙리스트 관리
- JWT가 만료되지 않은 상태에서 로그아웃 요청이 오는 경우, 서버에서 해당 토큰을 블랙리스트 DB에 넣어 처리
- 인증 필터에서 매 요청마다 토큰이 블랙리스트에 해당하는 토큰인지 확인해야한다.
- 서버에서 토큰을 효과적으로 관리할 수 있지만, 매 요청마다 블랙리스트를 확인해야하기 때문에
stateless
한 JWT의 장점이 없어진다.
- Refresh Token 기간 만료 처리
- 사용자가 로그아웃을 요청할 때 리프레시 토큰을 무효화해 해당 사용자가 더 이상 새로운 엑세스 토큰을 발급받지 못하도록 하는 방식
- 사용자의 로그아웃 요청에 대해 서버 측에서 적극적으로 대응할 수 있다는 장점이 있다.
- 엑세스 토큰 재발급의 연속성을 차단해 보안을 강화할 수도 있다.
- 하지만 리프레시 토큰 확인 과정에서 JWT의
Stateless
한 장점이 사라진다.
- 2번 VS 3번 비교
- 2번의 경우, 블랙리스트 DB 혹은 Redis를 사용해 서버 상태를 관리해야 한다.
- 또한
Stateless
성이 완전히 깨지고 (모은 요청 시 DB확인이 필요하기 때문에!) 성능 이슈가 생길 수 있다. - 하지만 3번의 경우, 리프레시 토큰만 관리하면 되기 때문에 상대적으로 가볍다.
- 리프레시 토큰만 서버 저장 및 관리하면 된다!
- 또한 3번은
Stateless
를 부분적으로 유지 가능하다. (액세스 토큰은 여전히Stateless
)
- 일단은 3번 방법을 선택해서 로그아웃을 구현해보기로 결정하였다.
- 어플리케이션이 그렇게 무거운 프로젝트가 아니기 때문에, 블랙 리스트 방식처럼 서버 자원을 지속적으로 소모하는 설계보다는 토큰 생명주기를 명확히 관리할 수 있는 방식이 더 적합할 것 같다고 판단했다.
- 또한 리프레시 토큰 구현으로 토큰의 생명 주기에 대해 이해해볼 수 있을 것 같아 선택하게 되었다.
- 이번 프로젝트는 데이터베이스 사용이 많은 구조이기 때문에, 불필요한 토큰 상태 관리를 피하고 전체 시스템의 부하를 줄이기 위한 의도도 있었다.
리프레시 토큰의 발급 및 만료 흐름을 직접 설계함으로써, JWT 기반 인증 시스템의 구조와 보안 설계에 대한 이해도를 높이는 기회로 삼고자 한다.
참고 :