NextJS 系列 之 BetterAuth

Date
Created
Aug 20, 2025 02:31 AM
Descrption
好记性不如烂笔头
Tags
Next.js
三方库
全栈工程师
notion image
之前一直使用NextAuth,不过社区名声一直不好,文档陈旧,逻辑耦合严重,于是乎,大家用脚投票有了新选择BetterAuth:

BetterAuth:

Better Auth 是一个与框架无关的 TypeScript 身份验证和授权框架。它提供了一套全面的开箱即用功能,并包含一个插件生态系统,简化了高级功能的添加。无论您需要双因素身份验证 (2FA)、多租户、多会话支持,还是像单点登录 (SSO) 这样的企业级功能,它都能让您专注于构建应用程序,而无需重复造轮子。

1.安装:

bun add better-auth

2.设置环境变量:

// .env BETTER_AUTH_SECRET=

3.设置基本URL:

这个是给betterAuth用的,服务端都会基于这个host来进行请求
BETTER_AUTH_URL=http://localhost:3000 #Base URL of your app

4.初始化Auth:

// lib/auth.ts import { betterAuth } from 'better-auth' import { drizzleAdapter } from 'better-auth/adapters/drizzle' import { nextCookies } from 'better-auth/next-js' import { db } from '@/lib/db' // your drizzle instance import * as schema from '@/lib/db/schema' // 导入 schema //TEST-5 export const auth = betterAuth({ baseURL: process.env.BETTER_AUTH_URL || 'http://localhost:3000', trustedOrigins: [ 'http://localhost:3000', 'https://localhost:3000', ...(process.env.NODE_ENV === 'production' ? [process.env.BETTER_AUTH_URL || ''] : []), ], advanced: { cookiePrefix: '***',//你的cookie前缀 }, database: drizzleAdapter(db, { provider: 'pg', schema, }), emailAndPassword: { enabled: true, autoSignIn: true, }, socialProviders: { google: { clientId: process.env.GOOGLE_CLIENT_ID as string, clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, }, }, plugins: [ nextCookies(), // 确保这是最后一个插件 ], })

5.创建数据库表:

因为现在BetterAuth的业务逻辑确定使用了固定的数据库表,你不可以随便改这几张表,所以让他们保留着就好;
npx @better-auth/cli generate

6.处理路由:

要处理 API 请求,您需要在服务器上设置路由处理程序。
// app/api/ath/[...all]route.ts import { auth } from "@/lib/auth"; // path to your auth file import { toNextJsHandler } from "better-auth/next-js"; export const { POST, GET } = toNextJsHandler(auth);

7.创建客户端实例

建议你也自己封装一个客户端实例,这样不用每个地方都舒适化,写这坨胶水代码
// lib/auth-client.ts import { createAuthClient } from 'better-auth/react' export const authClient = createAuthClient() export const { signIn, signUp, signOut, useSession } = authClient

8.客户端使用:

使用session:
const { data: session } = authClient.useSession()
邮箱登录:
const { data, error } = await authClient.signIn.email({ /** * The user email */ email, /** * The user password */ password, /** * A URL to redirect to after the user verifies their email (optional) */ callbackURL: "/dashboard", /** * remember the user session after the browser is closed. * @default true */ rememberMe: false }, { //callbacks })
谷歌登录:
const signIn = async () => { await authClient.signIn.social({ provider: 'google', }) }
登出:
await authClient.signOut()

9.服务端使用:

// src/api/product/route.ts import { auth } from '@/lib/auth' import { auth } from '@/lib/auth' import { createProject, updateProject } from '@/lib/db/projects' import { NextResponse } from 'next/server' import { headers } from 'next/headers' import { logger } from '@/lib/logger' export async function POST(request: Request) { try { const { projectName } = await request.json() const session = await auth.api.getSession({ headers: await headers(), }) if (!session?.user?.id) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) } const userId = session.user.id const project = await createProject(projectName, userId) return NextResponse.json({ projectId: project.projectId }) } catch (error) { logger.error('Error in product route', { error }) return NextResponse.json( { error: 'Internal server error' }, { status: 500 } ) } }