본문 바로가기
source-code/Next JS

[next js] app directory에서 token 저장하기

by mattew4483 2024. 2. 13.
728x90
반응형

next js 13 버전에서 app directory가 등장하면서,

app directory내 모든 컴포넌트들은 기본적으로 server component로 동작하게 되었습니다.

https://nextjs.org/docs/app/building-your-application/rendering/server-components

 

Rendering: Server Components | Next.js

Learn how you can use React Server Components to render parts of your application on the server.

nextjs.org

이러한 React Server Component(RSC)는 말 그대로 서버에서 실행되기 때문에

기존의 Client에서 실행되던 컴포넌트(React Client Component, RCC)에서 사용하던 브라우저 API들을 사용할 수 없습니다.

 

RSC에서는 window에 접근할 수 없다

따라서 local storage, session storage와 같은 브라우저 저장소 역시 사용할 수 없는데,

이로 인해 '사용자 인증에 필요한 정보(ex jwt token)를 어디에 저장할 것인가'하는 문제가 발생합니다.

import React from "react";

const fetchProfile = () => {
  return fetch("/end-point", {
    headers: {
        // error! where is token from?
        Authorization: `Bearer ${token}`,
    },
  });
};

const page = async () => {
  const data = await fetchProfile();
  console.log(data);
  return <div>Hello</div>;
};

export default page;

만약 end point server에서 cookie 통한 사용자 인증을 진행한다면, 동작 자체에는 큰 문제가 없습니다.

login이 완료된 경우 sever에서 set-cookie를 해주기만 하면, 이후의 요청에는 cookie에 해당 token이 알아서 들어가 있을 테니까요.

 

저희 서비스 역시 처음에는 위와 같은 방법을 사용했습니다.

하지만 얼마 지나지 않아, 아래 두 가지의 문제점이 발견되었습니다.

 

1. server API 인증 방식 변경 (Authorization header)

2024.02.06 - [source-code/Next JS] - [next js] server component로 httpOnly cookie 접근하기

 

[next js] server component로 httpOnly cookie 접근하기

현재 저희 서비스는 1) next 14로 구성한 admin 페이지에서 로그인 2) 로그인을 통해 access token, refresh token 발급 3) extension 내 API 요청 시 발급받은 access token을 함께 전달 위 flow를 통해 사용자를 인증

23life.tistory.com

사실 해당 이슈 자체가 직접적인 원인은 아닙니다.

next js로 구성한 서비스는 어디까지나 admin page였고,

domain 특정이 가능한 이상 same site None 옵션을 줄 필요가 없기 때문이죠.

 

하지만 이로 인해, chrome extension을 통해 서비스를 제공하는 저희 도메인 특성상

server에서는 모든 API의 인증 방식에서 cookie를 제거해야만 했습니다.

그리고 이는 필연적으로, admin page에서 사용하는 API들의 인증 방식에도 영향을 미치게 되었습니다.

server 측에서 API 인증 방식을 Authorization header에서 토큰을 조회하는 형태로 통일함에 따라,

next js로 제공 중인 admin page 역시 이를 따라갈 수밖에 없었습니다.

 

2. 로컬 개발 환경 테스트 어려움

현재 사내 개발-운영 환경은 아래와 같은 3단계로 구성되어 있습니다.

1) 로컬 개발 환경 -> 2) 배포 staging 환경 -> 3) 배포 production 환경

 

이때 로컬 개발 환경은 각 개발자들의 작업 환경을 의미하며, 대부분 local host를 가리키고 있으며

배포 staging 환경은 개발 사항들을 병합하여, production 반영 전 배포 환경 테스트를 위해 구성되어 있습니다.

 

문제는 client 측 로컬 개발 환경(1)에서 server 측 배포 staging 환경(2)과 cookie를 주고받을 때 발생했습니다.

(server 코드를 즉시 사용해야 하는 특별한 상황이 아니라면, client 측 로컬 개발 환경은 server 측 staging 환경을 바라보고 있습니다)

 

프로덕션 레벨의 cookie는 보안을 위해 Domain 옵션을 추가해, 허용된 도메인에서만 공유가 가능하므로...

개발 환경 request에 대한 응답에 server가 set-cookie를 한다 하더라도, 해당 값이 cookie에 세팅되지는 않습니다!

 

즉 client 개발 환경에 cookie를 전달하기 위해서는, 동일한 domain의 server로 요청을 보내야만 했는데...

이를 위해 모든 FE 개발자가 로컬 서버를 구동하는 건 불필요한 일이란 생각이 들었습니다.

 

문제 및 해결 방안

즉, 다음과 같은 요구사항이 존재합니다.

1. 로그인 성공 시, server는 response에 token을 반환한다.

2. 로그인 완료 후 관리자 페이지(RSC)에서 특정 API를 호출한다. (ex fetchProfile)

3. 이때 해당 요청은, Authorization header에 token을 전달해야 한다.

4. 로그인을 완료한 사용자는, 토큰 만료 전까지는 재로그인할 필요가 없다. (자동 로그인)

5. 로컬 개발 환경에서 배포된 staging server 환경에 로그인이 가능해야 한다.

 

이 중 2) RSC에서 api 호출 4) 자동 로그인 구현 을 생각한다면...

1) 로그인 성공 시 전달받은 token을 cookie에 저장하는 것이 필수적이란 생각이 들었습니다.

(RSC에서는 브라우저 스토리지를 사용할 수 없으므로)

 

하지만 로그인을 성공했다고 해서 server가 set-cookie를 하지 않을뿐더러,

그 경우 Domain 비허용으로 인해 5) 로컬 환경에서 cookie 설정 을 구현할 수가 없습니다.

 

여러 고민과 시행착오 끝에, 저는 다음과 같은 방법으로 위 요구사항을 구현했습니다.

1) server action을 통해 server에서 전달받은 token을 cookie에 저장한다.

2) middleware에서 cookie를 조회, 로그인 여부를 판단한다. (자동 로그인)

 

다음 글에 이어서...

2024.08.05 - [source-code/Next JS] - [next js] app directory에서 token 저장하기 - (2)

 

[next js] app directory에서 token 저장하기 - (2)

Backgrounds2024.02.13 - [source-code/Next JS] - [next js] app directory에서 token 저장하기 [next js] app directory에서 token 저장하기next js 13 버전에서 app directory가 등장하면서, app directory내 모든 컴포넌트들은 기본적

23life.tistory.com

 

728x90
반응형