Next.js Middleware.ts에서 Set-Cookie가 즉시 적용되지 않는 문제: Route Handlers와 Middleware.ts 간 쿠키 동기화를 위한 ResponseCookies 활용

ClydeHan·2024년 12월 31일
4

nextjs cookie image

문제 상황

  • 미들웨어에서 엑세스 토큰이 만료되었을 경우를 처리하기 위해 다음과 같은 로직을 추가했다.
    1. 엑세스 토큰 확인: 미들웨어가 요청의 accesstoken 쿠키를 확인하여 유효한지 검사한다.
    2. 재발급 처리: 엑세스 토큰이 만료된 경우, 리프레쉬 토큰을 이용해 /api/v1/auth/refresh 엔드포인트로 새로운 엑세스 토큰을 요청한다.
    3. 요청 이어가기: 새로 발급받은 엑세스 토큰을 설정하여 원래 요청을 이어서 처리하도록 한다.
  • 그러나, 핸들러(/api/v1/auth/refresh)에서 Set-Cookie를 통해 새로운 엑세스 토큰을 설정했음에도, 이 값을 미들웨어에서 바로 읽지 못하는 문제가 발생했다.

문제의 원인

요청-응답 타이밍 문제

  • 핸들러(/api/v1/auth/refresh)는 브라우저에 "새로운 엑세스 토큰을 저장하라"는 명령(Set-Cookie)을 응답으로 보낸다.
  • 하지만, 브라우저가 이 명령을 처리하기 전에 미들웨어가 실행된다.
  • 결과적으로, 브라우저는 쿠키를 저장하지 않았고, 미들웨어가 요청 쿠키에서 새로운 토큰을 찾을 수 없었다.
  • 미들웨어는 요청이 서버로 도착할 때 실행되기 때문에 브라우저에 저장된 쿠키가 아닌, 핸들러의 응답 헤더에 포함된 Set-Cookie를 수동으로 읽어야 했다.

cookies() API의 한계

  • Next.js의 cookies() API는 요청 헤더에 포함된 쿠키만 읽는다.
  • 핸들러 응답의 Set-Cookie 헤더를 읽을 수 있는 기능이 없어, 새로 설정된 쿠키를 바로 활용할 수 없다.

해결 방법

ResponseCookies 활용

  • Next.js에서 제공하는 ResponseCookies 클래스를 사용하여 핸들러 응답의 Set-Cookie 헤더에서 쿠키를 추출한다.
  • 이를 통해 새로 설정된 쿠키 값을 미들웨어에서 직접 확인하고 사용할 수 있다.

코드 구현

  • 핸들러에서 쿠키를 설정한 후, 미들웨어가 핸들러 응답을 확인하여 Set-Cookie 헤더에서 쿠키 값을 추출한다.
  • ResponseCookies 클래스를 사용하여 응답 헤더의 쿠키를 파싱하고, 필요한 값을 가져온다.

코드 예시

핸들러 코드

  • 응답 헤더에 Set-Cookie 포함
const response = NextResponse.json({ message: 'Token refreshed' });
response.cookies.set('accesstoken', newAccessToken, {
  httpOnly: true,
  sameSite: 'strict',
  path: '/',
});
return response;

미들웨어 코드

  • Set-Cookie 헤더에서 새로 설정된 쿠키 추출
const response = await fetch(`${API_URL}/api/v1/auth/refresh`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    cookie: `refreshtoken=${refreshtoken.value}`,
  },
  credentials: 'include',
});

if (!response.ok) {
  return NextResponse.redirect(new URL('/login', request.url));
}

// Set-Cookie 헤더에서 새로 설정된 쿠키 추출
const resCookies = new ResponseCookies(response.headers);
const newAccessToken = resCookies.get('accesstoken')?.value;

if (newAccessToken) {
	console.log('새로운 액세스 토큰이 유효합니다. 요청 처리를 계속 진행합니다.');
  return NextResponse.next();
}

결론

  • 문제는 요청-응답 사이클에서 발생하는 동작 타이밍의 차이와 cookies() API의 한계에서 비롯되었다.
  • ResponseCookies를 사용하여 핸들러 응답의 Set-Cookie 헤더에서 직접 쿠키를 추출함으로써 문제를 해결했다.

참고 문헌

0개의 댓글