[TIG] 로그아웃 시 refresh token 무효화

JEONG KI MIN·2024년 7월 30일

TIG

목록 보기
4/12

우리 서비스에서는 JWT를 사용해 로그인을 구현했었다. 이에 따라 로그아웃도 기록하려고 한다.

로그아웃

사용자가 로그아웃을 진행하면 기존의 토큰들을 무효화 시켜주어야 한다. 그렇지 않으면 개발을 좀 아는 사람이 토큰 값을 network 탭에서 까보고 가지고 있다가 억지로 악의적인 요청을 보낼 수도 있다.
백엔드에서 이를 검증해주고 막아야 한다.

Access Token

사용자에게 발급되는 토큰 중 하나인 at는 모든 요청에 대해 사용되기 때문에 반드시 만료해주어야 한다.
우리 서비스에서는 response body에 at를 담아서 보내주었기 때문에 프론트엔드에서 해당 토큰에 대한 접근이 가능했다. 따라서 로그아웃 요청이 이루어지면 프론트엔드에서 해당 토큰을 강제 만료시키는 방식으로 무효화를 진행했다.

Refresh Token

리프레시 토큰도 사용자가 가지고 있다면 reissue 요청을 통해 access token을 새로 발급받을 수 있기 때문에 로그아웃 시 반드시 무효화 시켜주어야 한다.
우리 서비스에서는 refresh token을 쿠키에 담아서 관리하고 전송하고 있었기 때문에 at와는 달리 프론트엔드에서 접근이 불가능 했다. (httpOnly 설정을 사용하고 있었기 때문이다)
따라서 로그아웃 요청이 오면 해당 rt를 무효화 하는 작업을 백엔드에서 담당해서 진행했다.

코드

@Transactional
public void logout(Long memberId) {
    Member member = memberRepository.findById(memberId)
            .orElseThrow(() -> new BusinessExceptionHandler("Member not found", ErrorCode.NOT_FOUND_ERROR));

    // 기존 리프레시 토큰을 블랙리스트에 추가
    String key = "blacklist:" + member.getRefreshToken();
    redisTemplateRT.opsForValue().set(key, "blacklisted", tokenProvider.getRefreshTokenExpiration(member.getRefreshToken()), TimeUnit.MILLISECONDS);

    member.updateRefreshToken(null);
}

로그아웃 시 사용되는 로직은 위와 같다.

  1. 일단 사용자가 at를 담아서 로그아웃 요청을 보내면 해당 at로 부터 사용자 아이디를 찾아낸다.
  2. 해당 아이디로 멤버 객체를 찾아온다.
    여기까지는 사용자 인증을 위한 과정이다.
  3. 사용자 객체로부터 refresh token을 가져와서 redis에 저장한다. 이때 blacklist 접두사를 붙여서 저장한다.
    추가적으로 해당 토큰의 남은 유효시간을 timeout 시간으로 정해서 해당 시간이 지나면 자동으로 redis에서 삭제 되도록 설정하였다.

이렇게 리프레시 토큰을 redis에 저장하고, 해당 refresh token이 사용되는 로직에서는 redis에 해당 토큰이 있는지 찾아본 뒤 없다면 진행하도록 구성했다.

결론

redis에 리프레시 토큰을 저장하면서 액세스 토큰에 대해서도 다시 생각해보게 되었다.
이전 포스트에서 언급했듯이, at 또한 쿠키로 전송한 뒤 만료시킬때 redis 에 저장했다면 좀 더 깔끔한 로직이 될 수 있을 것 같다.

profile
열심히 해볼게요

0개의 댓글