// NextAuth
NextAuth는 Next 앱의 오픈소스 인증 솔루션이다.
OAuth 인증, 비밀번호 기반 인증, 세션 관리 등이 필요한 상황에서 주로 사용한다.
간편한 설정으로 인증을 관리할 수 있다는 장점이 있으며, 필요에 따라 커스터마이징도 가능하다.
* 공식 사이트: https://next-auth.js.org/
NextAuth는 App Routes 와 Route Handlers 에서 사용법이 다르기 때문에 14 버전은 Route Handlers 가이드를 보아야 한다.
▪ NextAuth 설치
npm install next-auth
▪ route.ts 파일 생성
app/api/auth/[...nextauth]/route.ts
import NextAuth from 'next-auth';
import GoogleProvider from 'next-auth/providers/google';
const handler = NextAuth();
export { handler as GET, handler as POST };
const authOptions: any ={
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_OAUTH_ID || '',
clientSecret: process.env.GOOGLE_OAUTH_SECRET || '',
}),
],
}
const handler = NextAuth(authOptions);
export { authOptions, handler as GET, handler as POST };
Google, KaKao 등 다양한 Provider를 추가할 수 있다.
이때 clientId와 clientSecret은 외부에 공개되면 안 되기 때문에 환경변수로 사용한다.
▪ clientId, clientSecret 생성
https://console.cloud.google.com/
Google 클라우드 플랫폼에서 clientId와 clientSecret을 발급 받아야 한다.
GoogleCloud 로고 옆 셀렉트 박스를 누르면 새 프로젝트를 생성할 수 있는 모달이 뜬다.
나는 이미 생성한 프로젝트가 있는 상태라서 기존 게 뜬다.
프로젝트 이름을 자유롭게 설정하고 만들어준다.
프로젝트를 생성하면 생성한 프로젝트에서 작업할 수 있다.
API 및 서비스를 눌러준다.
API의 OAuth 동의 화면을 클릭하여 consent screen을 설정해주어야 한다.
외부에서 구글 로그인을 사용할 것이기 떄문에 External을 체크한 후 만들어 준다.
앱 이름, 사용자 지원 이메일, 개발자 이메일만 필수로 입력한다.
앱 도메인이나 승인된 도메인은 배포 후 해당 도메인을 나중에 추가해줘도 된다.
그 다음은 그냥 쭉쭉 넘겨준다.
이번에는 사용자 인증 정보를 만들어야 한다.
OAuth 클라이언트 ID를 클릭한다.
승인된 JavaScript 원본은 우선 localhost로 등록해놓고 배포 후 수정해주야 한다.
그러면 클라이언트ID, 클라이언트 보안 비밀번호를 얻을 수 있다.
저 두 가지를 .env 파일에 입력해주면 된다.
▪ SessionProvider 컴포넌트 생성
app/context/AuthContext.tsx
'use client';
import { SessionProvider } from 'next-auth/react';
interface AuthProps {
children: React.ReactNode;
}
export default function AuthContext({ children }: AuthProps) {
return <SessionProvider>{children}</SessionProvider>;
}
▪ app/layout.ts 파일 설정
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={`${inter.className} mx-auto max-w-screen-md text-lg`}>
<AuthContext>
<Header />
<main>{children}</main>
</AuthContext>
</body>
</html>
);
}
Next.js 는 기본으로 서버 컴포넌트인데 next-auth에서 제공해주는 훅을 사용하려면 클라이언트 컴포넌트여야 한다.
그래서 SessionProvider를 클라이언트 컴포넌트로 분리하고, 이 컴포넌트를 layout에서 사용하는 방식으로 구현한다.
▪ 로그인 / 로그아웃
next-auth에서는 useSession 이라는 훅을 제공해주기 때문에 로그인 여부를 쉽게 알 수 있다.
또한 signIn, signOut 이라는 함수를 제공하여 소셜 로그인을 손쉽게 구현할 수 있게 해준다.
export default function Header() {
const { data: session } = useSession();
return (
<header className="sticky top-0 z-10 mb-5 flex items-center justify-between border-b border-solid border-gray-300 bg-white text-3xl">
{session ? (
<ColorButton text="Sign out" onClick={() => signOut()} />
) : (
<ColorButton text="Sign in" onClick={() => signIn()} />
)}
</header>
);
}
Sign in 버튼을 누르면
구글로 로그인할 수 있는 버튼이 뜨고, 그 버튼을 누르면
로그인할 수 있다!
로그인하고 나면 Sign out 버튼으로 바뀐다.
그리고 Sign out을 누르면 다시 Sign in으로 변하는 걸 확인할 수 있다
▪ 로그인 UI 커스텀
지금은 기본으로 제공하는 UI를 사용하는데, 구글 로그인만 사용할 게 아니라 다른 로그인 방법도 함께 사용해야 하는 경우가 대부분일 것이다.
그러기 위해서는 로그인 UI를 커스텀해줄 수 있다.
import NextAuth from 'next-auth';
import GoogleProvider from 'next-auth/providers/google';
const authOptions: NextAuthOptions = {
pages: {
signIn: 'login',
},
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_OAUTH_ID || '',
clientSecret: process.env.GOOGLE_OAUTH_SECRET || '',
}),
],
};
const handler = NextAuth(authOptions);
export { authOptions, handler as GET, handler as POST };
providers를 추가해준 handler에 로그인 페이지를 정의해준다.
이름은 꼭 login이 아니라 다른 것으로 설정해도 된다.
그러고나서는 src/app/api/auth/login/page.tsx 로 페이지를 생성해 준다.
만약 login이 아닌 다른 걸로 signIn에 정의했다면 src/app/api/auth /원하는파일명/page.tsx 로 페이지를 생성해주면 된다.
src/app/api/auth /원하는파일명/page.tsx
* 복사용! *
테스트용으로 임시 로그인 페이지를 구현해보았다.
이번엔 Sign in 버튼을 누르면 내가 커스텀한 UI가 표시된다!
import { getServerSession } from 'next-auth';
import { authOptions } from '@/app/api/auth/[...nextauth]/route';
import { redirect } from 'next/navigation';
import { getProviders } from 'next-auth/react';
import Login from '@/components/Login';
interface LoginParams {
searchParams: {
callbackUrl: string;
};
}
export default async function LoginPage({
searchParams: { callbackUrl },
}: LoginParams) {
const session = await getServerSession(authOptions);
if (session) {
redirect('/');
}
const providers = (await getProviders()) ?? {};
return <Login providers={providers} callbackUrl={callbackUrl} />;
}
'use client';
import ColorButton from '@/components/ColorButton';
import { ClientSafeProvider, signIn } from 'next-auth/react';
export interface LoginProps {
providers: Record<string, ClientSafeProvider> | {};
callbackUrl: string;
}
export default function Login({ providers, callbackUrl }: LoginProps) {
return (
<div className="mt-[30%] flex items-center justify-center">
{providers &&
Object.values(providers).map(({ name, id }) => (
<ColorButton
key={id}
text={`Sign in with ${name}`}
onClick={() => signIn(id, { callbackUrl })}
size="medium"
/>
))}
</div>
);
}
▪ 로그인 callback
import NextAuth, { NextAuthOptions } from 'next-auth';
import GoogleProvider from 'next-auth/providers/google';
const authOptions: NextAuthOptions = {
pages: {
signIn: 'login',
},
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_OAUTH_ID || '',
clientSecret: process.env.GOOGLE_OAUTH_SECRET || '',
}),
],
callbacks: {
async signIn({ account, user, profile }) {
//처리
return true;
},
},
};
const handler = NextAuth(authOptions);
export { authOptions, handler as GET, handler as POST };
callbacks의 signIn은 로그인을 성공했을 경우 받는 함수이다.
로그인 정보를 받아오고 받아온 정보를 서버에 넘기는 등 로그인 후 작업을 처리한다.
'클라이언트 > Next.js' 카테고리의 다른 글
[Next.js] Sanity 사용하기 (0) | 2024.07.14 |
---|---|
[Next.js] Next에서 SWR 사용하기 (0) | 2024.07.12 |
[Next.js] Redirects, Rewrite (0) | 2024.06.29 |
[Next.js] 데이터 캐싱하기 (0) | 2024.06.27 |
[Next.js] Interception Routes와 Parallel Routes로 모달(Modal) 구현하기 (0) | 2024.06.25 |