NextJS 에서 next-auth 라는 라이브러리를 이용하면 google , facebook , naver 같은 소셜 로그인 기능을 쉽게 관리 및 추가 할 수 있습니다.
이번 포스트에서는 next-auth 를 통해 소셜 로그인을 구현하는 방법에 대해서 알아보겠습니다.
먼저 next-auth 라이브러리 설치를 진행 해줍니다
npm i next-auth
- pages/api 경로에 auth 폴더를 생성하고 그 안에 [...nextauth].js 파일을 생성 한 뒤 next-auth 관련 설정 작성합니다.
- 원하는 소셜로그인의 provider를 providers 객체에 추가해줍니다. 여기서는 google 로그인을 기능을 위해 GoogleProvider를 추가하겠습니다.
- .env 환경 변수에 clientId와 clientSecret 값을 추가하여 provider에 해당 값들을 제공합니다.
// pages/api/auth/[...nextauth].ts
import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
export default NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
GoogleProvider({
clientId: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID as string,
clientSecret: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_SECRET as string,
}),
],
secret: process.env.NEXT_PUBLIC_NEXTAUTH_SECRET,
callbacks: {
async session({ session, token, user }) {
console.log("INSIDE OF THE SESSION CALLBACK");
return { ...session, user: { ...session.user, ...user } };
},
},
});
7번째 줄에 prisma는 프로젝트하면서 prisma 사용해줘서 선언 했습니다
SessionProvider 설정
next-auth/react 에서 제공하는 SessionProvider로 Component를 감싸 nextjs에서 useSession 훅을 통해 session 정보를 접근 할 수 있도록 합니다.
import { SessionProvider } from "next-auth/react";
import { ChakraProvider } from "@chakra-ui/react";
import type { AppProps } from "next/app";
import { theme } from "@/chakra/theme";
import { Toaster } from "react-hot-toast";
export default function App({
Component,
pageProps: { session, ...pageProps },
}: AppProps) {
return (
<SessionProvider session={session}>
<ChakraProvider theme={theme}>
<Component {...pageProps} />
<Toaster />
</ChakraProvider>
</SessionProvider>
);
}
로그인 및 세션 정보 접근
기본 설정은 완료 됬으니 이제 실제 로그인 그리고 로그아웃 하는 방법에 대해서 알아보겠습니다.
어려운거 없습니다 그저 next-auth/react 에서 제공하는 signIn , signOut 그리고 useSession 을 활용하면 됩니다.
import Auth from "@/components/Auth/Auth";
import Chat from "@/components/Chat/Chat";
import { Box } from "@chakra-ui/react";
import type { NextPageContext } from "next";
import { getSession, useSession } from "next-auth/react";
export default function Home() {
const { data: session } = useSession();
console.log("clientSession", session);
const reloadSession = () => {
const event = new Event("visibilitychange");
document.dispatchEvent(event);
};
return (
<Box>
{session?.user?.username ? (
<Chat session={session} />
) : (
<Auth session={session} reloadSession={reloadSession} />
)}
</Box>
);
}
export async function getServerSideProps(context: NextPageContext) {
const session = await getSession(context);
return {
props: {
session,
},
};
}
서버로 데이터 받아오기 위해서 getServerSideProps로 진행했습니다
import { CreateUsernameData, CreateUsernameVariables } from "@/util/types";
import { useMutation } from "@apollo/client";
import { Button, Center, Image, Input, Stack, Text } from "@chakra-ui/react";
import { Session } from "next-auth";
import { signIn } from "next-auth/react";
import { useState } from "react";
import toast from "react-hot-toast";
import UserOperations from "../../graphql/operations/user";
interface IAuthProps {
session: Session | null;
reloadSession: () => void;
}
const Auth = ({ session, reloadSession }: IAuthProps) => {
const [username, setUsername] = useState("");
const [createUsername, { loading, error }] = useMutation<
CreateUsernameData,
CreateUsernameVariables
>(UserOperations.Mutations.createUsername);
const onSubmit = async () => {
if (!username) return;
try {
const { data } = await createUsername({ variables: { username } });
if (!data?.createUsername) {
throw new Error();
}
if (data.createUsername.error) {
const {
createUsername: { error },
} = data;
throw new Error(error);
}
toast.success("Username Successfully");
reloadSession();
} catch (error: any) {
toast.error(error?.message);
console.log("err", error);
}
};
console.log("se", session);
return (
<Center height="100vh">
<Stack spacing={8} align="center">
{session ? (
<>
<Text fontSize="3xl">Creat a Username</Text>
<Input
placeholder="Enter a username"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<Button width="100%" onClick={onSubmit} isLoading={loading}>
Save
</Button>
</>
) : (
<>
<Text fontSize="3xl">MessengerQL</Text>
<Button
onClick={() => signIn("google")}
leftIcon={<Image height="20px" src="/images/googlelogo.png" />}
>
Continue with Google
</Button>
</>
)}
</Stack>
</Center>
);
};
export default Auth;
import { signIn } from "next-auth/react" 여기서 가져와서 signIn하면
로그인한 데이터 정보가 나타납니다.
import { Button, Flex } from "@chakra-ui/react";
import { Session } from "next-auth";
import { signOut } from "next-auth/react";
import ConversationsWrapper from "./Conversations/ConversationsWrapper";
import FeedWrapper from "./Feed/FeedWrapper";
interface ChatProps {
session: Session;
}
const Chat = ({ session }: ChatProps) => {
return (
<Flex height="100vh" bg="#1F1F1F">
<ConversationsWrapper session={session} />
<FeedWrapper session={session} />
<Button onClick={() => signOut()}>Logout</Button>
</Flex>
);
};
export default Chat;
로그아웃은 간단합니다 import { signOut } from "next-auth/react" 가져온걸 사용하면 됩니다,
결론
next-auth를 통해 간단하게 소셜 로그인을 구현하는 방법에 대해서 알아봤습니다. provider 설정 외에 db에 연동하여 회원 정보를 저장 그리고 로그인 성공 여부 관련 설정 등등 여러 설정을 진행 할 수 있어 아주 유용하다고 생각됩니다.
또한 사용하기 쉽기 때문에 NextJS 에서 빠르게 로그인을 구현하고자 한다면 라이브러리 사용을 추천드립니다.
'Project' 카테고리의 다른 글
WebSocket/ Subscription (0) | 2023.08.29 |
---|---|
GraphQL 대화 생성 (0) | 2023.08.28 |
GraphQL- 유저 검색 기능 (0) | 2023.08.23 |
Graphql Query, prisma (0) | 2023.08.22 |
Graphql 리액트 연결 (0) | 2023.08.22 |