Next.js

Auth.js (구 Next Auth)를 사용하여 Next.js 인증 구현하기

minjaem 2024. 1. 28. 17:57

1. Auth.js

 공식문서에서 Auth.js란 웹 어플리케이션에서 인증을 위한 완벽한 오픈 소스 인증 솔루션이라고 설명하고 있다. 사실 Next Auth라는 이름으로 더 익숙한 이 라이브러리는, 4버전까지는 Next.js를 위한 솔루션이었으나, 5버전 부터는 Svelte, Express 등 더 많은 프레임 워크를 지원하며 Auth.js라는 이름으로 변경하였다. 확장성을 고려하여 이름을 바꾼 것 같다. 또한, 현재는 사실 베타 버전 즉 실험적 단계에 불과하여 Next Auth 공식문서와 Auth.js dev 공식문서를 번갈아가면서 확인하며 작성했다. 

 Auth.js 사용의 장점은 다음과 같다.

- OAuth Provider를 통하여 다양한 OAuth 기능을 쉽게 사용할 수 있다. 현재 79개 이상의 유명한 서비스(구글, 페이스북, 애플, 카카오톡, 네이버 등) 지원, 자체 DB에 직접 접근하여 사용할 수 있으며 23개 이상의 DB/ORMs(MySQL, Postgres, Prisma)등 지원한다.

- Email Provider를 통하여 내장된 이메일 / 패스워드 / 매직 링크 인증을 지원한다.

- Credentail Provider를 통하여 기존 백엔드와의 유연한 연동도 가능하다.

- 기본 보안기능

  • Signed, prefixed, server-only cookies
  • 내장된 CSRF protection
  • 클라이언트 사이드 자바스크립트에 의존하지 않음
  • 암호화된 JWT Session 

* [자세한 내용은 공식문서]

https://authjs.dev/getting-started/introduction#secure-by-default

2. Auth.js 사용 방법

API 라우트 구성하기

 먼저 Next.js 13이상 앱 라우팅 방식에서 Auth.js를 도입하기 위해서는 /pages/api/auth/[...nextauth] JS/TS 파일을 만들어서 API 라우트를 구성해야 한다. Next.js에서 새로 도입된 라우트 핸들러는 app 디렉토리에서만 사용할 수 있으며, 이 구조 방식은 REST 방식 요청과 유사하기 때문에 이 경로로 요청하기 위해서는 반드시 구성해주어야 한다.

* [자세한 설명은 공식문서 확인]

https://nextjs.org/docs/app/building-your-application/routing/route-handlers

 

Routing: Route Handlers | Next.js

Create custom request handlers for a given route using the Web's Request and Response APIs.

nextjs.org

 Auth.js는 라우트 핸들러가 초기화되는 것을 감지하고, Web 인스턴스 요청을 이해하고 응답 인스턴스를 반환하여, 이 반환된 값을 통하여 여러 요청을 처리하게 된다. 또한, Auth.js가 제대로 작동하려면 GET, POST 핸들러가 필요하다.

* [자세한 설명은 공식문서 확인]

https://next-auth.js.org/configuration/initialization#route-handlers-app

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

export { GET, POST } from '@/auth';

// src/auth.ts
import NextAuth from "next-auth"

export const { 
	handlers : { GET, POST } 
} = NextAuth({
	...
})

 

useSession Hook 사용하기

useSession 훅을 통하여 Auth.js를 통하여 반환된 데이터를 사용하고 싶다면 Session Provider를 넣어주자.

* [자세한 설명은 공식문서 확인]

https://next-auth.js.org/getting-started/client#sessionprovider

 

Client API | NextAuth.js

The NextAuth.js client library makes it easy to interact with sessions from React applications.

next-auth.js.org

// src/app/(beforeLogin)/layout.tsx
import { Inter } from 'next/font/google';
import { SessionProvider } from "next-auth/react";

type Props = {
	children: React.ReactNode
}

