세션 관리 및 로그아웃 연동 가이드 (웹 프런트엔드)
본 문서는 Kakao OAuth 로그인 이후 SleepZ 웹 프런트엔드에서 세션 유지, 토큰 갱신, 로그아웃, 소셜 연결 해제를 처리하는 방법을 정의합니다. 2025년 게스트 계정 도입으로 identityLevel=GUEST 세션이 추가되었으며, Step-up 흐름과의 연계는 게스트 계정 연동 가이드를 참고하세요. 기본 도메인 규칙은 다음을 참조하세요.
/domains/common/core-domains/auth/endpoints.md/domains/kr/core-domains/auth/endpoints.md/domains/kr/core-domains/auth/business-rules.md
1. 용어
- Access Token: 사용자의 인증 상태를 나타내는 JWT. HttpOnly 쿠키(
sleepz_access_token)에 저장. - Refresh Token: Access Token 갱신 용도의 JWT. HttpOnly 쿠키(
sleepz_refresh_token)에 저장,/auth/refresh경로에 한정. - Session TTL: Access Token은 1시간, Refresh Token은 30일 유효(도메인 기본값). TimeMachine 시계를 기준으로 판단.
2. 관련 엔드포인트 요약
| 기능 | HTTP | 엔드포인트 | 인증 | 비고 |
|---|---|---|---|---|
| 토큰 갱신 | POST | /auth/token/refresh | Refresh JWT 쿠키 | Access/Refresh 재발급 |
| 토큰 검증 | POST | /auth/token/validate | Access JWT | 클라이언트 세션 확인용 |
| 로그아웃 | POST | /auth/logout | Access JWT | Refresh 토큰 폐기, 쿠키 삭제 |
| Kakao 연결 해제 | POST | /auth/oauth/kakao/unlink | Access JWT + CSRF | 사용자가 요청한 경우만 |
| 게스트 세션 정보 | GET | /users/me | Access JWT | accountType, identityLevel 제공 |
3. 토큰 갱신 흐름
3.1. 호출 조건
- 라우트 보호용 미들웨어(Server Components 또는 Route Handler)에서 Access Token 만료 (
401 AUTH_TOKEN_EXPIRED) 가 감지된 경우. - 백엔드 규칙상 Refresh 시도는 만료 5분 전 1회만 허용되므로, 프런트는 중복 호출을 피하기 위해 Promise 캐싱 또는 상태 플래그를 사용.
3.2. 요청/응답
- 요청: 바디 없음. Refresh 쿠키 자동 첨부.
- 성공 응답 (
200)
{
"accessToken": "new-access-jwt",
"refreshToken": "new-refresh-jwt",
"expiresIn": 3600
}
- Set-Cookie
sleepz_access_token=...; HttpOnly; Secure; SameSite=Strictsleepz_refresh_token=...; HttpOnly; Secure; SameSite=Strict
- 오류
401 AUTH_REFRESH_TOKEN_EXPIRED: Refresh 만료 →/login리다이렉트400 AUTH_REFRESH_SESSION_LOCKED: 동시 세션 제어 → 재로그인 유도
3.3. 구현 노트
- Next.js 15 App Router에서 서버 액션 또는 Route Handler(
app/api/auth/refresh/route.ts)로 래핑하여 호출. - 로컬 컴포넌트에서는
fetch("/auth/token/refresh", { method: "POST", credentials: "include" })형태 사용. - Refresh 중 기존 요청은 큐잉 또는 재시도 전략을 적용.
4. 세션 검증
- 초기 렌더링 시
POST /auth/token/validate호출로 Access Token 유효성 체크 가능하며, 응답의identityLevel필드로 게스트 여부를 판별한다. - 응답 예시:
{
"subject": "user-uuid",
"identityLevel": "GUEST",
"expiresAt": "2025-01-20T11:30:00.000Z",
"roles": ["ROLE_OPERATOR"]
}
401 AUTH_TOKEN_INVALID→ Refresh 시도 후 실패 시/login.- Server Component에서는
cookies().get("sleepz_access_token")여부를 우선 확인하되, 직접 JWT 파싱 금지(도메인 규칙 위배).
5. 로그아웃 처리
5.1. 요청
POST /auth/logout
Authorization: Bearer <access>
X-CSRF-Token: <csrf>
- 바디는 선택적으로
{"reason":"USER_REQUEST"}필드 허용 (분석 용도). - 성공 시
204 No Content, 쿠키 삭제 헤더(Set-Cookie: ...; Max-Age=0) 응답. - 가장 빠른 UX를 위해 로그아웃 요청은
POSTfetch 후,/login으로 클라이언트 이동.
5.2. 프런트 UX 요구사항
- 사용자에게 "로그아웃하시겠습니까?" 확인 모달 제공.
- 성공 메시지: "정상적으로 로그아웃되었습니다."
- 실패 시 (예: 네트워크 오류) “세션 종료에 실패했습니다. 다시 시도해주세요.” 토스트 노출 후 상태 유지.
6. 단일 세션 정책
- SleepZ 웹은 동시에 하나의 활성 세션만 허용한다. 사용자가 새로운 브라우저/디바이스에서 로그인하면 기존 Refresh 토큰과 세션은 즉시 폐기된다.
- 기존 세션에서 API 호출 시
401 AUTH_REFRESH_TOKEN_EXPIRED또는400 AUTH_REFRESH_SESSION_LOCKED가 반환될 수 있으므로, 프런트는 "다른 기기에서 로그인되어 세션이 종료되었습니다."와 같은 메시지를 노출하고 로그인 페이지로 이동시켜야 한다. /v1/auth/sessions등 다중 세션 조회/종료 API는 웹 프런트엔드에서 호출하지 않는다. 필요한 경우 운영 도구에서만 사용한다.
7. 게스트 세션 추가 고려 사항
- 오류 코드 매핑
409 AUTH_GUEST_LINK_CONFLICT: Step-up 동시 요청. 사용자에게 잠시 후 재시도 또는 새 창 이용 안내.409 AUTH_GUEST_ACCESS_DENIED: 제한 기능 접근. 잠금 UI와 Step-up 유도 메시지 노출.
GET /users/me응답의groupIds에patients.guest.*패턴이 포함된 경우에만 게스트 UX 배너를 렌더링하고, Step-up을 유도한다. (v1.2.0부터 IAM Group 기반 식별 권장)- 게스트 세션 로그아웃 완료 메시지는 “게스트 체험이 종료되었습니다.”로 분기하고, 재온보딩 또는 정식 회원가입 CTA를 함께 제공한다.
- 다중 탭에서 Step-up 완료 이벤트를 동기화하기 위해
storage이벤트 또는 Broadcast Channel을 사용한다.
8. Kakao 연결 해제 (선택 기능)
- 엔드포인트:
POST /auth/oauth/kakao/unlink - 요청 바디:
{
"reason": "USER_REQUEST"
}
- 성공 응답:
{
"status": "unlinked",
"unlinkedAt": "2025-01-20T10:40:00.000Z"
}
- 프런트 처리:
- 성공 후 즉시
/login이동 또는 "계정 연결이 해제되었습니다." 안내. - 만약 이후 동일 계정으로 재연결 필요 시 로그인 플로우를 다시 수행.
- 성공 후 즉시
- 오류 코드:
403 AUTH_CSRF_TOKEN_MISSING: CSRF 헤더 누락 → 재시도409 AUTH_KAKAO_NOT_LINKED: 연결된 Kakao 계정 없음 → UI에서 버튼 비활성화 고려
9. CSRF 및 보안 헤더
X-CSRF-Token은 Next.js 서버에서 생성한 값을 쿠키(sleepz_csrf_token)와 헤더로 함께 전송해 검증.- 로그아웃과 unlink 요청은 반드시 CSRF 헤더를 포함해야 하며, fetch 요청 시
credentials: "include"설정. - 모든 시간 필드는 TimeMachine 기준으로 반환되므로, UI 표시 시 사용자 시간대 변환이 필요할 수 있음. Step-up 관련 안내에서도 동일한 규칙을 적용한다.
10. 테스트 체크리스트
- Access Token 만료 시
POST /auth/token/refresh호출로 세션 연장되는지 확인. - Refresh 만료(
401 AUTH_REFRESH_TOKEN_EXPIRED) 후 로그인 페이지로 리다이렉트 되는지 검증. - 로그아웃 성공 시 쿠키 삭제 및 보호된 페이지 접근 차단 여부 확인.
- CSRF 토큰 누락 상태에서 요청 시 403 응답이 발생하는지 테스트.
- Kakao unlink 후 재로그인 시 신규 연결 흐름이 정상 작동하는지 확인.
- 게스트 세션에서 제한 기능 접근 시
AUTH_GUEST_ACCESS_DENIED응답을 사용자 메시지로 매핑하는지 확인. - 게스트 Step-up 완료 후 기존 탭이 자동 로그아웃되지 않고 정규 세션으로 갱신되는지 검증.
11. 향후 TODO
- 단일 세션 종료 시 사용자 안내 문구/토스트 표준화
- Refresh 자동화 훅(React Query/ SWR) 공통 유틸 제공
- 로그아웃 후 남은 비공개 캐시(React Query 등) 초기화 패턴 문서화
- 게스트 온보딩·Step-up 오류 코드 시나리오를 포함한 Playwright 회귀 테스트 통합