[Next.js 13]Next.js 13.2버젼에 Next-auth 구현하기(+ 네이버 소셜 로그인)

S_Soo100·2023년 5월 13일
11

web

목록 보기
3/6

  • 사용 기술 : 넥스트JS 13.2 버젼 이상 (+ 타입스크립트, 테일윈드CSS)
  • 목표 : NextAuth.js를 통해 App폴더 내에서 소셜로그인 구현해보기

NextAuth.js 란?

  • Next.js가 인증해준 Auth관련 라이브러리.
  • 처음부터 Next.js 및 서버리스를 지원하도록 설계되었다.

솔루션을 만들며 가장 큰 부분을 차지하는게 회원가입 일 때가 많다.

기본 사용법

공식문서

1) 설치

npm i next-auth

  • next-auth는 @types 로 설치하지 않아도 타입스크립트를 위한 타입들이 같이 따라온다.

2) Route Handlers

  • 넥스트 12버젼 까지는 pages/api/auth에 [...nextauth].js라는 파일을 만들어서 사용했었는데(API 라우팅),
    13.2로 업데이트 되고 프로젝트 구성이 pages에서 app 디렉토리로 넘어감에 따라 next-auth도 app디렉토리를 지원한다.
    여기 의 공식 가이드를 보며 함께 따라해보자.
  • 기존과 비슷하게 app디렉토리 내부에 api/auth/[...nextauth] 디렉토리 안에route.ts 파일을 만든다.

/app/api/auth/[...nextauth]/route.ts

import NextAuth from "next-auth"

const handler = NextAuth({
  ...
})

export { handler as GET, handler as POST }
  • Route Handlers는 내부적으로 request를 보내고 response 인스턴스를 반환하는 핸들러를 제공한다.
    기본적으로 필요한 Get과 Post는 export 해주자.
  • 저 ... 안에 providers를 구현해주면 된다. providers는 로그인을 하고싶은 서비스의 제공자 별 포맷에 맞게 넣어주면 된다.
    공식문서에 굉장히 많은 서비스가 등록되어 있는데 무려 네이버(!)와 카카오(!) 도 있다!

3) Provider 붙이기

Providers 공식문서 링크

  • 지금 다시보니 생각보다 엄청 많다.
    대부분은 구글, 애플, 페이스북 3개에 본인이 원하는 서비스를 덧붙이게 될 듯 하다.
    카카오랑 네이버는 국내 서비스 아니면 안 쓰기 때문에 영어로 된 서비스에서는 쓰지 않는 경우가 많았다.
  • 네이버 provider를 보면 example에 우리가 추가해야 하는 코드가 나와있다. 그 부분을 가져와서 handler안에 추가한다.
import NextAuth from "next-auth";
import NaverProvider from "next-auth/providers/naver";
...

const handler = NextAuth({
  providers: [
    NaverProvider({
      clientId: process.env.NAVER_CLIENT_ID,
      clientSecret: process.env.NAVER_CLIENT_SECRET,
    }),
    ...
  ],
});

export { handler as GET, handler as POST };
  • 그러면 아래 부분이 오류라고 뜨는데, id와 secret키가 'string | undefined' 형식이라 string 자리에 할당이 불가능하다는 오류 메세지 이다.
  • 간단하게 || ""를 뒤에 붙여서 null이면 빈 문자열을 주도록 처리하고,
    이제는 환경변수를 설정해야 한다.
    하지만 설정할 환경변수들이 네이버에서 발급받아야 하는 것 들이니
    네이버 개발자로 가서 필요한 Key를 받아오자.

4) Naver 애플리케이션 등록, Key 발급

  • 네이버 개발자 홈페이지로 가서 APP을 만든다. 정말 간단하기 때문에 후다닥 해보기 바란다.
    네이버 애플리케이션 등록 (API 이용신청) 링크
    네이버 로그인만 사용한다고 체크한 다음, 받고 싶은 정보를 체크해주면 된다.

  • 완료하고 나면 콘솔에서 Client ID 와 Secret이 보인다.

  • 최상위 디렉토리에 .env 파일을 만들고 NAVER_CLIENT_IDNAVER_CLIENT_SECRET변수를 선언한 다음 저 두 키를 적어준다.
  • 그리고 한가지 더, API설정에서 서비스 URL 등록을 해야 한다.
    중앙 상당의 메뉴에서 "API설정"을 클릭하고 스크롤을 내리면 URL등록 부분이 나온다.
  • 거기에 아래같이 주소를 입력해주면 끝!!

5) 화면: Session Provider 감싸기

  • 로그인이 되어있는지 유저 정보는 무엇인지에 관한 정보를 세션(Session)이라고 한다.
    우리는 이 정보를 useSession이라는 리액트 훅을 통해 접근할 수 있으며,
    그를 위해 나의 애플리케이션의 최상위 레벨에 세션 컨텍스트인 <SessionProvider />로 감싸두어야 한다.
  • 기존에는 _app.js에 <SessionProvider />를 감쌌다면, 이제는 layout.tsx에서 감싸자. 하지만 layout.tsx는 메타 데이터를 가지는 등 SSR을 사용해야 하기 때문에 상태가 필요한 프로바이더와 자꾸 충돌한다. 편법으로 그 안에 한번 더 컴포넌트로 감싸주자.

