# Multi-Domain JWT 토큰 공유 분석 ## 현재 구조 진단 ### 도메인 구성 | 앱 | 도메인 | 포트(로컬) | |----|--------|-----------| | cs | `cs.onasys.co.kr` | 3000 | | as | `as.onasys.co.kr` | 3003 | | backend | 공통 1개 | 8000 | ### 핵심 문제 브라우저 쿠키는 **Same-Origin Policy** 적용: `cs.onasys.co.kr`에서 설정한 쿠키는 `as.onasys.co.kr`에서 **읽을 수 없음**. 현재 두 앱 모두 `NEXT_PUBLIC_COOKIE_DOMAIN` 환경변수가 **설정되지 않음** → 쿠키 `domain` 속성 없음 → 각 앱이 자기 도메인에만 쿠키 저장. ### 코드 흐름 분석 ``` authConfig.cookieDomain = process.env.NEXT_PUBLIC_COOKIE_DOMAIN (현재 undefined) ↓ token-manager.ts: getCookieDomain() → undefined 반환 ↓ setCookie(key, value, { domain: undefined, ... }) ← domain 없이 저장 ↓ 결과: cs.onasys.co.kr 쿠키 ≠ as.onasys.co.kr 쿠키 (공유 불가) ``` --- ## 해결 방법: Parent Domain Cookie ### 원리 쿠키 `Domain` 속성을 **부모 도메인**으로 설정하면 모든 서브도메인이 공유: ``` Domain=.onasys.co.kr → cs.onasys.co.kr ✅ 읽기/쓰기 가능 → as.onasys.co.kr ✅ 읽기/쓰기 가능 ``` --- ## 구현 방법 ### Step 1: 환경변수 추가 **apps/cs/.env.production** (또는 `.env.local` 배포용) ```env NEXT_PUBLIC_COOKIE_DOMAIN=.onasys.co.kr ``` **apps/as/.env.production** ```env NEXT_PUBLIC_COOKIE_DOMAIN=.onasys.co.kr ``` > [!IMPORTANT] > 반드시 앞에 `.` (점)을 붙여야 서브도메인 전체에 적용됩니다. ### Step 2: 코드 변경 불필요 `token-manager.ts`의 `getCookieDomain()`이 이미 `config.cookieDomain`을 사용하고 있으므로, 환경변수만 설정하면 됩니다. ```ts // packages/common/auth/token-manager.ts (현재 코드) const getCookieDomain = (): string | undefined => { if (typeof window === "undefined") return undefined; if (config.cookieDomain) return config.cookieDomain; // ← 이미 준비됨 return undefined; }; ``` ### Step 3: 백엔드 CORS 확인 백엔드가 `credentials: true`와 함께 올바른 `Access-Control-Allow-Origin`을 반환하는지 확인: ``` Access-Control-Allow-Origin: https://cs.onasys.co.kr (또는 as.onasys.co.kr) Access-Control-Allow-Credentials: true ``` > [!WARNING] > `Access-Control-Allow-Origin: *` 와 `credentials: true`는 동시에 사용 불가. > 명시적 도메인 또는 동적 오리진 허용 필요. --- ## SameSite 주의사항 현재 토큰 매니저 설정: ```ts setCookie(key, value, { secure: isHttps, sameSite: "lax", // ← 서브도메인 간 이동 시 쿠키 전송됨 (OK) domain, path: "/", }); ``` - `sameSite: "lax"` → 서브도메인 간 네비게이션에서 쿠키 전송 **가능** ✅ - `sameSite: "strict"` → 다른 도메인에서의 요청에 쿠키 미전송 ❌ - `sameSite: "none"` + `secure: true` → 크로스사이트 iframe 등에서도 전송 (필요 시) 배포 환경 HTTPS 사용 시 `secure: true` 자동 적용되므로 문제 없음. --- ## 세션 공유 흐름 (적용 후) ``` 사용자가 cs.onasys.co.kr 에서 로그인 ↓ setCookie("access-token", jwt, { domain: ".onasys.co.kr" }) ↓ 브라우저: .onasys.co.kr 쿠키 저장 ↓ 사용자가 as.onasys.co.kr 으로 이동 ↓ 브라우저가 자동으로 ".onasys.co.kr" 쿠키 전송 ↓ as 앱의 미들웨어: req.cookies.get("access-token") ✅ 정상 읽힘 ↓ 백엔드 API 호출 시 Authorization 헤더에 토큰 포함 ``` --- ## 추가 고려사항 ### 로그아웃 처리 한 앱에서 로그아웃 시 **도메인 지정 쿠키 삭제** 필요: ```ts // removeToken 에서 domain 이 자동 적용됨 (현재 코드 OK) removeCookie(key, { domain: ".onasys.co.kr", path: "/" }); ``` ### 토큰 갱신 (Refresh Token) `refresh-token` 쿠키도 같은 `domain` 설정 적용 → 두 앱 모두 silent refresh 가능. ### 로컬 개발 환경 로컬에서는 `localhost`가 서브도메인을 지원하지 않으므로 별도 처리 불필요 (`.env.local`에는 설정하지 않음). --- ## 최소 변경 요약 | 위치 | 변경 내용 | |------|----------| | `apps/cs/.env.production` | `NEXT_PUBLIC_COOKIE_DOMAIN=.onasys.co.kr` 추가 | | `apps/as/.env.production` | `NEXT_PUBLIC_COOKIE_DOMAIN=.onasys.co.kr` 추가 | | 소스 코드 | **변경 없음** (이미 cookieDomain 지원 구현됨) | | 백엔드 | CORS `Access-Control-Allow-Origin` 명시적 도메인 설정 확인 |