Docs
Better auth

1. Install

Xác thực user qua better-auth

1. Cài đặt better-auth

pnpm add better-auth

Packages: +26 ++++++++++++++++++++++++++ Progress: resolved 423, reused 357, downloaded 0, added 26, done

dependencies:

  • better-auth 1.3.4

2. Cập nhật file .env

BETTER_AUTH_SECRET=NGxDlgTN1nFWDwqOnrxNn4sGC9angt6u

Thiết lập base_url:

BETTER_AUTH_URL=http://localhost:3000 #Base URL of your app

Khi production thực tế, thay localhost bằng domain

3.Tạo file yêu cầu xác thực

Cần tạo ra file auth.ts để tiến hành xác thực

  • Nên để vị trí file: src/lib/auth.ts
  • Hoặc vị trí: src/utils/auth.ts
import { betterAuth } from "better-auth";
 
export const auth = betterAuth({
  //...
});

4.Cấu hình Database NEON và Prisma

Thêm cấu hình DB vào trong file auth.ts

  • Chọn Neon làm nơi lưu trữ thông tin người dùng
  • Chọn Prisma làm ORM

4.1 Cấu hình database NEON

  • Truy cập neon.tech
  • Tạo dự án mới
  • Ấn nút connect để lấy connection string

Cập nhật file .env

Thêm dòng sau:

DATABASE_URL="postgresql://neondb_owner:password@ep-late-mode-a1cbri6s-pooler.ap-southeast-1.aws.neon.tech/neondb?sslmode=require&channel_binding=require"

4.2 Cài đặt Prisma

Thêm Prisma
  1. Cài prisma ở chế độ phát triển
pnpm add -D prisma
  • Thêm mô tả vào package.json
"devDependencies": {
  "prisma": "^5.x.x"
}
  • bổ sung mã nguồn vào node_modules và .pnpm
  1. Cài client để kết nối với database
pnpm add @prisma/client
  1. Khởi tạo prisma
pnpm dlx prisma init
npx prisma init --db
  • Kiểm tra, bổ sung Database_url vào .env (nếu có rồi thì thôi)
  • Tạo thư mục prisma
  • Tạo file schema.prisma có cấu hình
datasource db {
  provider = "postgresql" // hoặc sqlite, mysql, v.v.
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}
  • thông số --db giúp prisma hỏi tên database và tự cấu hình. Nếu bạn chạy local, không cần dùng prisma cloud thì hãy bỏ qua tham só này
  1. Kết nối Better Auth với Prisma

Thông qua Adapter

import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
// If your Prisma file is located elsewhere, you can change the path
import { PrismaClient } from "@/generated/prisma";
 
const prisma = new PrismaClient();
export const auth = betterAuth({
    database: prismaAdapter(prisma, {
        provider: "sqlite", // or "mysql", "postgresql", ...etc
    }),
});

hoặc Drizzle (tham khảo phần Drizzle)

import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "@/db"; // your drizzle instance
 
export const auth = betterAuth({
    database: drizzleAdapter(db, {
        provider: "pg", // or "mysql", "sqlite"
    }),
});
  1. Tạo thư viện Prisma Client
pnpm prisma generate
  • Tạo ra thư viện trong src\generated\prisma

5. Tạo bảng cơ sở dữ liệu

Chuẩn hoá lại bảng dữ liệu trong schema

pnpm dlx @better-auth/cli generate
  • File prisma.schema sẽ được tạo lại, bạn gõ Y để ghi đè lên

√ The file ./prisma/schema.prisma already exists. Do you want to overwrite the schema to the file? ... yes 2025-08-05T02:37:49.926Z SUCCESS [Better Auth]: 🚀 Schema was overwritten successfully!

Chạy lệnh tạo bảng dữ liệu

pnpm prisma db push
  • Vào Neon để kiểm tra lại các bảng có tạo ra không

Environment variables loaded from .env Prisma schema loaded from prisma\schema.prisma Datasource "db": PostgreSQL database "neondb", schema "public" at "ep-old-recipe-a1ut1oji-pooler.ap-southeast-1.aws.neon.tech"

Your database is now in sync with your Prisma schema. Done in 2.65s

✔ Generated Prisma Client (v6.13.0) to .\src\generated\prisma in 115ms

6. Lựa chọn phương pháp xác thực

  • Cấu hình trong file auth.ts
  • Hỗ trợ các loại xác thực email/pass, oauth ..
import { betterAuth } from "better-auth";
 
export const auth = betterAuth({
  //...other options
  emailAndPassword: {
    enabled: true, 
  }, 
  socialProviders: {
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID as string, 
      clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, 
    }, 
  }, 
});

6.1 Sử dụng Email (mặc định)

export const auth = betterAuth({
  //...other options
  emailAndPassword: {
    enabled: true, 
  },
});
  • Nếu muốn tắt, chuyển true --> false

6.2 Sử dụng Oauth Google

Cập nhật lại file .env

# Oauth Google (hiai)
# Author URI Local = http://localhost:3000
# Redirect URI Local = http://localhost:3000/api/auth/callback/google
GOOGLE_CLIENT_ID="1050187222533-id84j5ifdv9s7crsvvg4mma79it0b3sa.apps.googleusercontent.com"
GOOGLE_CLIENT_SECRET="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"

7. Xử lý xác thực trên Backend

import { auth } from "@/lib/auth"; // path to your auth file
import { toNextJsHandler } from "better-auth/next-js";
 
export const { POST, GET } = toNextJsHandler(auth);
  • Endpoit trên BE để xử lý liên quan xác thực.

8. Client để gọi hàm signIn(), signUp(), signOut()

import { createAuthClient } from "better-auth/react"
export const authClient = createAuthClient({
    /** The base URL of the server (optional if you're using the same domain) */
    baseURL: "http://localhost:3000"
})

Thủ thuật tạo một instance Prisma duy nhất

⚙️ Nguyên nhân:

  • Next.js trong chế độ dev reload module liên tục.

  • Mỗi lần reload = tạo mới Prisma Client ⇒ nhiều instance cùng tồn tại.

✅ Giải pháp khuyên dùng:

  • Chỉ tạo 1 instance duy nhất bằng cách gán vào biến toàn cục (global):
import { PrismaClient } from "@prisma/client";

const globalForPrisma = global as unknown as { prisma: PrismaClient };

export const prisma =
  globalForPrisma.prisma || new PrismaClient();

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;

Ví dụ: Khi dùng lệnh tạo thư viện pnpm prisma generate

mặc định sẽ tạo src/generated/prisma

Khi đó lệnh import sẽ thành

import { PrismaClient } from "@/generated/prisma";