설치

패키지 설치

먼저 프로젝트에 Better Auth를 추가해 보겠습니다:

npm install better-auth

별도의 클라이언트와 서버 설정을 사용하는 경우 프로젝트의 양쪽 부분에 Better Auth를 설치해야 합니다.

환경 변수 설정

프로젝트 루트에 .env 파일을 생성하고 다음 환경 변수를 추가합니다:

  1. 비밀 키

라이브러리에서 암호화 및 해시 생성에 사용하는 무작위 값입니다. 아래 버튼을 사용하여 생성하거나 openssl과 같은 도구를 사용할 수 있습니다.

.env
BETTER_AUTH_SECRET=
  1. 기본 URL 설정
.env
BETTER_AUTH_URL=http://localhost:3000 # 앱의 기본 URL

Better Auth 인스턴스 생성

다음 위치 중 하나에 auth.ts라는 파일을 생성합니다:

  • 프로젝트 루트
  • lib/ 폴더
  • utils/ 폴더

이러한 폴더를 src/, app/ 또는 server/ 폴더 아래에 중첩할 수도 있습니다. (예: src/lib/auth.ts, app/lib/auth.ts)

이 파일에서 Better Auth를 가져와 인증 인스턴스를 생성합니다. 변수 이름 auth로 내보내거나 default export로 내보내야 합니다.

auth.ts
import { betterAuth } from "better-auth";

export const auth = betterAuth({
  //...
});

데이터베이스 구성

Better Auth는 사용자 데이터를 저장하기 위해 데이터베이스가 필요합니다. Better Auth를 SQLite, PostgreSQL, MySQL 등을 사용하도록 쉽게 구성할 수 있습니다!

auth.ts
import { betterAuth } from "better-auth";
import Database from "better-sqlite3";

export const auth = betterAuth({
    database: new Database("./sqlite.db"),
})
auth.ts
import { betterAuth } from "better-auth";
import { Pool } from "pg";

export const auth = betterAuth({
    database: new Pool({
        // 연결 옵션
    }),
})
auth.ts
import { betterAuth } from "better-auth";
import { createPool } from "mysql2/promise";

export const auth = betterAuth({
    database: createPool({
        // 연결 옵션
    }),
})

또는 ORM을 사용하려는 경우 내장된 어댑터 중 하나를 사용할 수 있습니다.

auth.ts
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "@/db"; // drizzle 인스턴스

export const auth = betterAuth({
    database: drizzleAdapter(db, {
        provider: "pg", // 또는 "mysql", "sqlite"
    }),
});
auth.ts
import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
// Prisma 파일이 다른 곳에 있는 경우 경로를 변경할 수 있습니다
import { PrismaClient } from "@/generated/prisma";

const prisma = new PrismaClient();
export const auth = betterAuth({
    database: prismaAdapter(prisma, {
        provider: "sqlite", // 또는 "mysql", "postgresql", ...등
    }),
});
auth.ts
import { betterAuth } from "better-auth";
import { mongodbAdapter } from "better-auth/adapters/mongodb";
import { client } from "@/db"; // mongodb 클라이언트

export const auth = betterAuth({
    database: mongodbAdapter(client),
});

데이터베이스가 위 목록에 없는 경우 지원되는 다른 데이터베이스를 확인하거나 지원되는 ORM 중 하나를 사용하세요.

데이터베이스 테이블 생성

Better Auth에는 라이브러리에서 필요한 스키마를 관리하는 데 도움이 되는 CLI 도구가 포함되어 있습니다.

  • Generate: 이 명령은 ORM 스키마 또는 SQL 마이그레이션 파일을 생성합니다.

Kysely를 사용하는 경우 아래의 migrate 명령으로 마이그레이션을 직접 적용할 수 있습니다. 마이그레이션을 수동으로 적용할 계획인 경우에만 generate를 사용하세요.

Terminal
npx @better-auth/cli generate
  • Migrate: 이 명령은 데이터베이스에 필요한 테이블을 직접 생성합니다. (내장된 Kysely 어댑터에서만 사용 가능)
Terminal
npx @better-auth/cli migrate

자세한 내용은 CLI 문서를 참조하세요.

대신 스키마를 수동으로 생성하려면 데이터베이스 섹션에서 필요한 핵심 스키마를 찾을 수 있습니다.

인증 방법

사용하려는 인증 방법을 구성합니다. Better Auth는 이메일/비밀번호 및 소셜 로그인 프로바이더에 대한 기본 지원을 제공합니다.

auth.ts
import { betterAuth } from "better-auth";

