재현
- 웹+앱 등 2기기에 동일 계정 로그인
- 기기 A에서 회원 탈퇴
- 기기 B에서 아무 화면 사용 →
/home ↔ /login 무한 리다이렉트 + refresh 재시도 루프
서버 로그: 모든 API가 401(COMMON-UNAUTHORIZED), refresh도 401(AUTH-001, "탈퇴 유저" 사유)이 초 단위로 반복.
원인 — 죽은 쿠키를 아무도 안 지움 + 로그인 페이지가 로컬 exp만 믿음
탈퇴 직후 access 토큰은 exp상 유효(최대 15분)하지만 서버에서는 무효인 상태가 된다. 이 상태에서:
/home 쿼리 401 → 인터셉터가 refresh 시도 → 401 → /login?redirect=/home&action=session-expired 리다이렉트. 이때 쿠키를 지우지 않음 (apis/client.ts 갱신 실패 catch)
- 로그인 페이지: action이 있어 홈 포워딩은 스킵하지만,
LoginButtons가 토스트 후 router.replace로 action 파라미터를 벗겨냄
/login?redirect=/home(action 없음) 재진입: login/page.tsx:26-33이 죽은 access 쿠키의 role=MEMBER만 보고 redirect(ROUTES.HOME) → 홈 복귀
- 1번으로 → 무한
proxy(#451의 쿠키 폐기)도 개입 못 한다 — isTokenValid가 로컬 exp만 검사해 "access 유효 → 통과"로 판단하므로 갱신 자체를 시도하지 않는다.
같은 이유로 Apple 동의철회, (이론상) 세션 재사용 감지 등 "서버가 세션을 죽였는데 클라는 모르는" 모든 경로에서 동일 루프가 발생할 수 있다. 배포 직후 레거시 토큰 401은 access가 이미 만료된 뒤라 proxy 경로(#451)로 정리되므로 이 루프에 해당하지 않는다.
수정
(a) proxy.ts — session-expired/withdrawn-account action으로 /login에 도착하면 인증 쿠키 폐기 (Set-Cookie Max-Age=0). 브라우저 httpOnly 쿠키는 JS로 지울 수 없어 이 지점이 유일한 정리 위치. 루프의 3번 고리(멤버 오인 → 홈 포워딩)를 끊는다.
(b) apis/client.ts — 갱신 실패(catch) 시 deleteCookie + 웹뷰면 WEB_REQ_LOGOUT 브릿지로 네이티브 TokenStorage까지 정리. 웹뷰(JS 쿠키)는 즉시 정리되고, 앱 재시작 시 죽은 토큰이 재주입되는 것도 방지.
서버 협의 (별도)
refresh 거부 code가 탈퇴 유저여도 AUTH-001(일반 만료)로 내려와 클라가 "탈퇴한 계정" 안내를 할 수 없음 → 탈퇴 사유일 때 USER-003으로 내려줄 수 있는지 협의. 루프 자체는 위 (a)+(b)로 해결되며 이건 안내 문구 정확성 문제.
연관 이슈
재현
/home↔/login무한 리다이렉트 + refresh 재시도 루프서버 로그: 모든 API가 401(
COMMON-UNAUTHORIZED), refresh도 401(AUTH-001, "탈퇴 유저" 사유)이 초 단위로 반복.원인 — 죽은 쿠키를 아무도 안 지움 + 로그인 페이지가 로컬 exp만 믿음
탈퇴 직후 access 토큰은 exp상 유효(최대 15분)하지만 서버에서는 무효인 상태가 된다. 이 상태에서:
/home쿼리 401 → 인터셉터가 refresh 시도 → 401 →/login?redirect=/home&action=session-expired리다이렉트. 이때 쿠키를 지우지 않음 (apis/client.ts갱신 실패 catch)LoginButtons가 토스트 후router.replace로 action 파라미터를 벗겨냄/login?redirect=/home(action 없음) 재진입:login/page.tsx:26-33이 죽은 access 쿠키의 role=MEMBER만 보고redirect(ROUTES.HOME)→ 홈 복귀proxy(#451의 쿠키 폐기)도 개입 못 한다 —
isTokenValid가 로컬 exp만 검사해 "access 유효 → 통과"로 판단하므로 갱신 자체를 시도하지 않는다.같은 이유로 Apple 동의철회, (이론상) 세션 재사용 감지 등 "서버가 세션을 죽였는데 클라는 모르는" 모든 경로에서 동일 루프가 발생할 수 있다. 배포 직후 레거시 토큰 401은 access가 이미 만료된 뒤라 proxy 경로(#451)로 정리되므로 이 루프에 해당하지 않는다.
수정
(a)
proxy.ts—session-expired/withdrawn-accountaction으로/login에 도착하면 인증 쿠키 폐기 (Set-Cookie Max-Age=0). 브라우저 httpOnly 쿠키는 JS로 지울 수 없어 이 지점이 유일한 정리 위치. 루프의 3번 고리(멤버 오인 → 홈 포워딩)를 끊는다.(b)
apis/client.ts— 갱신 실패(catch) 시deleteCookie+ 웹뷰면WEB_REQ_LOGOUT브릿지로 네이티브TokenStorage까지 정리. 웹뷰(JS 쿠키)는 즉시 정리되고, 앱 재시작 시 죽은 토큰이 재주입되는 것도 방지.서버 협의 (별도)
refresh 거부 code가 탈퇴 유저여도
AUTH-001(일반 만료)로 내려와 클라가 "탈퇴한 계정" 안내를 할 수 없음 → 탈퇴 사유일 때USER-003으로 내려줄 수 있는지 협의. 루프 자체는 위 (a)+(b)로 해결되며 이건 안내 문구 정확성 문제.연관 이슈