본문 바로가기
-- 오늘 있었던 개발 일기

ReFresh Token 에서 Refresh Token Rotation까지 사용하자

by code study 2026. 2. 11.

기존 방식: JWT 단일 토큰

초기에는 Access Token 하나만 사용하는 구조였다.

로그인
 → Access Token 발급 (유효기간 7일)
 → 만료 시 재로그인

 

운영 과정에서 다음과 같은 딜레마가 발생했다.


문제점

1. 토큰 유효기간을 길게 설정할 경우

  • 토큰 탈취 시 7일 동안 제3자가 자유롭게 사용 가능
  • JWT는 Stateless 특성으로 인해 서버에서 토큰을 강제로 무효화할 수 없음
  • 로그아웃을 하더라도 토큰은 만료 시점까지 계속 유효

결과적으로 보안 사고 발생 시 대응이 불가능하다.


2. 토큰 유효기간을 짧게 설정할 경우

  • 30분마다 재로그인이 필요
  • 사용자 경험(UX)이 크게 저하됨
  • 실제 서비스 환경에서는 사용자가 이탈할 가능성이 높아짐

해결책: Access Token + Refresh Token 구조 도입

보안과 사용자 경험을 동시에 만족시키기 위해
Access Token과 Refresh Token을 분리하여 사용한다.

토큰 종류 역할 만료 시간 관리 주체
Access Token API 요청 인증 30분 클라이언트
Refresh Token Access Token 재발급 7일 서버(Redis)

 


왜 더 안전한가?

상황 Access Token만 사용 Access + Refresh 사용
Access Token 탈취 7일간 피해 발생 최대 30분만 피해
Refresh Token 탈취 해당 없음 Redis에서 즉시 무효화 가능
로그아웃 토큰 만료까지 유효 Redis 삭제로 즉시 무효화
서버 제어 불가능 가능

핵심 구현 포인트

1. Refresh Token을 Redis에 저장

// 로그인 시
redisTemplate.set("refresh:1", refreshToken, 7일);

// 로그아웃 시
redisTemplate.delete("refresh:1");  // 즉시 무효화
  • Refresh Token을 서버에서 관리하여 강제 로그아웃 및 만료 제어 가능
  • JWT의 Stateless 특성을 보완하는 핵심 요소

2. Refresh Token Rotation 적용

// 토큰 갱신 시마다 새 Refresh Token 발급
String newRefreshToken = generateRefreshToken(memberId);
redisTemplate.set("refresh:1", newRefreshToken);  // 기존 토큰 덮어쓰기
  • Refresh Token 재사용 공격 방지
  • 탈취된 Refresh Token으로 재발급 시 Redis 불일치로 차단

3. 프론트엔드 자동 토큰 갱신 (Axios Interceptor)

// 401 에러 발생 시 자동으로 토큰 재발급 후 재요청
if (status === 401) {
    const newTokens = await reissue(refreshToken);
    return api(originalRequest);
}
  • 사용자는 로그인 만료를 인지하지 않음
  • 서비스 사용 흐름이 끊기지 않음

결론

항목 기존 방식 개선 후
보안 토큰 탈취 시 대응 불가 피해 시간 최소화 + 즉시 무효화
사용자 경험 주기적 재로그인 필요 자동 갱신으로 끊김 없음
서버 제어 불가능 로그아웃 및 강제 만료 가능

 

JWT의 Stateless 장점은 유지하면서,
Refresh Token과 Redis를 통해 서버의 제어권을 확보한 구조다.


현재는 AT에 만료기간을 RT와 같이 일주일로 수정하였다.

이유는 redis 클라우드를 통해 팀원들과 RT저장을 공유하며 사용하다보니 두 팀원이 같은 아이디로 로그인을하였을 때 다른 한 팀원에 AT가 만료되어 RT가 AT를 재발급을 하게 되면 다른 팀원이 사용했던 기존 AT와 RT에 의해 바뀐 새 AT와 달라지기 때문에 로그아웃이 되는 문제가 생겨 개발단계에서는 AT기간을 늘려서 개발하기로 결정하고 개발 완료시 다시 AT의 만료시간을 30분으로 줄일 예정이다.