개요

JWT 기반 사용자 인증을 직접 구현하면서, 고려해야 할 요소가 많았으며 각 선택지별 장·단점이 존재했다. 이번 포스트에서는 해당 기능을 구현하면서 고민했던 과정을 서술해 보고자 한다.

토큰 기반 인증 매커니즘

먼저, 토큰 기반 인증 매커니즘을 이해할 필요가 있다. 토큰을 사용한 인증 방식은 아래와 같다.

  1. 사용자가 로그인 한다. (로그인 정보를 서버로 요청)
  2. 서버는 사용자를 검증하고, 유효할 경우 Signature를 가지는 토큰을 클라이언트로 반환한다.
  3. 클라이언트는 토큰을 저장하고, 서버에 요청시 해당 토큰을 Request Header에 담아 서버에 요청한다.
  4. 서버는 토큰을 검증하고, 클라이언트 요청에 적절한 응답을 한다.

해당 방식은 서버에 사용자 상태 정보(인증 토큰 등)을 저장할 필요가 없기 때문에, scale-out 한 서버 확장에 용이하며 서버의 부담을 줄일 수 있게 된다.

하지만 해당 토큰(Access Token)이 탈취된다면, 토큰 만료 전까지 제3자가 무제한으로 사용할 수 있다는 문제점이 있다. 따라서, 해당 문제점을 해결하기 위해 Refresh Token의 도입이 필요하다.

Refresh Token 도입

Refresh Token의 매커니즘은 다음과 같다.

해당 매커니즘은 RFC-6749(OAuth2.0) 공식 문서에서 자세히 확인할 수 있습니다.

  1. 사용자가 로그인 한다. (로그인 정보를 서버로 요청)
  2. 서버는 Access Token과 Refresh Token을 함께 발급하고, 클라이언트로 반환한다.
  3. 클라이언트는 두 개의 토큰을 저장하고, 서버에 요청 시 Access Token을 Request Header에 담아 서버에 요청한다.
  4. 이후 Access Token이 만료되었을 때, 클라이언트는 Refresh Token을 서버로 전달하여 새로운 Access Token과 Refresh Token을 발급 받는다.

이렇게 Access Token의 유효기간을 매우 짧게 지정하고, 해당 토큰이 만료되었을 때 Refresh Token을 통해 지속적으로 Access Token을 재발급 해주는 방식으로 구현하면, 이전보다 제3자가 탈취한 Access Token을 사용할 수 있는 텀이 줄어들게 된다. (사용자 편의를 위해 토큰 재발급 받는 과정이 자연스러워함은 필수)

하지만 Refresh Token이 JWT 타입이면서 제3자에게 탈취되었다면, 서버에서는 토큰의 유효성 검증만 할 수 있기 때문에(JWT 타입이면 굳이 서버에 저장해놓지 않았을 것), 해당 토큰을 무력화할 수 있는 방법이 존재하지 않는다.

따라서 Refresh Token의 타입을 JWT가 아닌 다른 타입으로 지정하고, 서버의 공유 저장소(Redis 등)에 각 사용자에 대한 Refresh Token을 저장할 필요가 있다.

Refresh Token 타입

Refresh Token의 타입으로 적합하려면, 유일성을 보장하면서 동시에 최대한 크기가 작아야 한다. 따라서 UUID(Universally Unique IDentifier)를 Refresh Token 타입으로 지정한다.

또한, 서버의 공유 저장소(Redis 등)에 Refresh Token을 저장한다. 따라서 Access Token이 갱신될 때 Refresh Token 또한 같이 갱신되므로, 해당 사용자에게 저장되지 않은 Refresh Token으로 요청이 온다면 탈취된 것으로 판단하고 적절한 조치를 취할 수 있게 된다.

참고

댓글남기기