본문 바로가기

TroubleShooting

외부 API 연동 시 세션(loginInfo) 초기화 현상

반응형

1. 증상

  • 발생 시점: 외부 장비 조회 API를 호출한 뒤 페이지 새로고침
  • 증상: 로그인 정보(loginInfo)가 사라지고 로그인 페이지로 리다이렉트됨
  • 특이사항: 장비 조회 직후에는 화면상 loginInfo가 유지되어 보이고, 새로고침 후에만 세션이 없는 것처럼 동작

2. 원인

2.1 요약

외부 API(프록시 경유) 응답에 포함된 Set-Cookie 헤더가 우리 도메인으로 전달되면서, 기존 세션 쿠키가 덮어쓰이거나 제거됨.

2.2 상세

  1. 프론트에서 장비 조회 시 같은 오리진으로 요청을 보냄
    • 예: https://our-domain.com/api/external/...
    • 이 요청은 Nginx(Vite 프록시 등)를 통해 외부 API로 프록시됨
    • 예: https://api.example-external.go.kr/...
  2. 외부 API가 응답 시 Set-Cookie 헤더를 포함할 수 있음
    • 해당 API가 세션/추적용 쿠키를 설정하는 경우
  3. 프록시가 응답을 그대로 클라이언트에 전달하면, 브라우저 입장에서는
    • 응답이 우리 도메인(our-domain.com)에서 온 것으로 인식하고
    • Set-Cookie우리 도메인에 적용
  4. 그 결과
    • 우리 앱의 세션 쿠키(예: ADMIN_SESSION_ID)가
    • 외부 API에서 내려준 쿠키로 덮어쓰이거나 영향받아
    • 이후 요청에서 세션이 유효하지 않게 됨
  5. 새로고침 시
    • 앱이 /auth/.../loginInfo 등 세션 기반 API를 다시 호출하고
    • 이미 세션 쿠키가 바뀐 상태이므로 서버가 세션을 찾지 못해
    • loginInfo가 비어 있는 것처럼 보이고 로그인 페이지로 보내짐

2.3 왜 장비 조회 직후에는 괜찮아 보였나?

  • 직후에는 메모리 상의 Redux 상태에 이전에 불러온 loginInfo가 남아 있어서 화면에는 그대로 보임
  • 실제로는 쿠키는 이미 변경된 상태이고, 새로고침으로 앱이 다시 로드되면서 서버에 세션 요청을 보낼 때 문제가 드러남

3. 해결 방법

3.1 프록시에서 외부 API 응답의 Set-Cookie 제거 (권장)

외부 API 응답을 클라이언트로 넘기기 전에 Set-Cookie 헤더를 제거합니다.
우리 앱은 해당 외부 API의 쿠키가 필요하지 않으며, 제거해도 장비 조회 기능에는 영향이 없습니다.

(1) Vite 개발/프리뷰 환경

vite.config.ts의 해당 프록시에 configure를 추가합니다.

// 예시: /api/external/ 로 들어오는 요청을 외부 API로 프록시하는 경우
"/api/external/": {
  target: "https://api.example-external.go.kr/",
  changeOrigin: true,
  rewrite: (path) => path.replace(/^\/api\/external/, ""),
  secure: true,
  ws: true,
  configure: (proxy) => {
    proxy.on("proxyRes", (proxyRes) => {
      delete proxyRes.headers["set-cookie"];
      delete proxyRes.headers["set-cookie2"];
    });
  },
},
  • 의미: 외부 API 응답의 Set-Cookie를 제거한 뒤 클라이언트에 전달
  • 적용 범위: npm run dev, npm run preview 등 Vite가 프록시를 처리하는 환경

(2) Nginx (운영/스테이징)

해당 location 블록 안에 다음 한 줄을 추가합니다.

location /api/external/ {
    proxy_ssl_server_name on;
    proxy_pass https://api.example-external.go.kr/;

    proxy_set_header Host api.example-external.go.kr;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Port $server_port;

    # 외부 API 응답의 Set-Cookie를 클라이언트에 전달하지 않음
    proxy_hide_header Set-Cookie;
}
  • 의미: upstream(외부 API) 응답의 Set-Cookie를 숨겨서 클라이언트로 내려보내지 않음
  • 적용 후: nginx -t 로 문법 확인 후 nginx -s reload 로 반영

3.2 프론트엔드: 외부 API 요청에 쿠키 미전송 (보조)

해당 외부 API 호출 시 쿠키를 보내지 않도록 설정하면,
우리 세션 쿠키가 외부로 나가지 않고, 응답으로 받는 쿠키에 의한 덮어쓰기 가능성도 줄일 수 있습니다.

// 예: axios 사용 시
const response = await axios.get(requestUrl, {
  params: requestParams,
  withCredentials: false,  // 쿠키 미전송
});
  • 주의: withCredentials: false만으로는 응답의 Set-Cookie가 브라우저에 적용되는 것을 막지 못할 수 있음.
    따라서 3.1(프록시에서 Set-Cookie 제거) 를 함께 적용하는 것이 안전합니다.

4. 확인 방법

  1. 로그인 후 장비 조회(외부 API 호출) 실행
  2. 새로고침(F5 또는 페이지 리로드)
  3. 기대 결과: 로그인 상태 유지, loginInfo 정상 노출
  4. (선택) 브라우저 개발자 도구 → Application → Cookies 에서
    우리 도메인의 세션 쿠키(예: ADMIN_SESSION_ID)가
    장비 조회·새로고침 후에도 그대로 있는지 확인

5. 참고 사항

  • 외부 API 쿠키: 장비 조회용 공개 API는 인증이 필요 없으므로, 응답의 Set-Cookie는 해당 서비스의 세션/추적용일 가능성이 큼. 우리 쪽에서 제거해도 기능상 문제 없음.
  • 운영 반영: Nginx 등 실제 서비스 프록시에서도 동일하게 proxy_hide_header Set-Cookie 적용 필요.
  • 다른 외부 API: 비슷하게 같은 오리진으로 프록시하는 외부 API가 있다면, 동일한 방식으로 Set-Cookie 제거를 검토하는 것이 좋음.

반응형