treeru.com
개발

Better Auth로 Next.js 인증 구현하기 — 세션 관리부터 관리자 권한까지

2026-01-12
Treeru

Next.js에서 인증을 구현할 때 대부분 NextAuth(Auth.js)를 떠올립니다. 하지만 v5 마이그레이션의 복잡함, 커스터마이징의 어려움에 지쳤다면 Better Auth를 고려해보세요. 타입 안전한 API, 직관적인 세션 관리, 역할 기반 접근 제어까지 — 실전에서 쓸 수 있는 인증 시스템을 구축하는 과정을 정리했습니다.

TypeScript

타입 안전성

쿠키 기반

세션 관리

역할 분리

관리자 권한

SQLite

DB 연동

1Better Auth vs NextAuth 비교

NextAuth는 커뮤니티가 크고 프로바이더 지원이 풍부하지만, v5 마이그레이션과 커스터마이징에서 불편한 점이 많았습니다. Better Auth는 이런 불편함을 해소하기 위해 설계된 라이브러리입니다.

항목NextAuth (Auth.js)Better Auth
TypeScript 지원부분적 (타입 복잡)완전한 타입 추론
세션 방식JWT / DB 세션쿠키 기반 세션
커스터마이징콜백 체인 (복잡)직관적 플러그인
역할 관리직접 구현 필요내장 지원
소셜 로그인60+ 프로바이더주요 프로바이더
커뮤니티매우 큼성장 중

이메일/비밀번호 인증 + 관리자 권한이 주 목적이라면 Better Auth

소셜 로그인 프로바이더가 많이 필요하다면 NextAuth가 유리하지만, 자체 이메일/비밀번호 인증과 역할 기반 접근 제어가 핵심이라면 Better Auth가 훨씬 깔끔합니다.

2Better Auth 초기 설정

Better Auth는 서버 측 인스턴스와 클라이언트 측 인스턴스를 분리해서 구성합니다.Drizzle ORM + SQLite 가이드를 참고하면 데이터베이스 어댑터 설정이 간단해집니다.

# 패키지 설치

npm install better-auth

lib/auth.ts — 서버 측 설정

import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "./db";

export const auth = betterAuth({
  database: drizzleAdapter(db, { provider: "sqlite" }),
  emailAndPassword: {
    enabled: true,
    minPasswordLength: 8,
  },
  session: {
    expiresIn: 60 * 60 * 24 * 7,  // 7일
    updateAge: 60 * 60 * 24,       // 24시간마다 갱신
  },
});

lib/auth-client.ts — 클라이언트 측 설정

import { createAuthClient } from "better-auth/react";

export const authClient = createAuthClient({
  baseURL: process.env.NEXT_PUBLIC_SITE_URL,
});

export const { useSession, signIn, signUp, signOut } = authClient;

3이메일/비밀번호 인증

회원가입과 로그인은 클라이언트에서 signUpsignIn 함수를 호출하면 됩니다. Better Auth가 비밀번호 해싱, 세션 생성, 쿠키 설정을 자동으로 처리합니다.

회원가입 예시

const handleSignUp = async () => {
  const result = await signUp.email({
    email: "user@example.com",
    password: "securePassword123",
    name: "홍길동",
  });

  if (result.error) {
    // 에러 처리 (이메일 중복 등)
    console.error(result.error.message);
  } else {
    // 회원가입 성공 → 자동 로그인
    router.push("/dashboard");
  }
};

로그인 예시

const handleSignIn = async () => {
  const result = await signIn.email({
    email: "user@example.com",
    password: "securePassword123",
  });

  if (result.error) {
    // 로그인 실패 처리
    setError("이메일 또는 비밀번호가 올바르지 않습니다.");
  } else {
    // 로그인 성공
    router.push("/dashboard");
  }
};

4세션 관리

Better Auth는 쿠키 기반 세션을 사용합니다. 서버 컴포넌트에서는 headers를 통해, 클라이언트 컴포넌트에서는 useSession 훅을 통해 세션 정보를 가져올 수 있습니다.

서버 컴포넌트에서 세션 확인

import { auth } from "@/lib/auth";
import { headers } from "next/headers";

export default async function DashboardPage() {
  const session = await auth.api.getSession({
    headers: await headers(),
  });

  if (!session) {
    redirect("/auth/login");
  }

  return <div>안녕하세요, {session.user.name}님</div>;
}

클라이언트 컴포넌트에서 세션 확인

"use client";
import { useSession, signOut } from "@/lib/auth-client";

export default function UserMenu() {
  const { data: session, isPending } = useSession();

  if (isPending) return <div>로딩 중...</div>;
  if (!session) return <Link href="/auth/login">로그인</Link>;

  return (
    <div>
      <span>{session.user.name}</span>
      <button onClick={() => signOut()}>로그아웃</button>
    </div>
  );
}
세션 설정권장 값설명
expiresIn7일세션 만료 시간
updateAge24시간세션 자동 갱신 간격
cookieName기본값세션 쿠키 이름 (커스텀 가능)

