문제 상황
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 |