docs: 인증을 쿠키 기반 JWT로 개정 + 인증 설계 문서(11) 신설 - #12
Conversation
- §1.1 Bearer 헤더 → HttpOnly·Secure·SameSite 쿠키, Refresh 쿠키 Path 제한, memberId 미반환 - §1.5 상태 코드 표에 403 추가 (CSRF 실패) - §1.7 CSRF 절 신설 (XSRF-TOKEN 쿠키 → X-XSRF-TOKEN 헤더) - §2.1 POST /me/agreements 제거 - §3.2 SIGNUP_REQUIRED·signupToken 분기 제거, 콜백에서 즉시 회원 생성 후 Set-Cookie - §3.3 약관 동의 절 삭제, 이후 절 번호 조정 - §3.3 재발급을 쿠키 기반으로 전환하고 동시 재발급 금지 명시 인증 Endpoint는 302·204이거나 본문이 없어 공통 응답 봉투(§1.6)가 적용되지 않는다는 점을 각 절에 명시했다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
API 명세 §3.2 개정(소셜 인증 성공 시점에 회원 생성)에 맞춰 약관 동의를 로그인 시작 이전으로 옮긴 결과를 반영한다. - 06 §8: "동의 완료 전 member를 생성하지 않는다" 확정 항목을 뒤집고, 동의 증빙 수단이 서버에 남지 않는다는 영향을 명시 - 09 §1: 가입 플로우에서 동의 분기 제거, 약관을 로그인 이전 단계로 이동 - 10, 02, 04: 약관 안내 시점 표현 정리 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
프론트엔드와의 소통을 위해 인증 결정의 근거와 클라이언트가 지켜야 할 계약을 한 곳에 모은다. Endpoint 형태는 08 API 명세를 참조한다. - IETF draft-ietf-oauth-browser-based-apps의 아키텍처 등급과 BFF 쿠키 요구사항 - XSS·CSRF 맞교환과 쿠키를 택한 이유 - 클라이언트 계약: withCredentials, CSRF 헤더, 응답 봉투 예외, 401 처리와 동시 재발급 금지, 로그인은 페이지 이동 - 검토했으나 채택하지 않은 대안 4가지와 이유 - 합의 필요 항목 4가지 (확정 시 해당 절 삭제) - README 문서 구조 표에 항목 추가 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
d2be694 to
630396b
Compare
infra의 Traefik 경로 라우팅 구성상 프론트와 API가 같은 오리진이므로 CORS와 SameSite=None이 불필요하다는 사실을 근거로 값을 확정한다. 08 API 명세: - §1.1 SameSite=Lax 명시, same-origin이라 CORS 불필요함을 기재 - §2.1·§3.5 GET /auth/session 신설 (200/401, 앱 시작 시 로그인 판단) - §3.2 복귀 경로를 /auth/callback으로 고정. 요청 파라미터로 받지 않는다 (open redirect 방지). 실패는 ?error= 부착 - §3.7 회원 탈퇴 상세 신설 — 정책 10장 기준 연쇄 소프트 삭제, provider_user_id·email 마스킹, 재가입 시 신규 회원 11 인증 설계: - 1장 결론 표에 확정값 3건 추가 - 5.2 앱 시작 흐름 추가 - 7장을 "합의 필요 항목"에서 "배포 오리진과 쿠키"로 교체. Strict가 아닌 Lax인 이유(공유 링크 진입 시 로그아웃으로 보이는 문제)와 로컬 개발 시 same-site·cross-origin 구분을 기재 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
[병합 전 필수]
[§7 합의 3건 — 프론트 의견]
|
문서 헤더는 `기본 경로: /api/core/`인데 3장 이후 Endpoint는 모두 `/api/core/v1`을 써서 어긋나 보였다. 실제로는 `/api/core`가 인프라가 고정한 서비스 context-path이고 `v1`은 그 뒤에 붙는 API 버전 세그먼트라 둘 다 맞다. 관계를 드러내도록 표기를 고친다. - 헤더에서 context-path와 API 버전을 각각 적고 합친 기본 경로를 명시 - 2장 목록의 Endpoint가 기본 경로 뒤에 붙는 상대 경로임을 안내 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PR #12 리뷰(TrossYou) 회신 반영. 로그인 상태 확인 (B안 채택): - GET /auth/session Endpoint를 철회하고 logged_in 표시 쿠키로 대체 - 08 §1.8 신설 — 쿠키 속성·발급·삭제 시점과 "UI 힌트 전용, 인가 판단 금지, 실제 인가는 서버가 매 요청 검증" 경고를 명시 - 콜백·재발급·로그아웃·탈퇴 각 절에 표시 쿠키 처리 추가 - 11 §5.2 앱 시작 흐름을 쿠키 기반으로 재작성 base URL: - 08 헤더에 "클라이언트 API base URL 환경변수에는 /api/core/v1을 넣는다" 명시. 본문 Endpoint 37곳은 이미 전부 /api/core/v1로 통일되어 있어 변경 없음 SameSite=Lax와 콜백 경로 /auth/callback은 프론트 의견과 일치하여 유지. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
@TrossYou 리뷰 반영했습니다. [병합 전 필수] 1 — base path 확인해보니 본문 Endpoint는 이미 37곳 전부
[병합 전 필수] 2 — 토큰 교환 폐기 명시 PR 본문 최상단에 경고 블록으로 넣었습니다. 기존/변경 후 비교표라 이전 문서를 본 사람도 바로 알아챌 수 있을 겁니다. §7 합의 3건
로그인 확인은 제가
쿠키 사양은 이렇습니다.
한 가지만 확인 부탁드립니다. 콜백 복귀 경로 |
|
콜백 경로 /auth/callback 그대로 갈게. 프론트에 이 라우트 추가할 예정이야. |
|
Important — Refresh 쿠키 §1.1과 §3.2에서 refresh 쿠키를 이렇게 좁힙니다: 그런데 §3.4 로그아웃은
해결안 두 가지 중 하나를 명시하면 됩니다:
🟡 Minor 3건
|
PR #12 리뷰(minyongP) 반영. Important — Refresh 쿠키 Path가 로그아웃·탈퇴를 막던 문제: - Path를 /api/core/v1/auth/refresh → /api/core/v1/auth 로 확대. 로그아웃이 Refresh 쿠키 범위에 들어와 대상 토큰을 특정할 수 있다. 일반 API(/records 등)에는 여전히 실리지 않는다 - §3.4 로그아웃 — Refresh 쿠키로 해당 세션만 무효화. Access가 만료돼도 동작하며, Refresh가 없거나 무효해도 204(이미 로그아웃된 상태를 오류로 취급하지 않는다) - §3.6 탈퇴 — /me는 Refresh 쿠키 Path 밖이므로 Access로 회원을 식별해 해당 회원의 Refresh를 전부 무효화. 모든 기기 로그아웃이 의도된 동작 Minor: - §3.3 재발급 200 → 204. §1.6의 "본문 없는 성공은 204" 규정과 정합 - §3.2 Set-Cookie 예시에 HttpOnly·Secure·SameSite 속성을 실제로 표기 (참조만 두면 예시를 복붙할 때 놓친다) CSRF 403·401을 Security 필터가 직접 쓰는 건 문서 결함이 아니라 구현 의무이므로(back error-handling.md에 명기됨) 문서는 그대로 둔다. 콜백 경로 /auth/callback은 프론트 확정 회신을 받아 변경 없음. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
@minyongP Important — Refresh 쿠키 Path1번(Path 확대)을 택하되, 탈퇴는 2번 방식으로 나눴습니다. 1번만으로는
로그아웃 — Refresh 쿠키로 대상을 특정하므로 지적하신 "Access 만료 상태에서 로그아웃" 문제가 사라집니다. Refresh만 있으면 되니까요. 그리고 해당 세션 하나만 무효화하도록 명시했습니다. 다른 기기 로그인은 유지됩니다. Refresh 쿠키가 없거나 이미 무효한 경우에도 204입니다 — 이미 로그아웃된 상태를 오류로 취급하면 클라이언트가 처리할 게 늘어나기만 합니다. 탈퇴 — Access로 회원을 식별해 그 회원의 Refresh를 전부 무효화합니다. 탈퇴는 모든 기기에서 즉시 끊겨야 하므로 전체 무효화가 오히려 맞는 동작입니다. Access가 만료됐으면 401이고, 클라이언트는 평소처럼 재발급 후 재시도합니다. Minor1. 재발급 2. CSRF 403·401을 Security 필터가 직접 쓰는 건 — 말씀대로 문서 결함이 아니라 구현 의무라 문서는 그대로 뒀습니다. 3.
@TrossYou 콜백 경로 확정 감사합니다. |
요약
인증을 쿠키 기반 JWT로 개정하고, 그 결정 근거를 담은
11_인증_설계.md를 신설합니다. 관련 문서 5개의 정합성도 함께 맞췄습니다.배경
BFF와 리소스 서버를 한 서버로 운영하기로 하면서 토큰 전달 방식을 다시 정했습니다. IETF
draft-ietf-oauth-browser-based-apps는 아키텍처를 "decreasing order of security"로 나열하며 BFF를 개인 데이터를 다루는 애플리케이션에 "strongly recommended"로 두고, BFF 쿠키에Secure·HttpOnly를 MUST로 요구합니다. PinLog은 개인의 장소 기록과 위치 데이터를 다루므로 여기에 해당합니다.약관 동의는 클라이언트가 로그인 시작 이전 화면에서 전담하기로 하여 서버 API가 없어졌습니다.
변경 내용
1.
11_인증_설계.md신설 — 프론트엔드 소통용결정의 근거와 클라이언트가 지켜야 할 계약을 한 곳에 모았습니다. 구현 세부는 담지 않았습니다.
withCredentials, CSRF 헤더, 응답 봉투 예외, 401 처리와 동시 재발급 금지(single-flight), 로그인은 페이지 이동Lax를 고른 이유, 로컬 개발 주의2.
08_API_명세.md개정/api/core)와 API 버전(v1) 분리 표기. 클라이언트 base URL 환경변수 값은/api/core/v1HttpOnly+Secure+SameSite=Lax쿠키. Refresh 쿠키Path제한.memberId미반환403추가 (CSRF 실패)XSRF-TOKEN쿠키 →X-XSRF-TOKEN헤더logged_inPOST /me/agreements제거SIGNUP_REQUIRED·signupToken분기 제거. 콜백에서 즉시 회원 생성 후Set-Cookie+ 3023. #11(공통 응답 봉투)과의 조정
traceId추가분 폐기 — docs(S15P11A705-54): API 명세에 공통 응답 봉투 형식 반영 #11 쪽 설명을 그대로 사용/api/core는 인프라 고정 context-path,v1은 API 버전 세그먼트로 둘 다 맞습니다. 관계가 드러나도록 헤더를 나눴습니다4. 확정한 값
infra/docs/backend-conventions.md의 Traefik 경로 라우팅상 프론트와 API가 same-origin이라는 사실이 대부분을 결정했습니다.SameSiteLax/auth/callback, 실패 시?error=OAUTH_FAILED/api/core/v1logged_in표시 쿠키5. 정합성 맞춘 문서
06_데이터모델_및_무결성.md§8 — "동의 완료 전member를 생성하지 않는다"가 확정으로 박혀 있어 정면 충돌했습니다. 뒤집었습니다09_유저플로우.md§1 — 가입 다이어그램에서 동의 분기 제거, 약관을 로그인 이전으로 이동10_MVP_기능범위.md·02_정책_정의서.md·04_익명SNS_공개정책.md— 약관 안내 시점 표현 정리README.md문서 구조 표에11추가리뷰 회신 반영 (@TrossYou)
VITE_API_BASE_URL값 확정/api/core/v1이었고, 헤더 한 줄만/api/core라 어긋나 보였습니다. 둘의 관계를 헤더에 명시하고 환경변수에는/api/core/v1을 넣는다는 문장을 추가했습니다Lax/auth/callback(+?error=OAUTH_FAILED)GET /auth/session을 철회하고logged_in쿠키로 대체(§1.8). "UI 힌트 전용 / 인가 판단 금지 / 실제 인가는 서버가 매 요청 검증"을 인용 블록으로 강조했고,11§5.2에도 같은 경고를 넣었습니다남은 리뷰 항목
1.
02·04는 정책 문서라 소유가 다릅니다기획 담당 확인을 부탁드립니다. 결정된 흐름에 맞춰 문장만 정리했고 새로운 정책 판단을 넣지는 않았습니다.
2. 법적 리스크
"진행하면 동의한 것으로 간주"는 필수 약관, 특히 개인정보 수집·이용 동의에 대해 명시적 동의를 원칙으로 하는 국내 법제와 어긋날 소지가 있습니다. 또한 서버에 동의 기록이 남지 않아 증빙 요구에 대응할 수단이 없습니다.
06§8에 이 영향을 적어뒀습니다. 이 PR은 결정된 흐름을 반영한 것이고, 결정 자체의 타당성은 별도 판단이 필요합니다.🤖 Generated with Claude Code