AuthSession.tsx

'use client';
import { SessionProvider } from "next-auth/react";

type Props = ({
  children: React.ReactNode;
  });

export default function AuthSession({ children }: Props) {
  return <SessionProvider>{children}</SessionProvider>;
}

app/layout.tsx

import "./globals.css";
import { Nanum_Gothic } from "next/font/google";
import AuthSession from "@/AuthSession";

const nanum_gothic = Nanum_Gothic({
  subsets: ["latin"],
  weight: ["400", "700", "800"],
});

export const metadata = {
  title: "naver social sign-in by next-auth",
  description: "Generated by create next app",
};

type Props = {
  children: React.ReactNode;
};

export default function RootLayout({ children }: Props) {
  return (
    <html lang="en" className={nanum_gothic.className}>
      <body>
        <AuthSession>
          {children}
        </AuthSession>
      </body>
    </html>
  );
}
  • 공부하면서 찾아본 인도인 github 프로젝트에는 layout.tsx에 그냥 'use client' 넣어버리는 상남자도 있었다.
    (meta data 어디다 넣어야하지?)

6) 화면: 기본 로그인 화면 호출하기

  • 로그인 호출을 위해서는 next-auth에 있는 signIn, signOut 메서드를 호출하면 된다.
"use client"; // 필수!
import { signIn, signOut, useSession } from "next-auth/react";

...세션 상태 사용하기
const { data: session } = useSession();
...

...로그인 버튼
<button onClick={() => signIn()}>
Sign In
</button>
...

...로그아웃 버튼
<button onClick={() => signOut()}>
Sign Out
</button>
...
  • 이 버튼을 누르면 기본 로그인 창이 뜬다.
    네이버 하나만 나오니까 적적해서 밑에 2개 더 추가해 두었다.
    (어째서인지 구글이나 깃허브는 회사 로고가 뜨는데 네이버 카카오는 안 나온다)
  • 이제 Appbar를 구성해보자.
    로그인 하면 로그인한 사용자의 이름 혹은 이메일이 표시되었으면 좋겠고,
    예쁘게 프로필 사진도 같이 나오게 만들면 좋겠다.

  • 그리고 로그인 상태인지 로그아웃 상태인지 자동으로 판단하게 하려면 session?.user 가 null인지 아닌지를 가지고 구성하면 된다.

  • 나는 네이버 로그인 기능에 '이메일'과 '프로필 이미지'를 필수로 달라고 했기 때문에
    로그인 하면 로그인 버튼 옆에 이메일과 프로필 이미지가 출력되도록 한다.

"use client";
import { signIn, signOut, useSession } from "next-auth/react";
import Link from "next/link";
import React from "react";

const AppBar = () => {
  const { data: session } = useSession();

  return (
    <div className="flex gap-5 p-2 bg-slate-200 ">
      <Link className="text-sky-600 hover:text-sky-700" href={"/"}>
        Home
      </Link>

      <div className="flex gap-2 ml-auto">
        {session?.user ? (
          <>
            <img
              className="w-8 h-8 rounded-full"
              src={session.user.image || ""}
            />
            <p className="text-sky-600"> {session.user.email}</p>
            <button className="text-red-500" onClick={() => signOut()}>
              Sign Out
            </button>
          </>
        ) : (
          <button className="text-green-600" onClick={() => signIn()}>
            Sign In
          </button>
        )}
      </div>
    </div>
  );
};

export default AppBar;
  • 덤으로 app/page.tsx에서 session의 정보도 문자열로 출력하게 해봤다.

  • 로그인 하지 않은 상태
    데이터는 null, 상태는 unauthenticated(미인증)이다.

  • 로그인을 완료한 상태
    조금 더 예쁘게 만들어야겠지만.. 우선 정보들이 아주 잘 들어왔다.
    session에는 우리가 네이버 로그인에서 요청한 정보만 들어오고
    다른건 하나도 오지 않았음을 알 수 있다.
    상태가 authenticated(인증됨)으로 변경되었다.

profile
플러터, 리액트

6개의 댓글

comment-user-thumbnail
2023년 6월 28일

안녕하세요 :) 위에 글 따라 하는데 저는 layout 파일에, SessionProvider 감싼 AuthSession ('use client') 따로 만들어서 chidren 감쌌는데 오류가 납니다.. (터미널 에러 : StaticGenBailoutError: Page with dynamic = "error"), 혹시 이런 에러는 보시지 않으셨나요 ..?

1개의 답글
comment-user-thumbnail
2023년 7월 4일

안녕하세요~ 내용 정리 너무 잘해주셨는데 const { data: session } = useSession(); 적용하면 무한루프 돌지 않던가요..? 전 미친듯이 무한루프가 도네요..ㅠㅠ

1개의 답글
comment-user-thumbnail
2023년 11월 23일

많이 도움이 되었습니다~ㅎㅎ

답글 달기
comment-user-thumbnail
2024년 1월 9일

와 덕분에 에러 해결했어요! 감사합니다! : )

답글 달기