Files
sam-docs/frontend/v1/07-auth-flow.md
유병철 8f939d3609 docs: [frontend] 프론트엔드 아키텍처/가이드 문서 v1 작성
- _index.md: 문서 목록 및 버전 관리
- 01~09: 아키텍처, API패턴, 컴포넌트, 폼, 스타일, 인증, 대시보드, 컨벤션
- 10: 문서 API 연동 스펙 (api-specs에서 이관)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:24:25 +09:00

4.9 KiB

07. 인증 흐름

대상: 프론트엔드/백엔드 개발자 버전: 1.0.0 최종 수정: 2026-03-09


1. 인증 아키텍처 요약

┌─────────────────────────────────────────────────────┐
│ 브라우저                                              │
│                                                      │
│  [React 컴포넌트]                                     │
│       │ fetch('/api/proxy/...')                       │
│       │ (토큰 전송 안함 — 쿠키가 자동 포함)              │
│       ▼                                              │
│  [Next.js API Proxy]                                 │
│       │ 쿠키에서 access_token 읽기                     │
│       │ Authorization: Bearer {token} 헤더 추가        │
│       ▼                                              │
│  [authenticatedFetch 게이트웨이]                       │
│       │ 401 → refresh → retry (자동)                  │
│       ▼                                              │
│  [PHP Laravel Backend]                               │
│                                                      │
│  쿠키:                                                │
│  ├── access_token  (HttpOnly, 2시간)                  │
│  ├── refresh_token (HttpOnly, 7일)                    │
│  └── is_authenticated (non-HttpOnly, 상태 확인용)      │
└─────────────────────────────────────────────────────┘

2. 왜 HttpOnly 쿠키?

방식 XSS 취약 토큰 갱신 SAM 채택
localStorage 취약 (JS 접근 가능) 직접 구현
일반 쿠키 취약 (JS 접근 가능) 직접 구현
HttpOnly 쿠키 안전 (JS 접근 불가) 프록시에서 처리
  • JavaScript로 토큰을 읽을 수 없음 → XSS 공격에 안전
  • 대신 서버(Next.js 프록시)에서만 읽기 가능 → 프록시 패턴 필수

3. 로그인 흐름

1. 사용자 → 로그인 폼 입력 (email, password)
2. 프론트 → POST /api/proxy/auth/login { email, password }
3. 프록시 → POST /api/v1/auth/login (Laravel)
4. Laravel → { access_token, refresh_token, expires_in }
5. 프록시 → Set-Cookie 3개 설정:
   - access_token=xxx;  HttpOnly; Max-Age=7200
   - refresh_token=xxx; HttpOnly; Max-Age=604800
   - is_authenticated=true; Max-Age=7200
6. 프론트 → 대시보드로 이동

4. API 호출 시 토큰 흐름

1. 컴포넌트 → Server Action 호출 (또는 fetch /api/proxy/...)
2. Server Action → serverFetch → authenticatedFetch
   - 쿠키에서 access_token 읽기
   - Authorization: Bearer {token} 헤더 추가
3. 백엔드 응답:
   - 200 OK → 정상 처리
   - 401 → 토큰 만료 (아래 갱신 흐름)

5. 토큰 갱신 (자동)

1. API 호출 → 401 Unauthorized 응답
2. authenticatedFetch 감지:
   a. refresh_token으로 POST /api/v1/auth/refresh
   b. 새 access_token 발급
   c. 새 토큰으로 원래 요청 재시도 (1회)
3. 결과:
   - 재시도 성공 → 정상 응답 + 새 쿠키 설정
   - 재시도 실패 → 쿠키 삭제 + 로그인 페이지 이동

중요: 동시에 여러 요청이 401을 받으면, refresh는 1번만 실행 (globalThis 캐싱으로 중복 방지)


6. 미들웨어 (middleware.ts)

요청 단계에서의 인증 검사 (토큰 갱신과는 별개):

요청 들어옴
  ↓
1. 내부 요청 필터링 (_next/*)
2. IE 브라우저 차단
3. 다국어 처리 (ko, en)
4. /dev/ 경로 프로덕션 차단
5. 봇 탐지 (40+ 패턴 차단)
6. API/정적 파일 통과
7. 인증 확인:
   - 비인증 사용자 → 로그인 페이지 리다이렉트
   - 인증된 사용자가 로그인 페이지 접근 → 대시보드 리다이렉트
8. 보안 헤더 설정 (X-Robots-Tag, CSP 등)

7. 프론트엔드 개발자 체크리스트

항목 설명
직접 토큰 관리 금지 localStorage/sessionStorage에 토큰 저장
fetch 직접 호출 금지 Server Action 또는 /api/proxy/ 경로만 사용
인증 상태 확인 is_authenticated 쿠키 (non-HttpOnly) 또는 useAuthGuard()
401 처리 authenticatedFetch가 자동 처리 — 수동 처리 불필요

8. 백엔드 개발자 참고

항목 내용
인증 방식 Bearer Token (Authorization 헤더)
토큰 발급 POST /api/v1/auth/login
토큰 갱신 POST /api/v1/auth/refresh
401 응답 시 프론트가 자동 refresh → retry
API Key X-API-KEY 헤더 (환경변수: API_KEY)