Next.js v12 Authenticating

김준호·2022년 7월 13일
2

Next.js 프로덕트에 로그인이 필요했고, 특히 로그인 유지 부분을 어떤 프로세스로 구현했는지 작성합니다.

Authentication Patterns

Next.js 의 공식문서에는 2가지의 authentication patterns 가 제공됩니다.

  1. server side 에서는 loading skeleton을 제공하고, client side 에서 로그인을 처리하기
  2. server side 에서 로그인을 처리하고 그 정보를 client side 로 넘기기

각각은 분명한 장단점이 있고 그 중에서 저는 2번을 선택했습니다.
현재 진행 중인 프로덕트는 개인정보가 페이지를 렌더함에 있어 중요한 기준점이 되며, 이는 곧 로그인으로 판단되기 때문입니다.
2번을 선택한다면, 클라이언트 측에서는 로그인 유무에 따른 정확한 페이지를 바라볼 수 있고 인증과 관련된 불필요한 콘텐츠를 막을 수 있다는 장점이 있습니다.

공식 문서는 authentication을 관리하기 위해 iron-session, next-auth 두 라이브러리를 추천하니 확인해보시면 도움되실 것 같습니다.

Data Fetching

Next.js 에서 제공하는 Data fetching api 중 현재 고려해야할 선택지는 getServerSideProps, getInitialProps 가 있습니다.
현재 진행 중인 프로덕트는 대부분의 페이지에서 로그인 여부에 따라 콘텐츠가 달라지기 때문에 getInitialProps 를 선택했습니다.

Logic

환경: NextJS + redux(toolkit)

  1. 클라이언트에서 로그인을 합니다.

    • 서버로부터 로그인과 관련된 토큰들을 받고 프로덕트 관리 체계에 맞게 storage, cookie, header, .. 등을 활용해서 브라우저에 저장해줍니다.
    • 또한 받은 토큰을 통해 (유저 정보를 요청해서) 유저 정보를 redux store에 저장합니다.
      - redux 의 경우 NextJS 와 같이 사용하기 위해 next-redux-wrapper 를 사용합니다.
    • 제가 설명할 로직에서는 쿠키를 사용하기 때문에 access-token 을 쿠키에 저장합니다.
    • 아직까지는 로그인 유지를 위한 처리를 하지 않았으므로 새로고침(또는 a tag를 이용한 이동)시 로그아웃 처리됩니다.
      - CSR 단에서 로그인 유지를 처리하는 경우 루트 레벨 수준의 마운트 단계에서 로그인을 처리해줌으로써 해결할 수 있습니다.
  2. Next 서버에서 로그인을 합니다.

    • getInitialProps 는 AppContext 타입의 props 내에서 ctx에 접근할 수 있습니다.
    • ctx 에는 server only 형태로만 제공되는 프로퍼티인 req, res 가 존재하며, 여기에 접근할 수 있다는 것은 getInitialProps가 Next 서버에서 동작하고 있다는 것입니다.
    • getInitialProps 는 Next 서버에서 최초로 실행되며, 이후 next/link, next/route 를 통해 동작하는 경우 클라이언트에서 실행됩니다. 그러므로 getInitialProps 를 클라이언트와 서버측 코드로 각각 구분해서 사용해야 로그인 유지간에 발생하는 에러를 방지할 수 있습니다.
    • redux 를 NextJS 의 data fetching api 와 함께 사용하기 위해 next-redux-wrapper 라는 라이브러리를 사용하고 있습니다. 사용자가 요청시마다 redux store 를 생성하는 NextJS server 는 Client store 와 합쳐지기 위해 hydration 과정을 거치게 됩니다. 즉, Client redux store 의 state 는 NextJS server redux store 의 state 로 덮어씌여집니다.
    • ctx.req 가 존재하는 경우 (server only)
    • ctx.req.headers.cookie 를 통해 accessToken을 가지고 옵니다.
    • accessToken 로 사용자 정보를 가져옵니다(로그인)
    • 가져온 정보를 NextJS server store 에 저장해줍니다.
    • getInitialProps 이후의 프로세스가 동작되며 NextJS 서버 state 가 클라이언트 state 에 합쳐지며 로그인이 유지된 화면을 보게 됩니다.
  1. 로그아웃
    • 클라이언트에서 로그아웃을 진행합니다. (쿠키값을 삭제해주고.. store 를 비워주고..)
    • 로그아웃 후 새로고침을 진행하는 프로덕트라면 문제없지만, 로그인 정보를 손수 다 처리하고 다시 '/' 와 같은 특정 페이지로 라우팅하는 SPA 를 좋아하는 페이지라면 아래 글을 읽어주세요.
    • 클라이언트에서 로그아웃을 진행 후 getInitialProps 또는 redux devTools 를 통해 store 정보를 확인해보면 아직 유저의 정보가 남아있습니다. Next 서버의 store 정보가 Client 로 hydration 되는 것이지 그 반대는 아니니까요.
    • 이 때문에 로그아웃 처리를 확실히 해주지 않는 경우 분명 쿠키 같은 로그인을 위한 정보가 없음을 확인할 수 있음에도 마치 아직 로그인 상태인 것처럼 보일 수 있습니다.
    • 이를 해결하기 위한 방법은 간단합니다. 그냥 ctx.req 로부터 accessToken 에 접근할 수 없다면 state 를 날려주면 됩니다. 이를 통해 Next 서버와 클라이언트 둘다 동일한 로그인 상태를 초기에 가져갈 수 있게 됩니다.

Reference

https://nextjs.org/docs/authentication
https://nextjs.org/docs/api-reference/data-fetching/get-initial-props

잘못된 부분은 지적해주시면 감사하겠습니다.

profile
추운 겨울 감기 조심

2개의 댓글

comment-user-thumbnail
2023년 9월 7일

좋은글 감사 합니다. 👍

redux 를 NextJS 의 data fetching api 와 함께 사용하기 위해 next-redux-wrapper 라는 라이브러리를 사용하고 있습니다. 사용자가 요청시마다 redux store 를 생성하는 NextJS server 는 Client store 와 합쳐지기 위해 hydration 과정을 거치게 됩니다. 즉, Client redux store 의 state 는 NextJS server redux store 의 state 로 덮어씌여집니다.

제가 이부분을 많이 고민 하였습니다.
저희는 zustand 를 이용하고 있는데 이것도 서버에서 클라이언트로 상태를 덮어 씌을수 있는지 문의 부탁 드립니다.

위내용 코드공유 부탁 드립니다.

1개의 답글