개발자
안녕하세요. 최근 NextJs를 공부하며 이전 리액트 기반의 사이드 프로젝트를 NextJs로 구현해보고 있습니다. 카카오 로그인만 지원을 하고 있고, 프론트 쪽에서 카카오 인가 코드를 백엔드로 넘기면 백에서 jwt를 발급해서 응답으로 access token과 refresh token을 프론트로 넘겨주고 있습니다. 이전 프로젝트에서는 두 토큰 모두 localStorage에 저장하는 방식으로 했었는데요, 이번에는 쿠키를 이용해보려고 하고 있습니다. 다만 백엔드에서 set-cookie를 해놓지 않아서 응답으로 받은 토큰을 따로 쿠키에 저장해야하는 상황입니다. 하지만 Server Component에서는 set cookie가 안되는 것으로 알고 있습니다. <목표 구현 방식> route handler를 통해서 백엔드 api를 호출하고 그 값을 쿠키에 저장하도록 코드를 짰습니다. (/app/api/token/route.ts) return 값은 확인을 위해서 임의로 넣었습니다. 그리고 쿠키에 저장된 토큰을 통해서 서버 컴포넌트에서 이를 이용해 백엔드 api 통신을 하고 싶습니다. 하지만 서버 컴포넌트에서 쿠키를 확인하니 비어있는 쿠키인 것을 알 수 있었습니다. 얕은 지식으로 생각을 했을때, (route handler - 브라우저 혹은 서버 컴포넌트)에서 생성한 쿠키는 (백엔드 도메인 - 브라우저 혹은 서버 컴포넌트) 통신에 사용되는 쿠키와 다르기 때문이라고 생각이 들었는데 해답을 찾지 못했습니다. <질문 사항> - 백엔드 서버에서 set-cookie를 하지 않고 직접 구현할 순 없을까요? 쿠키는 forwarding이 안되나요? - 제가 생각한 구조 말고 추천하시는 토큰 관리 방식에 대해서 알려주셔도 감사하겠습니다. 아직 초보 개발자에 글도 잘 쓰지 못해 이해하시기 힘들 것 같지만, 넓으신 아량으로 지식을 나눠주신다면 정말 큰 도움이 될 것 같습니다. 긴글 읽어주셔서 감사합니다 (_ _)
1// /app/api/token/route.ts
2export async function GET(req: NextRequest) {
3 const cookieStore = cookies();
4 const authCode = req.nextUrl.searchParams.get("code");
5 const res = await fetch(`${SERVER_URL}/auth/login/kakao?code=${authCode}`, {
6 method: "GET",
7 headers: {
8 "Content-Type": "application/json",
9 },
10 });
11 const data = await res.json();
12 cookieStore.set("accessToken", data.data.accessToken, { httpOnly: true });
13 cookieStore.set("refreshToken", data.data.refreshToken, { httpOnly: true });
14
15 const at = cookieStore.get("accessToken")?.value;
16 const rt = cookieStore.get("refreshToken")?.value;
17
18 return Response.json({
19 data: { accessToken: at, refreshToken: rt },
20 });
21}
22
23
24// /app/oauth/callback/kakao/page.tsx
25async function getToken(authCode: string | string[]) {
26 const response = await fetch(
27 `http://localhost:3000/api/token?code=${authCode}`,
28 {
29 method: "GET",
30 },
31 );
32
33 const json = await response.json();
34 return json;
35}
36
37export default async function Page({ searchParams }: Props) {
38 const { code } = searchParams;
39 if (!code) redirect("/login");
40
41 await getToken(code);
42
43 return <div>Page</div>;
44}
커리어리 AI 봇
GPT가 달아주는 답변입니다.
2024년 04월 03일
Next.js에서 서버 컴포넌트는 모두 일관된 도메인에서 실행됩니다. 즉, 브라우저가 로드한 페이지와 API 요청들이 모두 같은 도메인에서 발생하므로 Cookie에 대한 접근이 가능합니다. 하지만 문제는 서버사이드 렌더링 (SSR) 시에는 특정 요청과 연관된 쿠키를 Node.js 서버에서 직접 처리해야 한다는 것입니다. 그래서 백엔드에서 Set-Cookie를 이용해 응답을 수신할 경우 프론트엔드(브라우저 혹은 Next.js 서버) 에서 해당 쿠키를 저장하게 됩니다. 반면 직접 구현한다는 건 브라우저에서 JavaScript를 사용하여 document.cookie 객체에 토큰 값을 설정하는 것을 말하며, 이럴 때는 HttpOnly 옵션을 사용할 수 없습니다. HttpOnly 속성이 있는 쿠키값은 클라이언트 사이드 스크립트(Javascript)로 접근할 수 없고 서버쪽으로만 값이 전송됩니다. 주로 세션을 관리하기 위해서 혹은 XSS(Cross-site scripting) 공격 방어를 위해 사용됩니다. 따라서, 엄격한 보안 요건이 필요한 경우에는 서버측에서 set-cookie를 사용하는 것이 좋습니다. 만약 백엔드에서 set-cookie 없이 구현하려고 한다면, Fetch API 어디에서든 credentials 옵션을 'include'로 설정하여 쿠키가 포함된 요청을 보내야 합니다. 추가적으로 토큰 관리 방식으로는 localStorage에 저장하는 것 외에도 session storage나 IndexedDB등을 이용할 수도 있습니다. 다만 이들은 모두 XSS 공격의 위험성이 있어 적절한 보안 조치가 필요합니다. API route handler의 경우 context의 res 객체를 통해 직접 쿠키를 설정할 수 있습니다. 하지만 이렇게 할 경우 XSS 공격에 노출될 위험이 있기 때문에 보안 대책이 필요합니다. 마지막으로 JWT 토큰은 가능한 서버 사이드에서 관리되어야 합니다. 클라이언트 사이드에서 관리하게 되면 CSRF, XSS와 같은 보안 문제에 노출될 가능성이 매우 높습니다.
지금 가입하면 모든 질문의 답변을 볼 수 있어요!