1설치 및 환경 변수
터미널
npm install next-auth환경 변수 설정
.env.local
# .env.local
NEXTAUTH_SECRET=your-secret-key-here
NEXTAUTH_URL=http://localhost:3000
# Google OAuth (선택)
GOOGLE_CLIENT_ID=xxx
GOOGLE_CLIENT_SECRET=xxx
# GitHub OAuth (선택)
GITHUB_ID=xxx
GITHUB_SECRET=xxx정보
NEXTAUTH_SECRET은
openssl rand -base64 32로 생성할 수 있습니다.
2API Route 설정
NextAuth는 /api/auth/* 경로를 사용합니다.
app/api/auth/[...nextauth]/route.ts
// app/api/auth/[...nextauth]/route.ts
import NextAuth from 'next-auth';
import GoogleProvider from 'next-auth/providers/google';
import GitHubProvider from 'next-auth/providers/github';
import CredentialsProvider from 'next-auth/providers/credentials';
const handler = NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
}),
GitHubProvider({
clientId: process.env.GITHUB_ID!,
clientSecret: process.env.GITHUB_SECRET!,
}),
// 이메일/비밀번호 로그인 (직접 구현)
CredentialsProvider({
name: 'Credentials',
credentials: {
email: { label: 'Email', type: 'email' },
password: { label: 'Password', type: 'password' },
},
async authorize(credentials) {
// 여기서 DB 조회 및 비밀번호 검증
// 실제로는 bcrypt 등으로 해시 비교 필요
const user = await findUserByEmail(credentials?.email);
if (user && verifyPassword(credentials?.password, user.password)) {
return { id: user.id, email: user.email, name: user.name };
}
return null;
},
}),
],
pages: {
signIn: '/login', // 커스텀 로그인 페이지
error: '/auth/error',
},
callbacks: {
async session({ session, token }) {
// 세션에 사용자 ID 추가
if (token.sub) {
session.user.id = token.sub;
}
return session;
},
},
});
export { handler as GET, handler as POST };3SessionProvider 설정
클라이언트 컴포넌트에서 세션을 사용하려면 SessionProvider가 필요합니다.
app/providers.tsx & app/layout.tsx
// app/providers.tsx
'use client';
import { SessionProvider } from 'next-auth/react';
export function Providers({ children }: { children: React.ReactNode }) {
return <SessionProvider>{children}</SessionProvider>;
}
// app/layout.tsx
import { Providers } from './providers';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="ko">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}4클라이언트에서 세션 사용
components/AuthStatus.tsx
// components/AuthStatus.tsx
'use client';
import { useSession, signIn, signOut } from 'next-auth/react';
export function AuthStatus() {
const { data: session, status } = useSession();
if (status === 'loading') {
return <div>로딩 중...</div>;
}
if (status === 'unauthenticated') {
return (
<div className="flex gap-2">
<button
onClick={() => signIn('google')}
className="px-4 py-2 bg-white text-gray-800 rounded-lg border"
>
Google로 로그인
</button>
<button
onClick={() => signIn('github')}
className="px-4 py-2 bg-gray-800 text-white rounded-lg"
>
GitHub로 로그인
</button>
</div>
);
}
return (
<div className="flex items-center gap-4">
<span>안녕하세요, {session?.user?.name}님!</span>
<button
onClick={() => signOut()}
className="px-4 py-2 bg-red-600 text-white rounded-lg"
>
로그아웃
</button>
</div>
);
}5서버 컴포넌트에서 세션 사용
서버 컴포넌트에서는 getServerSession을 사용합니다.
app/dashboard/page.tsx
// app/dashboard/page.tsx
import { getServerSession } from 'next-auth';
import { redirect } from 'next/navigation';
import { authOptions } from '@/app/api/auth/[...nextauth]/route';
export default async function DashboardPage() {
const session = await getServerSession(authOptions);
if (!session) {
redirect('/login');
}
return (
<div>
<h1>대시보드</h1>
<p>환영합니다, {session.user?.name}님!</p>
</div>
);
}6미들웨어로 라우트 보호
특정 경로를 일괄적으로 보호하려면 미들웨어를 사용합니다.
middleware.ts
// middleware.ts
import { withAuth } from 'next-auth/middleware';
export default withAuth({
callbacks: {
authorized: ({ token }) => !!token,
},
});
// 보호할 경로 지정
export const config = {
matcher: ['/dashboard/:path*', '/settings/:path*', '/api/protected/:path*'],
};7데이터베이스 연동 (선택)
사용자 정보를 DB에 저장하려면 어댑터를 사용합니다.
Prisma 어댑터 설정
// 1. 패키지 설치
// npm install @prisma/client @next-auth/prisma-adapter
// npm install -D prisma
// 2. Prisma 스키마
// prisma/schema.prisma
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
}
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String? @db.Text
access_token String? @db.Text
expires_at Int?
token_type String?
scope String?
id_token String? @db.Text
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
}
model Session {
id String @id @default(cuid())
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
// 3. NextAuth 설정에 어댑터 추가
import { PrismaAdapter } from '@next-auth/prisma-adapter';
import { prisma } from '@/lib/prisma';
const handler = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [...],
});언제 NextAuth를 선택할까요?
다음 단계
- 더 많은 프로바이더 - 50+ OAuth 프로바이더 설정
- Callbacks - 세션/토큰 커스터마이징
- Supabase 연동 - 데이터베이스와 함께 사용