5관리자 역할 분리

일반 사용자와 관리자를 구분하려면 사용자 테이블에 role 필드를 추가하고, API 라우트나 페이지에서 역할을 검증하는 미들웨어를 만들면 됩니다.

lib/admin-auth.ts — 관리자 검증 유틸

import { auth } from "@/lib/auth";
import { headers } from "next/headers";
import { NextResponse } from "next/server";

export async function requireAdmin() {
  const session = await auth.api.getSession({
    headers: await headers(),
  });

  if (!session || session.user.role !== "admin") {
    return null;
  }

  return session;
}

// API 라우트에서 사용
export async function adminGuard() {
  const session = await requireAdmin();
  if (!session) {
    return NextResponse.json(
      { error: "권한이 없습니다" },
      { status: 403 }
    );
  }
  return session;
}

관리자 전용 API 라우트 예시

// app/api/admin/members/route.ts
import { adminGuard } from "@/lib/admin-auth";

export async function GET() {
  const session = await adminGuard();
  if (session instanceof NextResponse) return session;

  // 관리자만 접근 가능한 로직
  const members = await db.select().from(users);
  return NextResponse.json({ members });
}

관리자 계정은 반드시 시드 스크립트로 생성하세요

회원가입 페이지에서 관리자 계정을 만들 수 있게 하면 보안 문제가 됩니다. 관리자 계정은 시드 스크립트(seed script)로 직접 DB에 생성하고, 일반 회원가입 과정에서는 role이 항상 "user"로 설정되도록 해야 합니다.

6보안 강화 포인트

인증 시스템은 보안이 가장 중요합니다. Better Auth는 기본적인 보안을 제공하지만, 추가로 신경 써야 할 부분들이 있습니다.

보안 항목Better Auth 기본추가 설정
비밀번호 해싱scrypt 자동 적용커스텀 해싱 함수 설정 가능
CSRF 보호내장SameSite 쿠키 설정
Rate Limiting기본적미들웨어에서 강화 권장
세션 고정 방지자동로그인 시 세션 재생성
비밀번호 정책최소 길이만복잡성 검증 추가 권장

AUTH_SECRET은 반드시 강력한 랜덤 문자열을 사용하세요

AUTH_SECRET 환경변수는 세션 암호화에 사용됩니다. 이 값이 노출되면 세션 위조가 가능해집니다. openssl rand -base64 32로 생성한 랜덤 문자열을 사용하고, 절대 Git에 커밋하지 마세요.

요약 체크리스트

Better Auth 인증 구현 핵심 요약

  • 서버(auth.ts)와 클라이언트(auth-client.ts)를 분리해서 설정한다
  • 이메일/비밀번호 인증은 signUp.email, signIn.email로 구현한다
  • 서버 컴포넌트에서는 auth.api.getSession, 클라이언트에서는 useSession을 쓴다
  • 관리자 역할은 role 필드로 구분하고 미들웨어로 검증한다
  • 관리자 계정은 시드 스크립트로만 생성한다
  • AUTH_SECRET은 강력한 랜덤 문자열을 사용하고 Git에 커밋하지 않는다

본 글은 Better Auth의 기본 사용법을 다루며, 프로덕션 환경에서는 추가적인 보안 감사가 필요합니다. 인증 시스템의 보안 취약점은 서비스 전체에 영향을 미칠 수 있으므로 전문가 검토를 권장합니다. 본 콘텐츠의 비상업적 공유는 자유이나, 상업적 이용 시 문의 페이지를 통해 연락 바랍니다.

웹 서비스 인증 시스템이 필요하신가요?

Treeru는 Better Auth 기반의 인증 시스템, 관리자 페이지, API 설계까지 풀스택 웹 서비스를 구축해 드립니다.

웹 개발 상담 신청
T

Treeru

웹 개발, IT 인프라, AI 솔루션 분야의 실무 인사이트를 공유합니다. 기업의 디지털 전환을 돕는 IT 파트너, Treeru입니다.

공유

댓글

(5개)
4.40/ 5

로그인하면 댓글을 작성할 수 있습니다.

2026-01-24
454.0

SQLite + Drizzle ORM과 연동하는 부분이 딱 제가 찾던 조합입니다. PostgreSQL 없이도 인증 시스템이 잘 돌아가네요.

2026-01-21
555.0

CSRF 토큰, 비밀번호 해싱, 세션 만료 설정을 다뤄주셔서 감사합니다. 인증 구현할 때 보안 부분을 빠뜨리는 글이 많은데, 이 글은 꼼꼼하네요.

2026-01-19
4.554.5

클라이언트 측 auth 훅 사용법이 명확해서 좋았습니다. useSession 하나로 로그인 상태를 관리할 수 있다는 게 편리하네요.

관련 글

© 2026 TreeRU. All rights reserved.

본 콘텐츠의 저작권은 TreeRU에 있으며, 출처를 밝히지 않은 무단 전재 및 재배포를 금합니다. 인용 시 출처(treeru.com)를 반드시 명시해 주세요.