큐 기반 토큰 재발급

interceptors로 인한 refreshToken 요청이 여러번 갈때

2025년 5월 14일

🥹 로그인 상태가 풀려 보이는 문제를 마주하다

앱 화면
로그인/비로그인 상태 화면 비교

서비스를 개발하면서 가장 난감했던 순간 중 하나는 로그인이 풀린 것처럼 보이는 현상이었습니다. 로그인된 유저는 오른쪽 화면, 비로그인 유저는 왼쪽 화면이 보여야 합니다.

그런데 access token이 만료된 뒤, 어떤 경우에는 로그인 상태가 유지되고, 어떤 경우에는 "로그인 후 이용해주세요" 화면이 나타났습니다. 항상 발생하는 문제가 아니어서 원인을 찾는 데 오랜 시간이 걸렸습니다.


기존 로직

  • axios interceptor에서 access token 만료 시 refresh token으로 재발급
  • 실패한 요청을 새 토큰으로 재시도
  • 프로필 요청 성공 시 Context에서 isAuthenticated = true 설정

토큰 재발급과 프로필 요청을 기반으로 로그인 상태를 유지하는 구조였습니다.


원인 파악 과정

두 가지 단서로 원인을 추적했습니다.

단서 1. "로그인 후 이용해주세요" 화면에서 로그인 화면으로 갔다가 뒤로 돌아오면 데이터가 정상적으로 표시됩니다.

단서 2. 챌린지 리스트는 표시되지 않지만, 날짜 위 색상과 상태바는 정상적으로 표시됩니다. 일부 요청만 실패한 것입니다.

카카오톡 대화내용
일부 요청만 실패한 화면

단서 1을 보면 실제로 로그인이 풀린 것이 아니므로, 토큰 재발급 로직에 문제가 있다고 판단했습니다.

테스트로 발견한 문제

토큰을 임의로 만료시키는 버튼을 만들어 재발급 과정을 확인했습니다.

요청 테스트
토큰 만료 테스트 결과

여러 번 테스트한 결과, 두 가지 문제를 발견했습니다.

  1. 재발급 요청이 한 번이 아니라 여러 번 전송됩니다.
  2. 실패한 요청들의 재시도 방식이 매번 달라집니다.

여기서 정확한 원인을 파악할 수 있었습니다.

재발급 이후 프로필 요청이 재시도되지 않으면, auth context가 인증 상태를 true로 설정하지 못합니다. 결과적으로 토큰은 유효하지만 isAuthenticated가 false가 되어 "로그인 후 이용해주세요"가 표시된 것입니다.


문제의 코드

첫 화면에서 5개 요청을 동시에 보내면, access token 만료 시 5개 모두 interceptor를 실행합니다. 각각 재발급을 시도하면서 문제가 발생합니다.

  1. 만료된 토큰으로 요청 A, B를 동시에 보냄
  2. A가 먼저 interceptor에서 재발급 시도
  3. 거의 동시에 B도 재발급 시도
  4. 서버가 B에 새 토큰을 발급하면서 A가 받은 토큰을 무효화
  5. A는 이미 무효화된 토큰으로 재시도

이 과정이 반복되면 무한 루프에 빠질 수 있고, 5개 요청 중 일부만 성공하는 상황이 발생합니다.


해결 방법

참고 블로그에서 해결책을 찾았습니다.

핵심 아이디어:

  • isRefreshing 플래그로 재발급 요청을 1회로 제한
  • 실패한 요청을 큐에 저장
  • 토큰 재발급 완료 후 큐의 모든 요청을 일괄 재시도
해결된 화면
정상적으로 동작하는 화면

이 구조를 적용한 결과:

  • 재발급 요청은 항상 1회만 발생
  • 실패한 요청들이 모두 정상적으로 재시도

마치며

큐 기반 재발급-재시도 로직으로 재발급 1회 → 큐에 쌓인 요청 일괄 재시도라는 명확한 흐름을 만들어 문제를 해결했습니다.

원인을 찾는 과정은 힘들었지만, 이 패턴은 토큰 재발급뿐 아니라 다양한 API 통신 안정성 문제에 활용할 수 있을 것 같습니다.