Choorai
Lv.3 Next.js

NextAuth.js 인증 가이드

NextAuth.js(Auth.js)는 Next.js를 위한 풀스택 인증 솔루션입니다. OAuth, 이메일 로그인, DB 세션을 모두 지원합니다.

Next.js 전용

NextAuth.js는 Next.js에서만 사용할 수 있습니다. 일반 React 앱은 Clerk을 사용하세요.

왜 NextAuth인가요?

  • Next.js App Router 완벽 지원
  • 50+ OAuth 프로바이더 지원
  • 서버 컴포넌트에서 세션 접근 가능
  • Prisma, Drizzle 등 DB 어댑터 제공
  • 무료 & 오픈소스

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_SECRETopenssl 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를 선택할까요?

NextAuth 추천

  • Next.js 풀스택 프로젝트
  • 서버 컴포넌트에서 세션 필요
  • DB에 사용자 정보 저장 필요
  • 무료 솔루션 선호

다른 선택지 고려

  • React SPA → Clerk
  • 빠른 UI 필요 → Clerk
  • 엔터프라이즈 → Auth0

다음 단계

마지막 업데이트: 2026년 2월 22일 · 버전: v0.0.1

피드백 보내기

입력한 내용으로 새 이슈 페이지를 엽니다.

GitHub 이슈로 보내기