export const auth = betterAuth({
  //...다른 옵션
  emailAndPassword: { 
    enabled: true, 
  }, 
  socialProviders: { 
    github: { 
      clientId: process.env.GITHUB_CLIENT_ID as string, 
      clientSecret: process.env.GITHUB_CLIENT_SECRET as string, 
    }, 
  }, 
});

플러그인을 통해 패스키, 사용자명, 매직 링크 등 더 많은 인증 방법을 사용할 수 있습니다.

핸들러 마운트

API 요청을 처리하려면 서버에 라우트 핸들러를 설정해야 합니다.

프레임워크에서 지정한 catch-all 라우트 핸들러에 새 파일 또는 라우트를 생성합니다. 이 라우트는 /api/auth/* 경로에 대한 요청을 처리해야 합니다. (다른 기본 경로를 구성하지 않은 경우)

Better Auth는 표준 Request 및 Response 객체가 있는 모든 백엔드 프레임워크를 지원하며 인기 있는 프레임워크에 대한 헬퍼 함수를 제공합니다.

/app/api/auth/[...all]/route.ts
import { auth } from "@/lib/auth"; // 인증 파일 경로
import { toNextJsHandler } from "better-auth/next-js";

export const { POST, GET } = toNextJsHandler(auth);
/server/api/auth/[...all].ts
import { auth } from "~/utils/auth"; // 인증 파일 경로

export default defineEventHandler((event) => {
    return auth.handler(toWebRequest(event));
});
hooks.server.ts
import { auth } from "$lib/auth"; // 인증 파일 경로
import { svelteKitHandler } from "better-auth/svelte-kit";
import { building } from '$app/environment'

export async function handle({ event, resolve }) {
    return svelteKitHandler({ event, resolve, auth, building });
}
/app/routes/api.auth.$.ts
import { auth } from '~/lib/auth.server' // 필요에 따라 경로 조정
import type { LoaderFunctionArgs, ActionFunctionArgs } from "@remix-run/node"

export async function loader({ request }: LoaderFunctionArgs) {
    return auth.handler(request)
}

export async function action({ request }: ActionFunctionArgs) {
    return auth.handler(request)
}
/routes/api/auth/*all.ts
import { auth } from "~/lib/auth"; // 인증 파일 경로
import { toSolidStartHandler } from "better-auth/solid-start";

export const { GET, POST } = toSolidStartHandler(auth);
src/index.ts
import { Hono } from "hono";
import { auth } from "./auth"; // 인증 파일 경로
import { serve } from "@hono/node-server";
import { cors } from "hono/cors";

const app = new Hono();

app.on(["POST", "GET"], "/api/auth/*", (c) => auth.handler(c.req.raw));

serve(app);
src/index.ts
import { auth } from "./auth"; // 인증 파일 경로

export default {
    async fetch(request: Request) {
        const url = new URL(request.url);

        // 인증 라우트 처리
        if (url.pathname.startsWith("/api/auth")) {
            return auth.handler(request);
        }

        // 다른 라우트 처리
        return new Response("Not found", { status: 404 });
    },
};

Node.js AsyncLocalStorage 지원: Better Auth는 비동기 컨텍스트 추적을 위해 AsyncLocalStorage를 사용합니다. Cloudflare Workers에서 이를 활성화하려면 wrangler.tomlnodejs_compat 플래그를 추가하세요:

wrangler.toml
compatibility_flags = ["nodejs_compat"]
compatibility_date = "2024-09-23"

또는 AsyncLocalStorage 지원만 필요한 경우:

wrangler.toml
compatibility_flags = ["nodejs_als"]

다음 주요 릴리스에서는 AsyncLocalStorage 지원을 기본으로 가정하므로 이 구성이 필요합니다.

ExpressJS v5는 path-to-regexp@6으로 전환하여 라우트 경로 일치에 중대한 변경 사항을 도입했습니다. *와 같은 와일드카드 라우트는 이제 새로운 명명된 구문을 사용하여 작성해야 합니다. 예를 들어 /{*any}와 같이 catch-all 패턴을 올바르게 캡처해야 합니다. 이는 라우팅 시나리오 전반에서 호환성과 예측 가능한 동작을 보장합니다. 자세한 내용은 Express v5 마이그레이션 가이드를 참조하세요.

결과적으로 ExpressJS v5의 구현은 다음과 같아야 합니다:

app.all('/api/auth/{*any}', toNodeHandler(auth));

이름 any는 임의적이며 원하는 식별자로 바꿀 수 있습니다.

server.ts
import express from "express";
import { toNodeHandler } from "better-auth/node";
import { auth } from "./auth";

const app = express();
const port = 8000;

app.all("/api/auth/*", toNodeHandler(auth));

// Better Auth 핸들러 이후에 express json 미들웨어를 마운트하거나
// Better Auth와 상호 작용하지 않는 라우트에만 적용하세요
app.use(express.json());

app.listen(port, () => {
    console.log(`Better Auth 앱이 포트 ${port}에서 실행 중입니다`);
});

이것은 express, fastify, hapi 등과 같은 다른 노드 서버 프레임워크에서도 작동하지만 일부 수정이 필요할 수 있습니다. fastify 가이드를 참조하세요. CommonJS(cjs)는 지원되지 않습니다.

/pages/api/auth/[...all].ts
import type { APIRoute } from "astro";
import { auth } from "@/auth"; // 인증 파일 경로

export const GET: APIRoute = async (ctx) => {
    return auth.handler(ctx.request);
};

export const POST: APIRoute = async (ctx) => {
    return auth.handler(ctx.request);
};
import { Elysia, Context } from "elysia";
import { auth } from "./auth";

const betterAuthView = (context: Context) => {
    const BETTER_AUTH_ACCEPT_METHODS = ["POST", "GET"]
    // 요청 메서드 검증
    if(BETTER_AUTH_ACCEPT_METHODS.includes(context.request.method)) {
        return auth.handler(context.request);
    } else {
        context.error(405)
    }
}

const app = new Elysia().all("/api/auth/*", betterAuthView).listen(3000);

console.log(
`🦊 Elysia가 ${app.server?.hostname}:${app.server?.port}에서 실행 중입니다`
);
src/routes/api/auth/$.ts
import { auth } from '~/lib/server/auth'
import { createServerFileRoute } from '@tanstack/react-start/server'

export const ServerRoute = createServerFileRoute('/api/auth/$').methods({
GET: ({ request }) => {
    return auth.handler(request)
},
POST: ({ request }) => {
    return auth.handler(request)
},
});
app/api/auth/[...all]+api.ts
import { auth } from '@/lib/server/auth'; // 인증 파일 경로

const handler = auth.handler;
export { handler as GET, handler as POST };

클라이언트 인스턴스 생성

클라이언트 측 라이브러리는 인증 서버와 상호 작용하는 데 도움이 됩니다. Better Auth는 바닐라 JavaScript를 포함한 모든 인기 있는 웹 프레임워크용 클라이언트를 제공합니다.

  1. 프레임워크에 맞는 패키지에서 createAuthClient를 가져옵니다. (예: React의 경우 "better-auth/react")
  2. 함수를 호출하여 클라이언트를 생성합니다.
  3. 인증 서버의 기본 URL을 전달합니다. (인증 서버가 클라이언트와 동일한 도메인에서 실행 중인 경우 이 단계를 건너뛸 수 있습니다.)

/api/auth가 아닌 다른 기본 경로를 사용하는 경우 경로를 포함한 전체 URL을 전달해야 합니다. (예: http://localhost:3000/custom-path/auth)

lib/auth-client.ts
import { createAuthClient } from "better-auth/client"
export const authClient = createAuthClient({
    /** 서버의 기본 URL (동일한 도메인을 사용하는 경우 선택사항) */
    baseURL: "http://localhost:3000"
})
lib/auth-client.ts
import { createAuthClient } from "better-auth/react"
export const authClient = createAuthClient({
    /** 서버의 기본 URL (동일한 도메인을 사용하는 경우 선택사항) */
    baseURL: "http://localhost:3000"
})
lib/auth-client.ts
import { createAuthClient } from "better-auth/vue"
export const authClient = createAuthClient({
    /** 서버의 기본 URL (동일한 도메인을 사용하는 경우 선택사항) */
    baseURL: "http://localhost:3000"
})
lib/auth-client.ts
import { createAuthClient } from "better-auth/svelte"
export const authClient = createAuthClient({
    /** 서버의 기본 URL (동일한 도메인을 사용하는 경우 선택사항) */
    baseURL: "http://localhost:3000"
})
lib/auth-client.ts
import { createAuthClient } from "better-auth/solid"
export const authClient = createAuthClient({
    /** 서버의 기본 URL (동일한 도메인을 사용하는 경우 선택사항) */
    baseURL: "http://localhost:3000"
})

팁: 원하는 경우 특정 메서드를 내보낼 수도 있습니다:

export const { signIn, signUp, useSession } = createAuthClient()

🎉 완료!

이제 애플리케이션에서 better-auth를 사용할 준비가 되었습니다! 기본 사용법으로 계속 진행하여 인증 인스턴스를 사용하여 사용자를 로그인시키는 방법을 알아보세요.

On this page