Javascript/NuxtJS

[Nuxt3] Next-Auth 사용 시 쿠키 중복 및 SSR 처리 주의사항

kyoulho 2025. 5. 27. 16:42

문제 상황

Nuxt3와 Next-Auth를 함께 사용할 때, 서버 사이드 렌더링(SSR) 과정에서 useAuth().getSession()을 호출하면 매번 새로운 set-cookie 헤더가 응답에 추가됩니다. 특히 아래와 같은 상황에서 문제가 심각해집니다:

  • 다수의 API 호출: SSR 중 여러 컴포넌트가 각각 getSession()을 호출하는 경우
  • 헤더 크기 제한 초과: HTTP 쿠키 헤더 전체 크기가 일반적으로 4KB를 넘으면 브라우저가 쿠키를 거부하거나 잘라냅니다.
  • 중복 세션 쿠키: 동일한 세션 쿠키가 반복 삽입되어, 실제 필요한 쿠키 외에 불필요한 메타 정보가 헤더에 포함됩니다.

결과적으로 SSR 중 렌더링이 실패하거나, 클라이언트에 쿠키가 제대로 전달되지 않는 현상이 발생할 수 있습니다.


원인 분석

  • 클라이언트 전용 함수 사용: useAuth().getSession()은 Next-Auth가 클라이언트 렌더링 시에만 세션 쿠키를 관리하도록 설계된 함수입니다.
  • SSR에서의 세션 갱신: 서버에서 호출할 때마다 세션 유효성을 재검증하며 set-cookie를 통해 갱신된 쿠키를 응답에 포함합니다.
  • 헤더 누적: 여러 컴포넌트나 미들웨어에서 중복 호출 시, 이전 호출의 쿠키까지 다시 쌓이게 됩니다.


중요한 맥락

Nuxt의 composables는 실행 환경이 서버인지 클라이언트인지 미리 알 수 없습니다. 클라이언트에서 실행될 경우 서버 이벤트 핸들러에서 세션 쿠키를 문제없이 반환하지만, 서버에서 실행되는 경우 Next-Auth의 세션 쿠키가 없어서 null이 반환됩니다.

이 때문에 서버에서 실행될 때는 요청에 세션 쿠키 헤더를 직접 설정하여 이벤트 핸들러로 전달해야 합니다.


해결 방법

공통 fetch 유틸리티 활용

서버에서 다른 내부 API 호출 시 Next-Auth 세션 쿠키를 자동으로 전달하지 않으므로, 쿠키와 Authorization 헤더를 명시적으로 설정하는 공통 유틸리티가 필요합니다.

import type { AvailableRouterMethod } from 'nitropack';
import { FetchError } from 'ofetch';

export type TApiOptions<TQuery, TBody, TRes> = {
  url: string;
  method: Uppercase<AvailableRouterMethod<string>>;
  query?: TQuery;
  body?: TBody;
  fetchOptions?: RequestInit;
};

export const useApi = async <TQuery, TBody, TRes>({
  url,
  method,
  query,
  body,
  fetchOptions,
}: TApiOptions<TQuery, TBody, TRes>): Promise<TRes> => {

  const headers: Record<string, string> = {
    Cookie: import.meta.server ? useRequestEvent()?.node.req.headers.cookie || '' : '',
    ...(fetchOptions?.headers as Record<string, string>),
  };

  try {
    const response = await $fetch<TRes>(url, {
      method,
      query,
      body,
      headers,
      ...fetchOptions,
    });

    return response;
  } catch (err) {
    if (err instanceof FetchError && err.response?.status === 401) {
      await useAuth().signOut();
    }
    throw err;
  }
};

서버 이벤트 핸들러

import { getServerSession } from '#auth';

export default defineEventHandler(async (event) => {
  const config = useRuntimeConfig();
  const targetURL = config.springApiBaseUrl + event.node.req.url?.replace(/^\/spring/, '');

  const session = await getServerSession(event);
  event.node.req.headers.authorization = `Bearer ${session?.accessToken}`;

  return proxyRequest(event, targetURL);
});

위 설정을 통해:

  • SSR 시 중복된 set-cookie 발생을 원천 차단합니다.
  • 내부 API 호출 시 Next-Auth 세션 쿠키와 Bearer 토큰을 일관되게 전달합니다.
  • 토큰 만료 시 자동 로그아웃 처리 등을 간편하게 관리할 수 있습니다.

'Javascript > NuxtJS' 카테고리의 다른 글

[Nuxt3] 빌드 후 동적 프록시 설정하기  (0) 2025.03.26
[Nuxt3] NextAuth, keycloak 연동  (0) 2025.03.16
[Nuxt3] 환경 변수 관리  (0) 2025.03.15
[Nuxt3] 스토리지: vueuse  (0) 2025.03.15
[Nuxt3] 헬스 체크  (1) 2025.03.15