NextJS 에서 next-auth 라는 라이브러리를 이용하면 google, kakao 소셜 로그인 기능을 쉽게 관리 할 수 있다고 해서 도전! 처음 구현하다 보니 잘 할 수 있을까 싶었는데 next-auth 최고!
yarn을 쓰고 있기 때문에 yarn add를 통해 설치했다.
yarn add next-auth
pages/api/auth 폴더 안에 [...nextauth].js 파일을 생성해 준다.
[...nextauth].js 파일에 원하는 소셜 로그인 provider를 providers 객체에 추가해준다. google 소셜 로그인을 위해 GoogleProvider를 providers 배열 안에 넣어준다.
import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";
export default NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
// 여기에 다른 provider를 추가하면 된다.
],
});
.env 환경 변수에 client Id와 client Secret 값을 추가해 provider에 해당 값을 process.env.CLIENT_ID로 불러와준다.
.env 파일은 gitignore에 넣어 github에 올라가지 않게 관리!
next-auth/react 에서 제공하는 SessionProvider로 Component를 감싸 nextjs에서 useSession 훅을 통해 session 정보를 접근 할 수 있도록 한다.
// app.js
import { SessionProvider } from "next-auth/react";
function app({ Component, pageProps }) {
return (
<>
<SessionProvider session={session}>
<Component {...pageProps} />
</SessionProvider>
</>
)
);
}
export default app;
이렇게 컴포넌트를 감싸줌으로써 session 정보에 접근할 수 있다.
이제 next-auth의 signIn, signOut, useSession을 쓸 수 있다.
signIn 함수로 로그인을 간단하게 구현할 수 있다. 최고최고
import { signIn } from "next-auth/react";
const socialLogin = (e, provider) => {
e.preventDefault();
signIn(provider);
}
두 개 이상의 소셜 로그인 구현 시엔 파라미터로 provider를 넣어주면 된다.
// google
<button type="button" onClick={e => socialLogin(e, "google")}>Google</button>
// kakao
<button type="button" onClick={e => socialLogin(e, "kakao")}></button>
이제 로그인 완성..이다! 이제 session access token을 서버에 보내 로컬 access 토큰과 refresh 토큰을 받아와야했다.
session 토큰을 위해 [...nextauth].js 파일에서 callbacks 객체를 추가해 session으로 해당 계정의 access token을 return 받을 수 있다.
export default NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
],
callbacks: [
{
async jwt({ token, account }) {
if (account) {
token.accessToken = account.access_token;
}
return token;
},
async session({ session, token }) {
if (session) {
session.accessToken = token.accessToken;
}
return session;
},
},
});
header 컴포넌트가 어느 페이지에나 존재하기 때문에 로그인 여부를 header에서 관리하기로 정했다. 여기서 useSession 훅을 통해 session data와 status를 확인 할 수 있다. 만약 소셜 로그인 상태라면 status를 console.log로 확인했을 때 "authenticated"가 찍히게 된다. 그래서 useEffect로 세션 상태를 확인해 로컬 토큰을 받아오기로 했다.
// header.js
import { useSession } from "next-auth/react";
.
.
.
const { data: sessionData, status: sessionStatus } = useSession();
useEffect(() => {
if (sessionData && sessionStatus === "authenticated") {
로컬토큰요청함수();
}
}, [socialData,socialStatus]);
로그아웃은 더더 간단하다. 내 경우 로컬과 소셜을 같이 관리하기 위해 session data가 null이 아닐 경우, 소셜 로그인이기 때문에 signOut() 하도록 했다.
const logOutHandler = () => {
if (sessionData) {
signOut();
}
로컬로그아웃함수();
};
<button type="button" onClick={logOutHandler}>로그아웃</button>
[next-auth][error]CLIENT_FETCH_ERROR]
로컬에서 잘되다 배포 할 때 에러가 발생한다고.. ㅎㅎ..
환경변수에 NEXTAUTH_URL와 NEXTAUTH_SECRET를 반드시 넣어주어야 한다고 한다. NEXTAUTH_URL은 이미 있고, secret이 문제같았다.
바로 추가
// [...nextauth].js
secret: process.env.NEXTAUTH_SECRET
참고) https://next-auth.js.org/configuration/options#nextauth_secret
구글링 하다 보니 pages 폴더와 같은 레벨에 api 폴더가 존재하면 배포 시 에러가 발생할 수 있다고..! 혹시 다시 에러가 발생할까 싶어 같은 레벨에 있는 폴더 이름을 apis로 바꿔주고 경로를 모두 수정했다. 해결~