Auth.js (구 Next Auth)를 사용하여 Next.js 인증 구현하기
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('아이디와 비밀번호가 일치하지 않습니다.');
}
};
[출처]
Next-auth 를 이용한 로그인 구현
next-auth 라이브러리를 이용해 로그인을 구현한 내용에 대해 공유합니다.
velog.io