정의
로그인이 필요한 API를 호출하기 전에, “지금 비로그인이다”가 아니라 “세션 판정이 끝났는가”를 먼저 확인하는 기법이다.
인증 해소(auth resolution) 는 앱이 쿠키·토큰으로 세션을 복원하거나 “세션 없음”을 확정한 상태다. 그 전에는 user가 잠시 null일 수 있다. 게이팅(gating) 은 React Query 등의 enabled로 fetch on/off를 제어하는 것이다. 전형적인 식은 enabled: authResolved && isAuthenticated다.
왜 필요한가
세션 복원은 비동기다. 로딩 창에 !user만 보고 보호 리소스를 치면 401 Unauthorized가 나고, 전역 핸들러가 /login으로 보내 공개 홈·SEO 페이지까지 깨진다. 테스트용 MSW(목 네트워크)는 401을 안 내거나 타이밍을 가려, 실브라우저(쿠키 없는 컨텍스트) 에서만 재현되는 버그가 된다.
동작 원리
- auth 레이어가
status: 'loading' | 'authenticated' | 'anonymous'(또는resolved: boolean)를 노출한다. - 보호 쿼리:
enabled: status === 'authenticated'(또는resolved && !!user). - 공개/익명 페이지: 보호 쿼리
enabled: false, 목·정적 데이터만 사용. isAnonymous를!user로만 정의하지 않는다 — loading 중 true가 되면 잘못된 익명 UI·잘못된 fetch가 난다.- 전역 401→로그인 리다이렉트는 보호 라우트에만 적용하거나 공개 경로를 예외 처리한다.
실무 적용
- 공개 랜딩/홈: 메타·JSON-LD·FAQ는 서버/정적, 워크스페이스 API는 끄기.
- 헤더·탭 클릭: 익명이면 네비게이션 대신 로그인 다이얼로그.
- E2E: MSW만으로 “익명 OK”를 단정하지 말고, 쿠키 격리 실브라우저로 네트워크 401 유무를 본다.
- 로딩 UI:
resolved === false일 때는 스피너/스켈레톤, 익명 확정 후에만 잠금 패널.
트레이드오프
| 선택 | 장점 | 비용 |
|---|---|---|
| 엄격 게이트 | 공개 페이지 안정 | 해소 전 데이터 공백(스켈레톤 필요) |
!user만으로 fetch | 구현 단순 | 로딩 창 401·리다이렉트 |
| 전역 401→login | 보안 UX 단순 | SEO·익명 미리보기와 충돌 |
사용하면 안 되는 경우
- 애초에 공개 API만 쓰는 페이지에 과도한 auth 게이트를 붙여 불필요 지연을 만드는 경우.
- 서버 컴포넌트에서 이미 세션을 확정했는데 클라이언트에서 중복으로 막고 원인을 가리는 경우(경계를 문서화할 것).
흔한 실수
isAnonymous = !user→ 로딩 중에도 익명 취급.- E2E만 초록, 프로덕션에서만 로그인 튕김.
- 401 핸들러가 모든 fetch 실패에
/login— 공개 리소스 404/네트워크 오류까지 로그인으로 보냄.
관련 개념
- race-safe-async-ui-requests — 요청 취소·최신 응답만 반영
- structured-data-visible-content-parity — 공개 홈이 열렸을 때 채울 콘텐츠 규칙