1. 개요
기존에 구동되던 사용자 인증 방식을 RefreshToken 기반의 지연 갱신(Lazy Refresh) 매커니즘으로 유연하게 전환하고, 이 전환 과정에서 뜻하지 않게 맞닥뜨린 프론트/백엔드 서버 간의 9시간 타임존 시차 불일치 및 무한 로그인 리다이렉션 루프 현상을 JWT 절대 시간 검증 파싱 방식으로 말끔하게 극복해 낸 소중한 아키텍처 개선 기록을 담고 있습니다.
2. 핵심 내용
2-1. 토큰 지연 갱신(Lazy Refresh)과 로컬 스토리지의 데이터 성격 규정
사용자의 보안성과 매끄러운 UX를 동시에 챙기기 위해, 단순히 타이머를 돌려 주기적으로 토큰을 연장하는 방식(Proactive Timer) 대신 사용자가 실제로 보호된 자원에 접근하거나 앱을 조작하는 찰나의 순간에만 만료 여부를 검증하고 토큰을 살려내는 지연 갱신(Lazy Refresh) 방식을 도입해 서버의 불필요한 부하를 최소화하고자 고민했습니다.
아울러 로컬 스토리지에 보존되는 임시 데이터 또한 세밀하게 성격을 나눴습니다. 개인 일지 드래프트와 같은 보안에 민감한 정보들은 로그아웃 시 즉각 휘발(Purge)되도록 설정하는 반면, 다크모드 설정이나 테마와 같이 연속된 유저 경험이 유지되어야 하는 데이터는 로컬 스토리지에 남아있도록 조율하여 실무적인 무결성을 동시에 만족시켰습니다.
2-2. 9시간 시차와 로그인 루프 트러블슈팅 (원인 및 해결책)
- 문제 상황: 배포 직후 오전 10시경, 백엔드 서버는 토큰 만료에 따라 정상적으로
401 Unauthorized에러를 반환하는 상황이었음에도 불구하고, 프론트엔드의 인증 미들웨어가 유효성 검증 단계를 오판하여 메인 화면으로 리다이렉트시킨 뒤 다시 API를 찔러 결국 무한 로그인 루프가 발생하는 기이한 병목이 포착되었습니다. - 원인 분석:
- 도커 컨테이너 내부의 타임존 설정을
Asia/Seoul로 명시하였으나, 백엔드 스프링 부트에서 시간대 정보가 배제된LocalDateTime문자열로 만료 일시를 넘겨주는 실책이 있었습니다. - 이를 프론트엔드(Next.js) 서버나 브라우저 환경에서 수신하여 표준
Date객체로 파싱할 때 ISO 포맷 특성상 이를 임의로 **UTC(세계 표준시)**로 해석해 버렸습니다. - 그 결과, 실제 만료 시각인 한국 표준시(KST) 오전 9시 58분이 프론트엔드에서는 9시간 뒤인 오후 6시 58분으로 오인되는 상황이 빚어졌고, 아직 토큰 만료가 많이 남았다고 착각하여 계속 만료된 토큰으로 통신을 강행했던 것이 원인이었습니다.
- 도커 컨테이너 내부의 타임존 설정을
- 해결 방안: 문자열 보정이나 서버 시스템 시간 수정처럼 외적 환경 요인에 강하게 묶인 옵션들을 과감히 배제했습니다. 대신 **“가장 강력하고 오염되지 않은 단일 원천 데이터(Single Source of Truth)인 JWT 페이로드 내부의
exp(만료 유닉스 타임스탬프) 값을 직접 디코딩하여 대조하자”**는 전략을 수립하고 전격 도입했습니다. JWT 내부exp는 타임존에 독립적인 절대적인 유닉스 시간 초단위(Seconds) 정보이므로 프론트엔드가 환경의 제약 없이 항시 정확한 만료를 탐지할 수 있도록 문제를 말끔히 차단했습니다.
2-3. JWT 절대 시간 파싱 전환 구현 및 추천 라이브러리 검토
BFF(Backend-For-Frontend) 및 Axios Response Interceptor 단에서 만료 데이터를 절대 스탬프 기준으로 동기화해 줌으로써 로그인 루프는 온전히 소멸되었습니다. 이처럼 브라우저의 시간 설정이나 서버가 배포된 클라우드 리전의 타임존 설정에 방해받지 않고 데이터 무결성을 보장하는 것은 프로덕션 안정성 확립에 매우 핵심적입니다.
- 추천 오픈소스 라이브러리:
jwt-decode: 프론트엔드 단에서 JWT 페이로드를 단 몇 줄의 안전하고 경량화된 코드로 안전하게 파싱해주는 대표적인 유틸리티 라이브러리입니다. 복잡한 Base64 디코딩 및 예외 처리를 대신 처리해주어 유닉스 타임스탬프exp를 안전히 획득하는 데 매우 적극 추천해 드립니다.TanStack Query (React Query): API 호출 과정에서의 지연 갱신(Lazy Refresh) 로직과 함께 데이터 동기화를 유지할 때, 쿼리의enabled옵션 게이팅(Gating) 처리를 선언적이고 풍부하게 도와주므로 Axios 인터셉터 구조의 보완재로 매우 유용하게 쓰일 수 있습니다.