인증 API 맥락 (Refresh 쿠키)
스펙 원본은 frontmatter
spec:. 전체 계약은 auth-refresh-cookie-api.md. 이 문서는 설계 이유와 FE·BE가 함께 지켜야 하는 흐름만.
한눈에
| 엔드포인트 | 역할 한 줄 |
|---|---|
POST /v1/auth/google/complete | OAuth ticket → access token(body) + refresh(HttpOnly 쿠키) |
POST /v1/auth/token/refresh | 쿠키 검증 후 access·refresh 동시 재발급 |
POST /v1/auth/logout | refresh 쿠키 만료(Max-Age=0) |
왜 이렇게 생겼나
- Refresh는 stateless JWT + HttpOnly 쿠키. DB·Redis 저장 없음(운영 단순),
localStorage대비 XSS로 토큰 자체를 읽을 수 없음. 대가는 아래 “알려진 제약”. - 쿠키
Path=/v1/auth— refresh 토큰이 인증 API 호출에만 실려 다닌다. 일반 API 요청엔 아예 전송 안 됨(노출 면적 최소화). - access token은 body로 반환 — FE가 메모리에 두고
Authorization헤더로 사용.
FE·BE가 함께 지키는 흐름
보호 API 401 → refresh 1회(single-flight) → 성공: 원요청 1회만 재시도
→ 실패: POST /logout → /login 이동- single-flight: 여러 API가 동시에 401이어도 refresh 요청은 하나만.
- 재발급 실패 시 서버가 쿠키를 자동 삭제하지 않는다 — FE가 반드시
/logout을 호출해 HttpOnly 쿠키를 만료시켜야 함. 안 하면 만료·손상 쿠키로 refresh 무한 실패 루프. - refresh 자체의 실패는 다시 refresh하지 않는다. 원요청 재시도는 최대 1회.
- 모든 인증 호출은
credentials: 'include'필수 — 빠지면 쿠키가 안 실려 로컬에서만 재현 안 되는 401이 된다.
알려진 제약 (stateless 선택의 대가)
- 로그아웃은 브라우저 쿠키만 삭제 — 탈취된 refresh JWT는 만료 전까지 유효.
- 재사용 감지, 기기별 세션, 전체 기기 로그아웃 없음.
- 탈퇴 회원은 토큰이 남아 있어도 재발급 거부(US0002).
- 이 제약이 문제 되면(보안 사고, 세션 관리 요구) DB 저장 방식 재검토 — 그때 ADR로.
엣지케이스 · gotcha
SameSite=Lax기본. FE와 API가 다른 사이트로 갈라질 때만None+Secure— 그리고 그 경우 CORS origin은 정확한 값만(와일드카드 불가). 로컬 HTTP는REFRESH_COOKIE_SECURE=false.- 오류 코드 분기:
AU0001(쿠키 없음, 401) vsAU0005(만료·서명 불량, 400) — HTTP status가 다르다는 점 주의.
관련 문서
- 전체 계약(스포크): auth-refresh-cookie-api.md