Files
frontend/docs/02.multi-domain-jwt.md
T

4.4 KiB

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 쿠키 (공유 불가)

원리

쿠키 Domain 속성을 부모 도메인으로 설정하면 모든 서브도메인이 공유:

Domain=.onasys.co.kr
  → cs.onasys.co.kr ✅ 읽기/쓰기 가능
  → as.onasys.co.kr ✅ 읽기/쓰기 가능

구현 방법

Step 1: 환경변수 추가

apps/cs/.env.production (또는 .env.local 배포용)

NEXT_PUBLIC_COOKIE_DOMAIN=.onasys.co.kr

apps/as/.env.production

NEXT_PUBLIC_COOKIE_DOMAIN=.onasys.co.kr

Important

반드시 앞에 . (점)을 붙여야 서브도메인 전체에 적용됩니다.

Step 2: 코드 변경 불필요

token-manager.ts의 getCookieDomain()이 이미 config.cookieDomain을 사용하고 있으므로, 환경변수만 설정하면 됩니다.

// 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 주의사항

현재 토큰 매니저 설정:

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 헤더에 토큰 포함

추가 고려사항

로그아웃 처리

한 앱에서 로그아웃 시 도메인 지정 쿠키 삭제 필요:

// 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 명시적 도메인 설정 확인