关于 better-auth
面向构建 Web 应用认证功能的开发者,提供 better-auth 配置与使用指南,涵盖适配器、框架设置、端点及插件,包括 MCP OAuth 提供方插件。
主要功能
- 01Drizzle 与 Kysely 适配器指南
- 02特定框架的配置说明
- 03认证端点参考
- 04组织与管理插件
- 05MCP OAuth 提供方插件
适用场景
- 01为 D1 数据库配置 better-auth
- 02在 TanStack Start 中设置认证
- 03添加组织和团队管理
- 04为 MCP 客户端提供 OAuth
MCP 相关
MCP 插件可让 better-auth 充当 MCP 客户端的 OAuth 提供方。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ ovachiever/ droid-tings --skill better-auth安装后在 Claude Code 中输入/better-auth确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.md.claude-plugin/plugin.jsonassets/auth-flow-diagram.mdreferences/cloudflare-worker-drizzle.tscloudflare-worker-kysely.tsdatabase-schema.tsreact-client-hooks.tsxreferences/nextjs/postgres-example.tsREADME.mdscripts/setup-d1-drizzle.sh详细介绍
better-auth - D1 适配器与错误预防指南
软件包:[email protected](2025 年 11 月 22 日) 破坏性变更:仅支持 ESM(v1.4.0)、多团队表变更(v1.3)、D1 需要 Drizzle/Kysely(无直接适配器)
⚠️ 重要:D1 适配器要求
better-auth 没有 d1Adapter()。你必须使用:
- Drizzle ORM(推荐):
drizzleAdapter(db, { provider: "sqlite" }) - Kysely:
new Kysely({ dialect: new D1Dialect({ database: env.DB }) })
详情请参阅下方问题 #1。
v1.4.0 新增内容(2025 年 11 月 22 日)
主要功能:
- 无状态会话管理 - 无需数据库存储的会话
- 仅支持 ESM 的软件包 ⚠️ 破坏性变更:不再支持 CommonJS
- JWT 密钥轮换 - 自动轮换密钥,增强安全性
- SCIM 配置 - 企业用户配置协议
- @standard-schema/spec - 替代用于验证的 ZodType
- CaptchaFox 集成 - 内置 CAPTCHA 支持
- 自动检测服务端 IP
- 基于 Cookie 的账户数据存储
- 支持多个通行密钥来源
- RP 发起的注销端点(OIDC)
📚 文档:https://www.better-auth.com/changelogs
v1.3 新增内容(2025 年 7 月)
主要功能:
- 支持 SAML 2.0 的 SSO - 企业单点登录(已移至单独的
@better-auth/sso软件包) - 多团队支持 ⚠️ 破坏性变更:从成员表中移除
teamId,需要新增teamMembers表 - 附加字段 - 为组织/成员/邀请模型添加自定义字段
- 性能改进和错误修复
📚 文档:https://www.better-auth.com/blog/1-3
替代方案:Kysely 适配器模式
如果你更喜欢使用 Kysely 而非 Drizzle:
文件:src/auth.ts
import { betterAuth } from "better-auth";
import { Kysely, CamelCasePlugin } from "kysely";
import { D1Dialect } from "kysely-d1";
type Env = {
DB: D1Database;
BETTER_AUTH_SECRET: string;
// ... other env vars
};
export function createAuth(env: Env) {
return betterAuth({
secret: env.BETTER_AUTH_SECRET,
// Kysely with D1Dialect
database: {
db: new Kysely({
dialect: new D1Dialect({
database: env.DB,
}),
plugins: [
// CRITICAL: Required if using Drizzle schema with snake_case
new CamelCasePlugin(),
],
}),
type: "sqlite",
},
emailAndPassword: {
enabled: true,
},
// ... other config
});
}
为什么需要 CamelCasePlugin?
如果你的 Drizzle 架构使用 snake_case 列名(例如 email_verified),而 better-auth 需要的是 camelCase(例如 emailVerified),CamelCasePlugin 会自动在两者之间转换。
框架集成
TanStack Start
⚠️ 重要:TanStack Start 需要 reactStartCookies 插件才能正确处理 Cookie 设置。
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { reactStartCookies } from "better-auth/react-start";
export const auth = betterAuth({
database: drizzleAdapter(db, { provider: "sqlite" }),
plugins: [
twoFactor(),
organization(),
reactStartCookies(), // ⚠️ MUST be LAST plugin
],
});
为什么需要它:TanStack Start 使用一种特殊的 Cookie 处理系统。没有此插件,signInEmail() 和 signUpEmail() 等身份验证函数将无法正确设置 Cookie,导致身份验证失败。
重要:reactStartCookies 插件必须是数组中的最后一个插件。
API 路由设置(/src/routes/api/auth/$.ts):
import { auth } from '@/lib/auth'
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/api/auth/$')({
server: {
handlers: {
GET: ({ request }) => auth.handler(request),
POST: ({ request }) => auth.handler(request),
},
},
})
📚 官方文档:https://www.better-auth.com/docs/integrations/tanstack
可用插件(v1.3+)
Better Auth 提供用于高级身份验证功能的插件:
| 插件 | 导入 | 说明 | 文档 |
|---|---|---|---|
| OIDC 提供方 | better-auth/plugins | 构建自己的 OpenID Connect 提供方(为其他应用充当 OAuth 提供方) | 📚 |
| SSO | better-auth/plugins | 支持 OIDC、OAuth2 和 SAML 2.0 的企业单点登录 | 📚 |
| Stripe | better-auth/plugins | 支付和订阅管理(自 v1.3+ 起稳定) | 📚 |
| MCP | better-auth/plugins | 为模型上下文协议(MCP)客户端充当 OAuth 提供方 | 📚 |
| Expo | better-auth/expo | React Native/Expo 集成,支持安全的 Cookie 管理 | 📚 |
API 参考
概览:你可免费获得的功能
调用 auth.handler() 时,better-auth 会自动在 /api/auth/* 下暴露 80 多个可用于生产环境的 REST 端点。每个端点也都可通过 auth.api.* 作为服务端方法使用,以便通过代码调用。
这种双层 API 系统意味着:
- 客户端(React、Vue、移动应用)可直接调用 HTTP 端点
- 服务端代码(中间件、后台任务)使用
auth.api.*方法 - 零样板代码——无需手动编写身份验证端点
节省时间:从头构建约需 220 小时。使用 better-auth 约需 4–8 小时。减少 97%。
自动生成的 HTTP 端点
使用 auth.handler() 时,所有端点都会自动在 /api/auth/* 下暴露。
核心身份验证端点
| 端点 | 方法 | 描述 |
|---|---|---|
/sign-up/email | POST | 使用电子邮件/密码注册 |
/sign-in/email | POST | 使用电子邮件/密码进行身份验证 |
/sign-out | POST | 用户登出 |
/change-password | POST | 更新密码(需要当前密码) |
/forget-password | POST | 发起密码重置流程 |
/reset-password | POST | 使用令牌完成密码重置 |
/send-verification-email | POST | 发送电子邮件验证链接 |
/verify-email | GET | 使用令牌验证电子邮件(?token=<token>) |
/get-session | GET | 获取当前会话 |
/list-sessions | GET | 获取用户的所有活动会话 |
/revoke-session | POST | 结束指定会话 |
/revoke-other-sessions | POST | 结束除当前会话外的所有会话 |
/revoke-sessions | POST | 结束用户的所有会话 |
/update-user | POST | 修改用户资料(姓名、图片) |
/change-email | POST | 更新电子邮件地址 |
/set-password | POST | 为仅使用 OAuth 的账户添加密码 |
/delete-user | POST | 删除用户账户 |
/list-accounts | GET | 获取已关联的身份验证提供商 |
/link-social | POST | 将 OAuth 提供商关联到账户 |
/unlink-account | POST | 取消关联提供商 |
社交 OAuth 端点
| 端点 | 方法 | 描述 |
|---|---|---|
/sign-in/social | POST | 发起 OAuth 流程(在请求正文中指定提供商) |
/callback/:provider | GET | OAuth 回调处理程序(例如,/callback/google) |
/get-access-token | GET | 获取提供商访问令牌 |
OAuth 流程示例:
// Client initiates
await authClient.signIn.social({
provider: "google",
callbackURL: "/dashboard",
});
// better-auth handles redirect to Google
// Google redirects back to /api/auth/callback/google
// better-auth creates session automatically
插件端点
双重身份验证(2FA 插件)
import { twoFactor } from "better-auth/plugins";
| 端点 | 方法 | 描述 |
|---|---|---|
/two-factor/enable | POST | 为用户启用 2FA |
/two-factor/disable | POST | 停用 2FA |
/two-factor/get-totp-uri | GET | 获取身份验证器应用的二维码 URI |
/two-factor/verify-totp | POST | 验证身份验证器中的 TOTP 代码 |
/two-factor/send-otp | POST | 通过电子邮件发送 OTP |
/two-factor/verify-otp | POST | 验证电子邮件 OTP |
/two-factor/generate-backup-codes | POST | 生成恢复代码 |
/two-factor/verify-backup-code | POST | 使用备用代码登录 |
/two-factor/view-backup-codes | GET | 查看当前备用代码 |
📚 文档:https://www.better-auth.com/docs/plugins/2fa
组织插件(多租户 SaaS)
import { organization } from "better-auth/plugins";
组织(10 个端点):
| Endpoint | Method | Description |
|---|---|---|
/organization/create | POST | 创建组织 |
/organization/list | GET | 列出用户的组织 |
/organization/get-full | GET | 获取完整的组织详情 |
/organization/update | PUT | 修改组织 |
/organization/delete | DELETE | 移除组织 |
/organization/check-slug | GET | 检查 slug 是否可用 |
/organization/set-active | POST | 设置当前组织上下文 |
成员(8 个端点):
| Endpoint | Method | Description |
|---|---|---|
/organization/list-members | GET | 获取组织成员 |
/organization/add-member | POST | 直接添加成员 |
/organization/remove-member | DELETE | 移除成员 |
/organization/update-member-role | PUT | 更改成员角色 |
/organization/get-active-member | GET | 获取当前成员信息 |
/organization/leave | POST | 离开组织 |
邀请(7 个端点):
| Endpoint | Method | Description |
|---|---|---|
/organization/invite-member | POST | 发送邀请邮件 |
/organization/accept-invitation | POST | 接受邀请 |
/organization/reject-invitation | POST | 拒绝邀请 |
/organization/cancel-invitation | POST | 取消待处理的邀请 |
/organization/get-invitation | GET | 获取邀请详情 |
/organization/list-invitations | GET | 列出组织邀请 |
/organization/list-user-invitations | GET | 列出用户待处理的邀请 |
团队(8 个端点):
| Endpoint | Method | Description |
|---|---|---|
/organization/create-team | POST | 在组织内创建团队 |
/organization/list-teams | GET | 列出组织团队 |
/organization/update-team | PUT | 修改团队 |
/organization/remove-team | DELETE | 移除团队 |
/organization/set-active-team | POST | 设置当前团队上下文 |
/organization/list-team-members | GET | 列出团队成员 |
/organization/add-team-member | POST | 将成员添加到团队 |
/organization/remove-team-member | DELETE | 移除团队成员 |
权限与角色(6 个端点):
| Endpoint | Method | Description |
|---|---|---|
/organization/has-permission | POST | 检查用户是否拥有权限 |
/organization/create-role | POST | 创建自定义角色 |
/organization/delete-role | DELETE | 删除自定义角色 |
/organization/list-roles | GET | 列出所有角色 |
/organization/get-role | GET | 获取角色详情 |
/organization/update-role | PUT | 修改角色权限 |
📚 文档:https://www.better-auth.com/docs/plugins/organization
管理员插件
import { admin } from "better-auth/plugins";
| Endpoint | Method | Description |
|---|---|---|
/admin/create-user | POST | 以管理员身份创建用户 |
/admin/list-users | GET | 列出所有用户(支持筛选和分页) |
/admin/set-role | POST | 为用户分配角色 |
/admin/set-user-password | POST | 更改用户密码 |
/admin/update-user | PUT | 修改用户详情 |
/admin/remove-user | DELETE | 删除用户账户 |
/admin/ban-user | POST | 封禁用户账户 |
/admin/unban-user | POST | 解封用户 |
/admin/list-user-sessions | GET | 获取用户的活跃会话 |
/admin/revoke-user-session | DELETE | 结束指定的用户会话 |
/admin/revoke-user-sessions | DELETE | 结束用户的所有会话 |
/admin/impersonate-user | POST | 开始模拟用户身份 |
/admin/stop-impersonating | POST | 结束模拟会话 |
📚 文档:https://www.better-auth.com/docs/plugins/admin
其他插件端点
Passkey 插件(5 个端点)- 文档:
/passkey/add、/sign-in/passkey、/passkey/list、/passkey/delete、/passkey/update
Magic Link 插件(2 个端点)- 文档:
/sign-in/magic-link、/magic-link/verify
Username 插件(2 个端点)- 文档:
/sign-in/username、/username/is-available
Phone Number 插件(5 个端点)- 文档:
/sign-in/phone-number、/phone-number/send-otp、/phone-number/verify、/phone-number/request-password-reset、/phone-number/reset-password
Email OTP 插件(6 个端点)- 文档:
/email-otp/send-verification-otp、/email-otp/check-verification-otp、/sign-in/email-otp、/email-otp/verify-email、/forget-password/email-otp、/email-otp/reset-password
Anonymous 插件(1 个端点)- 文档:
/sign-in/anonymous
JWT 插件(2 个端点)- 文档:
/token(获取 JWT)、/jwks(用于验证的公钥)
OpenAPI 插件(2 个端点)- 文档:
/reference(使用 Scalar UI 的交互式 API 文档)/generate-openapi-schema(以 JSON 格式获取 OpenAPI 规范)
服务端 API 方法(auth.api.*)
每个 HTTP 端点都有对应的服务端方法。可用于:
- 服务端中间件(保护路由)
- 后台任务(用户清理、通知)
- 管理员操作(批量管理用户)
- 自定义身份验证流程(以编程方式创建会话)
核心 API 方法
// Authentication
await auth.api.signUpEmail({
body: { email, password, name },
headers: request.headers,
});
await auth.api.signInEmail({
body: { email, password, rememberMe: true },
headers: request.headers,
});
await auth.api.signOut({ headers: request.headers });
// Session Management
const session = await auth.api.getSession({ headers: request.headers });
await auth.api.listSessions({ headers: request.headers });
await auth.api.revokeSession({
body: { token: "session_token_here" },
headers: request.headers,
});
// User Management
await auth.api.updateUser({
body: { name: "New Name", image: "https://..." },
headers: request.headers,
});
await auth.api.changeEmail({
body: { newEmail: "[email protected]" },
headers: request.headers,
});
await auth.api.deleteUser({
body: { password: "current_password" },
headers: request.headers,
});
// Account Linking
await auth.api.linkSocialAccount({
body: { provider: "google" },
headers: request.headers,
});
await auth.api.unlinkAccount({
body: { providerId: "google", accountId: "google_123" },
headers: request.headers,
});
插件 API 方法
2FA 插件:
// Enable 2FA
const { totpUri, backupCodes } = await auth.api.enableTwoFactor({
body: { issuer: "MyApp" },
headers: request.headers,
});
// Verify TOTP code
await auth.api.verifyTOTP({
body: { code: "123456", trustDevice: true },
headers: request.headers,
});
// Generate backup codes
const { backupCodes } = await auth.api.generateBackupCodes({
headers: request.headers,
});
Organization 插件:
// Create organization
const org = await auth.api.createOrganization({
body: { name: "Acme Corp", slug: "acme" },
headers: request.headers,
});
// Add member
await auth.api.addMember({
body: {
userId: "user_123",
role: "admin",
organizationId: org.id,
},
headers: request.headers,
});
// Check permissions
const hasPermission = await auth.api.hasPermission({
body: {
organizationId: org.id,
permission: "users:delete",
},
headers: request.headers,
});
Admin 插件:
// List users with pagination
const users = await auth.api.listUsers({
query: {
search: "john",
limit: 10,
offset: 0,
sortBy: "createdAt",
sortOrder: "desc",
},
headers: request.headers,
});
// Ban user
await auth.api.banUser({
body: {
userId: "user_123",
reason: "Violation of ToS",
expiresAt: new Date("2025-12-31"),
},
headers: request.headers,
});
// Impersonate user (for admin support)
const impersonationSession = await auth.api.impersonateUser({
body: {
userId: "user_123",
expiresIn: 3600, // 1 hour
},
headers: request.headers,
});
何时使用哪种方式
| 使用场景 | 使用 HTTP 端点 | 使用 auth.api.* 方法 |
|---|---|---|
| 客户端身份验证 | ✅ 是 | ❌ 否 |
| 服务端中间件 | ❌ 否 | ✅ 是 |
| 后台任务 | ❌ 否 | ✅ 是 |
| 管理员仪表板 | ✅ 是(来自客户端) | ✅ 是(来自服务端) |
| 自定义身份验证流程 | ❌ 否 | ✅ 是 |
| 移动应用 | ✅ 是 | ❌ 否 |
| API 路由 | ✅ 是(代理到处理程序) | ✅ 是(直接调用) |
示例:受保护路由中间件
import { Hono } from "hono";
import { createAuth } from "./auth";
import { createDatabase } from "./db";
const app = new Hono<{ Bindings: Env }>();
// Middleware using server-side API
app.use("/api/protected/*", async (c, next) => {
const db = createDatabase(c.env.DB);
const auth = createAuth(db, c.env);
// Use server-side method
const session = await auth.api.getSession({
headers: c.req.raw.headers,
});
if (!session) {
return c.json({ error: "Unauthorized" }, 401);
}
// Attach to context
c.set("user", session.user);
c.set("session", session.session);
await next();
});
// Protected route
app.get("/api/protected/profile", async (c) => {
const user = c.get("user");
return c.json({ user });
});
查找可用端点
使用 OpenAPI 插件查看配置中的所有端点:
import { betterAuth } from "better-auth";
import { openAPI } from "better-auth/plugins";
export const auth = betterAuth({
database: /* ... */,
plugins: [
openAPI(), // Adds /api/auth/reference endpoint
],
});
交互式文档:访问 http://localhost:8787/api/auth/reference
这里会显示 Scalar UI,其中包含:
- ✅ 按功能分组的所有可用端点
- ✅ 带类型的请求/响应架构
- ✅ 试用功能(在浏览器中测试端点)
- ✅ 身份验证要求
- ✅ 多种语言的代码示例
以编程方式访问:
const schema = await auth.api.generateOpenAPISchema();
console.log(JSON.stringify(schema, null, 2));
// Returns full OpenAPI 3.0 spec
量化节省的时间
从头开始构建(手动实现):
- 核心身份验证端点(注册、登录、OAuth、会话):40 小时
- 电子邮件验证和密码重置:10 小时
- 2FA 系统(TOTP、备用代码、电子邮件 OTP):20 小时
- 组织(团队、邀请、RBAC):60 小时
- 管理面板(用户管理、模拟用户):30 小时
- 测试和调试:50 小时
- 安全加固:20 小时
手动投入总计:约 220 小时(全职 5.5 周)
使用 better-auth:
- 初始设置:2-4 小时
- 自定义和样式调整:2-4 小时
使用 better-auth 所需总计:4-8 小时
节省:约 97% 的开发时间
关键要点
better-auth 提供 80 多个可用于生产环境的端点,涵盖:
- ✅ 核心身份验证(20 个端点)
- ✅ 双重身份验证与无密码登录(15 个端点)
- ✅ 组织与团队(35 个端点)
- ✅ 管理与用户管理(15 个端点)
- ✅ 社交 OAuth(自动配置回调)
- ✅ OpenAPI 文档(交互式界面)
你无需编写任何端点代码。 只需配置功能并调用 auth.handler()。
已知问题与解决方案
问题 1:"d1Adapter is not exported" 错误
问题:代码显示 import { d1Adapter } from 'better-auth/adapters/d1',但该导出不存在。
症状:出现 TypeScript 错误或有关缺少导出的运行时错误。
解决方案:改用 Drizzle 或 Kysely:
// ❌ WRONG - This doesn't exist
import { d1Adapter } from 'better-auth/adapters/d1'
database: d1Adapter(env.DB)
// ✅ CORRECT - Use Drizzle
import { drizzleAdapter } from 'better-auth/adapters/drizzle'
import { drizzle } from 'drizzle-orm/d1'
const db = drizzle(env.DB, { schema })
database: drizzleAdapter(db, { provider: "sqlite" })
// ✅ CORRECT - Use Kysely
import { Kysely } from 'kysely'
import { D1Dialect } from 'kysely-d1'
database: {
db: new Kysely({ dialect: new D1Dialect({ database: env.DB }) }),
type: "sqlite"
}
来源:已通过 4 个在生产环境中使用 better-auth + D1 的代码库验证
问题 2:架构生成失败
问题:npx better-auth migrate 未能创建兼容 D1 的架构。
症状:迁移 SQL 语法错误,或无法与 D1 配合使用。
解决方案:使用 Drizzle Kit 生成迁移:
# Generate migration from Drizzle schema
npx drizzle-kit generate
# Apply to D1
wrangler d1 migrations apply my-app-db --remote
原因:Drizzle Kit 会生成兼容 SQLite 的 SQL,可与 D1 配合使用。
问题 3:"CamelCase" 与 "snake_case" 列名不匹配
问题:数据库中有 email_verified,但 better-auth 预期的是 emailVerified。
症状:会话读取失败,用户数据缺少字段。
解决方案:在 Kysely 中使用 CamelCasePlugin,或正确配置 Drizzle:
使用 Kysely:
import { CamelCasePlugin } from "kysely";
new Kysely({
dialect: new D1Dialect({ database: env.DB }),
plugins: [new CamelCasePlugin()], // Converts between naming conventions
})
使用 Drizzle:从一开始就使用 camelCase 定义架构(如示例所示)。
问题 4:D1 最终一致性
问题:写入后立即读取会话时返回过时数据。
症状:用户登录后,下一次请求中的 getSession() 返回 null。
解决方案:使用 Cloudflare KV 存储会话(强一致性):
import { betterAuth } from "better-auth";
export function createAuth(db: Database, env: Env) {
return betterAuth({
database: drizzleAdapter(db, { provider: "sqlite" }),
session: {
storage: {
get: async (sessionId) => {
const session = await env.SESSIONS_KV.get(sessionId);
return session ? JSON.parse(session) : null;
},
set: async (sessionId, session, ttl) => {
await env.SESSIONS_KV.put(sessionId, JSON.stringify(session), {
expirationTtl: ttl,
});
},
delete: async (sessionId) => {
await env.SESSIONS_KV.delete(sessionId);
},
},
},
});
}
添加到 wrangler.toml:
[[kv_namespaces]]
binding = "SESSIONS_KV"
id = "your-kv-namespace-id"
问题 5:SPA 应用的 CORS 错误
问题:身份验证 API 与前端位于不同源时出现 CORS 错误。
症状:浏览器控制台中出现 Access-Control-Allow-Origin 错误。
解决方案:在 Worker 中配置 CORS 标头:
import { cors } from "hono/cors";
app.use(
"/api/auth/*",
cors({
origin: ["https://yourdomain.com", "http://localhost:3000"],
credentials: true, // Allow cookies
allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
})
);
问题 6:OAuth 重定向 URI 不匹配
问题:社交登录失败,并出现 "redirect_uri_mismatch" 错误。
症状:Google/GitHub OAuth 在用户授权后返回错误。
解决方案:确保 OAuth 提供商设置中的 URI 完全匹配:
Provider setting: https://yourdomain.com/api/auth/callback/google
better-auth URL: https://yourdomain.com/api/auth/callback/google
❌ Wrong: http vs https, trailing slash, subdomain mismatch
✅ Right: Exact character-for-character match
检查 better-auth 回调 URL:
// It's always: {baseURL}/api/auth/callback/{provider}
const callbackURL = `${env.BETTER_AUTH_URL}/api/auth/callback/google`;
console.log("Configure this URL in Google Console:", callbackURL);
问题 7:缺少依赖项
问题:出现有关缺少软件包的 TypeScript 错误或运行时错误。
症状:出现 Cannot find module 'drizzle-orm' 或类似错误。
解决方案:安装所有必需的软件包:
Drizzle 方案:
npm install better-auth drizzle-orm drizzle-kit @cloudflare/workers-types
Kysely 方案:
npm install better-auth kysely kysely-d1 @cloudflare/workers-types
问题 8:未发送电子邮件验证邮件
问题:始终收不到电子邮件验证链接。
症状:用户注册后没有收到电子邮件。
解决方案:实现 sendVerificationEmail 处理函数:
export const auth = betterAuth({
database: /* ... */,
emailAndPassword: {
enabled: true,
requireEmailVerification: true,
},
emailVerification: {
sendVerificationEmail: async ({ user, url }) => {
// Use your email service (SendGrid, Resend, etc.)
await sendEmail({
to: user.email,
subject: "Verify your email",
html: `
<p>Click the link below to verify your email:</p>
<a href="${url}">Verify Email</a>
`,
});
},
sendOnSignUp: true,
autoSignInAfterVerification: true,
expiresIn: 3600, // 1 hour
},
});
对于 Cloudflare:使用 Cloudflare Email Routing 或外部服务(Resend、SendGrid)。
问题 9:会话过期过快
问题:会话意外过期,或永不过期。
症状:用户意外退出登录,或退出登录后会话仍然存在。
解决方案:配置会话过期时间:
export const auth = betterAuth({
database: /* ... */,
session: {
expiresIn: 60 * 60 * 24 * 7, // 7 days (in seconds)
updateAge: 60 * 60 * 24, // Update session every 24 hours
},
});
问题 10:社交登录提供商未提供用户数据
问题:社交登录成功,但缺少用户数据(姓名、头像)。
症状:通过 Google/GitHub 登录后,session.user.name 为 null。
解决方案:请求更多权限范围:
socialProviders: {
google: {
clientId: env.GOOGLE_CLIENT_ID,
clientSecret: env.GOOGLE_CLIENT_SECRET,
scope: ["openid", "email", "profile"], // Include 'profile' for name/image
},
github: {
clientId: env.GITHUB_CLIENT_ID,
clientSecret: env.GITHUB_CLIENT_SECRET,
scope: ["user:email", "read:user"], // 'read:user' for full profile
},
}
问题 11:Drizzle 架构的 TypeScript 错误
问题:TypeScript 对架构类型报错。
症状:出现 Type 'DrizzleD1Database' is not assignable to...
解决方案:从数据库导出正确的类型:
// src/db/index.ts
import { drizzle, type DrizzleD1Database } from "drizzle-orm/d1";
import * as schema from "./schema";
export type Database = DrizzleD1Database<typeof schema>;
export function createDatabase(d1: D1Database): Database {
return drizzle(d1, { schema });
}
问题 12:Wrangler 开发模式无法使用
问题:wrangler dev 因数据库错误而失败。
症状:本地开发时出现“找不到数据库”或迁移错误。
解决方案:先在本地应用迁移:
# Apply migrations to local D1
wrangler d1 migrations apply my-app-db --local
# Then run dev server
wrangler dev
问题 13:用户数据更新未反映到 UI 中(使用 TanStack Query 时)
问题:更新用户数据(例如头像、姓名)后,即使调用了 queryClient.invalidateQueries(),useSession() 中的内容仍未更新。
症状:成功更新后,头像图片或用户资料数据仍显示旧内容。TanStack Query 缓存显示的是更新后的数据,但 better-auth 会话仍显示旧值。
根本原因:better-auth 使用 nanostores 管理会话状态,而非 TanStack Query。调用 queryClient.invalidateQueries() 只会使 React Query 缓存失效,不会影响 better-auth nanostore。
解决方案:更新用户数据后,手动通知 nanostore:
// Update user data
const { data, error } = await authClient.updateUser({
image: newAvatarUrl,
name: newName
})
if (!error) {
// Manually invalidate better-auth session state
authClient.$store.notify('$sessionSignal')
// Optional: Also invalidate React Query if using it for other data
queryClient.invalidateQueries({ queryKey: ['user-profile'] })
}
适用情况:
- 同时使用 better-auth 和 TanStack Query
- 更新用户资料字段(姓名、图片、电子邮件)
- 任何会在客户端修改会话用户数据的操作
替代方案:调用 useSession() 中的 refetch(),但 $store.notify() 更直接:
const { data: session, refetch } = authClient.useSession()
// After update
await refetch()
注意:$store 是未文档化的内部 API。此模式已在生产环境中验证,但未来的 better-auth 版本可能会有所更改。
来源:社区发现的模式,已验证用于生产环境
迁移指南
从 Clerk 迁移
主要区别:
- Clerk:第三方服务 → better-auth:可自托管
- Clerk:专有软件 → better-auth:开源
- Clerk:按月收费 → better-auth:免费
迁移步骤:
- 从 Clerk 导出用户数据(CSV 或 API)
- 导入 better-auth 数据库:
// migration script const clerkUsers = await fetchClerkUsers(); for (const clerkUser of clerkUsers) { await db.insert(user).values({ id: clerkUser.id, email: clerkUser.email, emailVerified: clerkUser.email_verified, name: clerkUser.first_name + " " + clerkUser.last_name, image: clerkUser.profile_image_url, }); } - 将 Clerk SDK 替换为 better-auth 客户端:
// Before (Clerk) import { useUser } from "@clerk/nextjs"; const { user } = useUser(); // After (better-auth) import { authClient } from "@/lib/auth-client"; const { data: session } = authClient.useSession(); const user = session?.user; - 更新中间件以验证会话
- 配置社交登录提供方(使用相同的 OAuth 应用,但配置不同)
从 Auth.js(NextAuth)迁移
主要区别:
- Auth.js:功能有限 → better-auth:功能全面(2FA、组织等)
- Auth.js:依赖大量回调 → better-auth:基于插件
- Auth.js:会话处理方式不一 → better-auth:一致
迁移步骤:
- 数据库架构:Auth.js 和 better-auth 使用相似的架构,但列名不同
- 替换配置:
// Before (Auth.js) import NextAuth from "next-auth"; import GoogleProvider from "next-auth/providers/google"; export default NextAuth({ providers: [GoogleProvider({ /* ... */ })], }); // After (better-auth) import { betterAuth } from "better-auth"; export const auth = betterAuth({ socialProviders: { google: { /* ... */ }, }, }); - 更新客户端钩子:
// Before import { useSession } from "next-auth/react"; // After import { authClient } from "@/lib/auth-client"; const { data: session } = authClient.useSession();
更多资源
官方文档
- 主页:https://better-auth.com
- 简介:https://www.better-auth.com/docs/introduction
- 安装:https://www.better-auth.com/docs/installation
- 基本用法:https://www.better-auth.com/docs/basic-usage
核心概念
- 会话管理:https://www.better-auth.com/docs/concepts/session-management
- 用户与账户:https://www.better-auth.com/docs/concepts/users-accounts
- 客户端 SDK:https://www.better-auth.com/docs/concepts/client
- 插件系统:https://www.better-auth.com/docs/concepts/plugins
身份验证方法
- 电子邮件和密码:https://www.better-auth.com/docs/authentication/email-password
- OAuth 提供方:https://www.better-auth.com/docs/concepts/oauth
插件文档
核心插件:
- 双重身份验证(2FA):https://www.better-auth.com/docs/plugins/2fa
- 组织:https://www.better-auth.com/docs/plugins/organization
- 管理员:https://www.better-auth.com/docs/plugins/admin
- 多会话:https://www.better-auth.com/docs/plugins/multi-session
- API 密钥:https://www.better-auth.com/docs/plugins/api-key
- 通用 OAuth:https://www.better-auth.com/docs/plugins/generic-oauth
无密码插件:
- Passkey:https://www.better-auth.com/docs/plugins/passkey
- 魔法链接:https://www.better-auth.com/docs/plugins/magic-link
- 电子邮件 OTP:https://www.better-auth.com/docs/plugins/email-otp
- 电话号码:https://www.better-auth.com/docs/plugins/phone-number
- 匿名:https://www.better-auth.com/docs/plugins/anonymous
高级插件:
- 用户名:https://www.better-auth.com/docs/plugins/username
- JWT:https://www.better-auth.com/docs/plugins/jwt
- OpenAPI:https://www.better-auth.com/docs/plugins/open-api
- OIDC 提供方:https://www.better-auth.com/docs/plugins/oidc-provider
- SSO:https://www.better-auth.com/docs/plugins/sso
- Stripe:https://www.better-auth.com/docs/plugins/stripe
- MCP:https://www.better-auth.com/docs/plugins/mcp
框架集成
- TanStack Start:https://www.better-auth.com/docs/integrations/tanstack
- Expo(React Native):https://www.better-auth.com/docs/integrations/expo
社区与支持
- GitHub:https://github.com/better-auth/better-auth(22.4k ⭐)
- 示例:https://github.com/better-auth/better-auth/tree/main/examples
- Discord:https://discord.gg/better-auth
- 更新日志:https://github.com/better-auth/better-auth/releases
相关文档
- Drizzle ORM:https://orm.drizzle.team/docs/get-started-sqlite
- Kysely:https://kysely.dev/
生产环境示例
已验证可运行的 D1 仓库(均使用 Drizzle 或 Kysely):
- zpg6/better-auth-cloudflare - Drizzle + D1(包含 CLI)
- zwily/example-react-router-cloudflare-d1-drizzle-better-auth - Drizzle + D1
- foxlau/react-router-v7-better-auth - Drizzle + D1
- matthewlynch/better-auth-react-router-cloudflare-d1 - Kysely + D1
没有任何项目使用直接的 d1Adapter——均需要 Drizzle/Kysely。
版本兼容性
测试版本:
[email protected][email protected][email protected][email protected][email protected]@cloudflare/workers-types@latest[email protected]- Node.js 18+、Bun 1.0+
破坏性变更:升级时请查看更新日志:https://github.com/better-auth/better-auth/releases
令牌效率:
- 不使用 skill:约 28,000 个令牌(D1 适配器错误、TanStack Start Cookie、nanostore 失效、OAuth 流程、API 发现)
- 使用 skill:约 5,600 个令牌(聚焦于错误、破坏性变更和 API 参考)
- 节省:约 80%(约 22,400 个令牌)
预防的错误:13 个有明确解决方案的已记录问题 核心价值:D1 适配器要求、v1.4.0/v1.3 破坏性变更、TanStack Start 修复、nanostore 模式、80 多个端点参考
上次验证时间:2025-11-22 | Skill 版本:3.0.0 | 变更:补充了 v1.4.0(仅 ESM、无状态会话、SCIM)和 v1.3(SSO/SAML、多团队)的知识缺口。删除了教程/设置内容(约 700 行)。聚焦于错误预防、破坏性变更和 API 参考。