[next-auth] Pages 커스텀 하기 (Next.js v.13 app 디렉토리 적용법)

Maria Kim·2023년 11월 11일
0
post-thumbnail

NextAuth.js Page 공식 문서

next-auth의 Pages 공식 문서를 확인하면 아직 예전의 Next.js page 디렉토리를 사용하는 방법만 소개되어 있다.

물론, page와 app 디렉토리. 12버전과 13버전을 마스터할 분들은 쉽게 변환이 되겠지만.

아직 익숙하지 않은 분들을 위해 13 version app 디렉토리에 적용하는 방법을 소개하려고 한다.

공식 문서의 12버전 page 버전

import type {
  GetServerSidePropsContext,
  InferGetServerSidePropsType,
} from "next"
import { getProviders, signIn } from "next-auth/react"
import { getServerSession } from "next-auth/next"
import { authOptions } from "../api/auth/[...nextauth]"

export default function SignIn({
  providers,
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
  return (
    <>
      {Object.values(providers).map((provider) => (
        <div key={provider.name}>
          <button onClick={() => signIn(provider.id)}>
            Sign in with {provider.name}
          </button>
        </div>
      ))}
    </>
  )
}

export async function getServerSideProps(context: GetServerSidePropsContext) {
  const session = await getServerSession(context.req, context.res, authOptions)

  // If the user is already logged in, redirect.
  // Note: Make sure not to redirect to the same page
  // To avoid an infinite loop!
  if (session) {
    return { redirect: { destination: "/" } }
  }

  const providers = await getProviders()

  return {
    props: { providers: providers ?? [] },
  }
}

13버전 app 버전 적용 후

  • 13버전 app 부터는 async를 사용하는 컴포넌트와 'use client'를 사용하는 컴포넌트 분리해야 한다.(아니면 'No async client component' 에러가 발생)
    그래서 상위 부모 컴포넌트에서 async를 처리하고 자식 컴포넌트가 client 를 사용하도록 분리하면 된다.
  • ⚠️ 아직 client 컴포넌트 내에 서버 컴포넌트를 넣을 수 없다. 그래서 최대한 client 컴포넌트는 작게 만들어야 한다.

page.tsx

import { getProviders } from "next-auth/react";
import SignInOptions from "./SignInOptions";

export default async function Page() {
  const providers = (await getProviders()) ?? {};

  return <SignInOptions providers={providers}  />;
}

SignInOptions.tsx

"use client";

import { ClientSafeProvider, signIn } from "next-auth/react";

type Props = {
  providers: Record<string, ClientSafeProvider>;
};

export default function SignInOptions({providers}: Props) {

  return (
    <>
      {Object.values(providers).map((provider) => (
        <div key={provider.name}>
          <button onClick={() => signIn(provider.id)}>
            Sign in with {provider.name}
          </button>
        </div>
      ))}
    </>
  );
}
profile
Frontend Developer, who has business in mind.

0개의 댓글