Next.js
로그인이 풀리는 문제를 쿠키 옵션부터 확인한 기록
HTTPS 배포 뒤 세션 쿠키가 저장되지 않던 문제를 SameSite, Secure, domain 순서로 점검했다.
시작은 이상한 재로그인 현상
관리자 페이지에서 글을 저장하면 로그인 화면으로 다시 튕겼다. API 응답은 200이었고 서버 로그에도 세션 생성 기록이 있었다. 그런데 브라우저 Application 탭을 열어 보니 쿠키가 아예 저장되지 않았다.
이때 백엔드 세션 로직만 계속 보면 시간이 오래 걸린다. 실제로는 Set-Cookie 헤더가 내려왔는데 브라우저가 조용히 거절하고 있었다.
브라우저가 거절한 이유 찾기
개발자 도구 Network 탭에서 로그인 요청을 클릭하고 Cookies 영역을 봤다. Chrome은 거절 사유를 꽤 자세히 보여 준다. 내 경우에는 HTTPS 페이지에서 내려온 쿠키였지만 옵션 조합이 애매했다.
서버에서 응답 헤더도 직접 확인했다.
curl -i https://example.com/api/login -H 'content-type: application/json' --data '{"password":"test"}'
문제의 쿠키는 대략 이런 모양이었다.
Set-Cookie: session=abc; Path=/; SameSite=None
SameSite=None을 쓰려면 Secure가 같이 있어야 한다. 로컬에서 HTTP로 테스트할 때는 다른 옵션을 쓰고, 운영에서는 HTTPS 기준으로 분기해야 했다.
고친 코드의 모양
Express 기준으로는 환경에 따라 옵션을 분리했다.
const isProd = process.env.NODE_ENV === 'production';
res.cookie('session', token, {
httpOnly: true,
secure: isProd,
sameSite: isProd ? 'none' : 'lax',
path: '/',
maxAge: 1000 * 60 * 60 * 24 * 7,
});
같은 사이트 안에서만 쓰는 관리자 쿠키라면 SameSite=Lax로 충분한 경우가 많다. 프론트와 API가 완전히 다른 도메인일 때만 None이 필요한지 다시 확인하는 편이 낫다.
점검표
로그인이 자꾸 풀릴 때 나는 이 순서로 본다.
- 로그인 응답에
Set-Cookie가 있는가 - 브라우저가 쿠키를 저장했는가
- 거절 사유가 Secure, SameSite, Domain 중 무엇인가
- API 요청에
credentials: 'include'가 빠지지 않았는가 - 서버 시간이 크게 틀어져 만료 시간이 이상해지지 않았는가
남은 교훈
세션 문제는 서버 코드만 봐서는 반쪽짜리다. 쿠키는 서버가 보낸다고 끝나는 값이 아니라 브라우저가 받아들여야 효력이 생긴다. 다음부터는 로그인 API가 성공했다는 로그보다 브라우저 쿠키 저장 여부를 먼저 확인하려고 한다.