배꼽파지 않도록 잘 개발해요

[Node.js] 서버에서 로그아웃시 HttpOnly 쿠키 브라우저에서 삭제하는 방법 본문

BackEnd/Node.js

[Node.js] 서버에서 로그아웃시 HttpOnly 쿠키 브라우저에서 삭제하는 방법

꼽파 2024. 10. 24. 11:04

벌써 프로젝트가 1차적으로 마무리되었다.
우리 서버는 NestJS 프레임워크를 사용하여 express-session과 connect-redis, passport를 통해 세션 인증을 사용하고 있다.
이전 프로젝트에서 토큰만 사용해봐서 쿠키와 세션을 사용하는 것이 굉장히 낯설었다.
프로젝트 시행착오의 70%는 인증 쪽이고, 30% TypeORM 쪽이다.

 

https://programming-bellybutton.tistory.com/215

 

[중간이들] NestJS 세션 로그아웃 구현 중 쿠키 문제 해결 과정

NestJS 서버에서 express-session과 passport, connect-redis를 사용하여 세션 로그인을 구현하였다.API를 점검하는 도중에 로그아웃에 문제가 있는 것을 발견하였다.어제 몇 시간 동안 테스트한 결과, 자잘한

programming-bellybutton.tistory.com

 

지난 시간에 이런 글을 올린 적이 있다.

브라우저에서 쿠키가 삭제되지 않는다는 글을 올린 적 있는데, 이것은 반쪽만 해결한 글이었다.

며칠 뒤에 완전히 해결되어서 블로그에 글을 쓴다하는게 벌써 한 달 넘는 시간이 지나갔다.

 

쿠키 브라우저에서 삭제되는 옵션은 expires: 과거 날짜, maxAge: 0

결론부터 말하면 쿠키 전송할 때 옵션과 삭제할 때 옵션을 각각 따로 생성하여, 

삭제할 때는 expires에 과거 날짜로, maxAge는 0으로 지정하면 해결이 되었다.

 

주의할 점은 다른 옵션들은 쿠키 전송할 때 사용하였던 것을 그대로 지정해줘야한다는 것이다.

 

send-cookie-options.ts

import { CookieOptions } from 'express';

const commonOptions = {
  domain: process.env.COOKIE_DOMAIN,
  httpOnly: true,
};

const sendCookieOptions = (): CookieOptions => {
  // 배포환경
  if (process.env.NODE_ENV === 'production') {
    return {
      ...commonOptions,
      secure: true,
      sameSite: 'none',
      maxAge: 2 * 60 * 60 * 1000, // 2시간 (세션 유효기간)
    };
    // 개발환경
  } else {
    return {
      ...commonOptions,
      secure: false,
      sameSite: 'lax',
      maxAge: 24 * 60 * 60 * 1000, // 24시간
    };
  }
};

export { sendCookieOptions };

 

clear-cookie-options.ts

import { CookieOptions } from 'express';
import { sendCookieOptions } from './send-cookie-options';

const clearCookieOptions = (): CookieOptions => {
  const options = sendCookieOptions();
  return {
    ...options,
    expires: new Date(Date.now() - 1000), 
    maxAge: 0,
  };
};

export default clearCookieOptions;

 

이렇게 하면 로그아웃시 쿠키가 브라우저에서 완전히 사라진다.

 


1. 서버에서의 쿠키 옵션 세팅

쿠키 전송할 때는 배포환경과 개발환경의 옵션을 다르게 하였다.

옵션이 조금만 맞지 않아도 쿠키가 브라우저에 들어오지 않는다.

  개발 환경 배포 환경
secure false true
samesite 'lax' 'none'
domain '.localhost' 구매한 도메인

domain의 경우 만약 caugannies.com이 구매한 도메인이라면 '.caugannies.com' 혹은 'caugannies.com'으로 적어줄 수 있다.

그럼 subdomain.caugannie.com인 모든 도메인에서 이 쿠키를 받을 수 있다는 의미가 된다.

https://ko.javascript.info/cookie


2. 쿠키가 잘 들어오지 않을 때 판단 가이드

  • 브라우저에서 third-party cookie를 차단하였다, 쿠키 이슈가 있어서 blocked 되었다는 경고문이 보인다
  • 쿠키 흔적 자체가 보이지 않는다

위와 같은 경우에는 무조건 서버에서 쿠키 옵션 세팅을 잘 했는지부터 점검을 해야한다.


3. 프론트엔드와 서버에서 CORS와 withCredentials 옵션 설정

1) 서버의 CORS 옵션과 withCredentials 옵션

쿠키를 전송하는 서버에서 허용 가능한 도메인을 적어주고, cors 설정에서 credentials: true를 적어준다.

 

2) 쿠키를 전송해야하는 프론트엔드 쪽에서도 withCredentials: true 옵션을 써준다.

  • fetch의 경우 'credentials: include'
  • axios의 경우 'withCredentials: true'
fetch(url, {
  method: 'GET',
  credentials: 'include'
});
axios.get(url, { withCredentials: true });


Cookie 결론 요약

  1. 쿠키를 전송할 때와 삭제할 때의 옵션을 다르게 해준 후, httpOnly 쿠키의 경우 삭제시에 maxAge: 0, expires: 과거 시간을 지정해주면 브라우저에 있는 쿠키가 삭제된다.
  2. 아래에 적어 놓은 것을 다 세팅하고 점검해야 쿠키가 제대로 들어온다.
  • 서버의 쿠키 옵션 설정 (로컬과 배포환경에서의 옵션이 다름)
  • 서버의 CORS 설정
  • 프론트엔드와 서버에서 withCredentials: true 설정
728x90