export default function RootLayout({
	children,
}: Props) {
	return (
    	<html lang="en">
        	<body className={inter.className}>
            	<SessionProvider>
                	{children}
                </SessionProvider>
            </body>
        </html>
    )
}

 

Credential Provider 설정하기

 Auth.js에서 제공하는 provider에는 3가지의 종류가 있다.

- OAuth: 카카오톡, 네이버, 깃헙, 구글 등 사용자가 즐겨 사용하는 기존 로그인으로 로그인 할 수 있는 방법

- Email: 하나 이상의 OAuth 서비스 외에 이메일을 통한 로그인 지원을 추가하면 사용자가 OAuth 계정에 엑세스 할 수 없는 경우 로그인 할 수 있는 방법

- Credential: 사용자가 유연하게 로그인에 필요한 정보들을 구현하고, 인증 백엔드와 유연하게 통합할 수 있는 방법

오늘은 백엔드와 로그인 할 수 있는 방법 Credential Provider에 대해서 알아보도록 하자.

 

 Auth.js 5버전 부터, authorize method만 정의하면 된다. authorize 콜백은 credentials 값을 통해 해당 사용자가 로그인이 가능한지 여부를 판단하여 로그인을 제어 할 수 있는 함수이며, 로그인 여부를 판단하는 api 응답 값을 통하여 제어할 수 있다. 로그인이 유효한 경우(응답 성공) User 객체를 반환한다. (이때, 반환된 객체는 auth 객체로 사용할 수 있으며, 또한 Session Provider 내부에서 상속 받는 컴퍼넌트들은 useSession hook을 이용하여 유저 객체를 받을 수 있다.) 또한, 유효하지 않은 경우는 null을 반환하여 쉽게 에러 핸들링을 할 수 있다.

* [자세한 내용은 공식문서 확인]

 

// src/auth.ts

import NextAuth from "next-auth"
import { cookies } from 'next/headers'
import CredentialsProvider from "next-auth/providers/credentials";
import cookie from 'cookie';

export const {
  handlers: { GET, POST },
  auth,
  signIn,
} = NextAuth({
  pages: {
    signIn: '/i/flow/login',
    newUser: '/i/flow/signup',    
  },
  providers: [
    CredentialsProvider({
      async authorize(credentials) {
        const authResponse = await fetch(`${process.env.AUTH_URL}/api/login`, {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            id: credentials.username,
            password: credentials.password,
          }),
        })

        // 백엔드 쿠키를 브라우저에 심는 부분
        let setCookie = authResponse.headers.get('Set-Cookie');
        if (setCookie) {
          const parsed = cookie.parse(setCookie)
          cookies().set('connect.sid', parsed['connect.sid'], parsed)
        } 

        if (!authResponse.ok) {
          return null
        }

        const user = await authResponse.json()

        return {
          email: user.id,
          name: user.nickname,
          image: user.image,
          ...user,
        }
      },
    }),
  ]
});

 

Auth.js에 로그인 요청하기

자, 이제 export 해놓은 SignIn 함수에 credentials 인자와 id, password, redirect 값을 객체로 요청해주면 Auth.js에서 로그인 기능을 처리하게 된다.

const onSubmit: FormEventHandler<HTMLFormElement> = async (e) => {
    e.preventDefault();
    setMessage('');
    try {
      const response = await signIn("credentials", {
          username: id,
          password,
          redirect: false,
        })
      if (!response?.ok) {
        setMessage('아이디와 비밀번호가 일치하지 않습니다.');
      } else {
        router.replace('/home');
      }
    } catch (err) {
      console.error(err);
      setMessage('아이디와 비밀번호가 일치하지 않습니다.');
    }
  };

 

 

 

 

 

 

 

[출처]

https://velog.io/@dosomething/Next-auth-%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84

 

Next-auth 를 이용한 로그인 구현

next-auth 라이브러리를 이용해 로그인을 구현한 내용에 대해 공유합니다.

velog.io

https://velog.io/@leehyewon0531/NextAuth-%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C-%EC%A0%95%EB%A6%AC-Introduction-Getting-Started