关于 api-auth-better-auth-drizzle-hono
面向使用 Better Auth 的 TypeScript 开发者,提供认证配置、会话、插件和数据库迁移指南,涵盖邮箱密码、OAuth、双重验证及组织多租户。
主要功能
- 01服务端配置与数据库适配器
- 02类型安全的会话中间件
- 03邮箱与密码认证流程
- 04OAuth 与双重验证
- 05组织多租户
- 06数据库、Cookie 缓存与无状态会话
适用场景
- 01为 TypeScript 应用添加自托管认证
- 02使用类型安全会话保护路由
- 03配置 OAuth 和双重验证登录
- 04选择会话策略
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ agents-inc/ skills --skill api-auth-better-auth-drizzle-hono安装后在 Claude Code 中输入/api-auth-better-auth-drizzle-hono确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
metadata.yamlreference.mdexamples/core.mdoauth.mdorganizations.mdsessions.mdtwo-factor.md详细介绍
使用 Better Auth 进行身份验证
快速指南: 在 TypeScript 应用中使用 Better Auth(v1.5+)实现类型安全、可自托管的身份验证。它提供电子邮件/密码、OAuth、2FA、会话、无状态身份验证和组织多租户功能。插件架构支持渐进式扩展。请在依赖会话的中间件之前挂载身份验证处理程序;跨源部署时,请先配置 CORS;添加插件后,务必运行架构生成命令。
<critical_requirements>
关键:使用此技能前
(必须在任何依赖会话的其他中间件之前,将 Better Auth 处理程序挂载到身份验证路由上)
(客户端与服务端位于不同源时,必须在身份验证路由之前配置 CORS 中间件)
(所有密钥(clientId、clientSecret、BETTER_AUTH_SECRET)必须使用环境变量,绝不硬编码)
(添加插件后,必须先运行 npx auth@latest generate,再运行 ORM 迁移工具)
(必须使用 auth.$Infer.Session 类型,在中间件中以类型安全的方式访问会话)
</critical_requirements>
自动检测: Better Auth、betterAuth、createAuthClient、auth.handler、auth.api.getSession、socialProviders、twoFactor 插件、organization 插件、drizzleAdapter、会话管理、OAuth 提供方、无状态会话、cookieCache、genericOAuth、oAuthProvider、passkey、SCIM
适用场景:
- 构建可自托管的身份验证(避免被供应商锁定)
- 需要在一个解决方案中实现电子邮件/密码 + OAuth + 2FA
- 具有组织/团队管理功能的多租户 SaaS
- 类型安全的会话管理
- 需要将会话存储在数据库中或使用无状态会话的项目
不适用场景:
- 需要免维护的托管身份验证(可考虑托管身份验证解决方案)
- 没有用户账户的简单静态网站
- 无服务器冷启动至关重要的项目(不过无状态模式有所帮助)
涵盖的关键模式:
- 带插件的服务端配置(auth.ts)
- 会话中间件与类型安全的路由保护
- 电子邮件/密码身份验证流程
- OAuth 提供方(GitHub、Google、Generic OAuth)
- 双重身份验证(TOTP)
- 组织与多租户
- 会话策略:数据库、Cookie 缓存、无状态
- 数据库适配器集成
- 客户端 useSession 钩子
- 性能:实验性联接、Cookie 缓存、无状态会话
详细资源:
- examples/core.md - 注册、登录、客户端设置、数据库适配器
- examples/oauth.md - GitHub、Google、Generic OAuth 提供方
- examples/two-factor.md - TOTP 设置、启用、验证
- examples/organizations.md - 多租户、邀请
- examples/sessions.md - 会话配置、Cookie 缓存、无状态模式
- reference.md - 决策框架、反模式、版本说明
设计理念
Better Auth 采用以 TypeScript 为先、可自托管的身份验证方式。用户数据保留在你的数据库中,不会被供应商锁定。插件架构支持渐进式扩展——从简单配置开始,并根据需要添加功能。
核心原则:
- 全面保障类型安全 - 会话类型通过
auth.$Infer.Session从服务端传递到客户端 - 以数据库为事实来源 - 会话存储在你的数据库中(可选无状态模式)
- 基于插件的可扩展性 - 按需添加 2FA、组织、通行密钥、SCIM、OAuth 提供方
- 与框架无关 - 适用于任何 TypeScript Web 框架
- 注重性能 - 实验性联接(快 2-3 倍)、Cookie 缓存、无状态会话
核心模式
模式 1:服务配置(auth.ts)
创建带数据库适配器的 auth 实例。这是所有身份验证配置的唯一事实来源。
// lib/auth.ts
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "@/lib/db";
const SESSION_EXPIRES_IN_SECONDS = 60 * 60 * 24 * 7; // 7 days
const SESSION_UPDATE_AGE_SECONDS = 60 * 60 * 24; // Refresh daily
export const auth = betterAuth({
database: drizzleAdapter(db, { provider: "pg" }),
emailAndPassword: {
enabled: true,
minPasswordLength: 8,
maxPasswordLength: 128,
},
session: {
expiresIn: SESSION_EXPIRES_IN_SECONDS,
updateAge: SESSION_UPDATE_AGE_SECONDS,
},
trustedOrigins: [process.env.APP_URL || "http://localhost:3000"],
});
优点: 命名常量让会话策略易于审计,URL 使用环境变量,并且只导出一个实例
// BAD: Magic numbers, hardcoded secrets, default export
const auth = betterAuth({
database: { url: "postgres://user:pass@localhost/db" },
session: { expiresIn: 604800 },
});
export default auth;
缺点: 硬编码凭据会泄露到源代码管理中,魔法数字让策略难以理解,使用默认导出
完整设置(含电子邮件验证和 Drizzle 适配器配置)请参见 examples/core.md。
模式 2:具备类型安全的会话中间件
挂载 auth 处理程序,并创建用于在路由中访问会话的类型化中间件。
// CRITICAL: CORS must be configured BEFORE auth routes
app.use("/auth/*", cors({ origin: APP_URL, credentials: true }));
app.on(["POST", "GET"], "/auth/*", (c) => auth.handler(c.req.raw));
// middleware/auth-middleware.ts - Type-safe session access
type AuthVariables = {
user: typeof auth.$Infer.Session.user | null;
session: typeof auth.$Infer.Session.session | null;
};
export const authMiddleware = createMiddleware<{ Variables: AuthVariables }>(
async (c, next) => {
const session = await auth.api.getSession({ headers: c.req.raw.headers });
c.set("user", session?.user ?? null);
c.set("session", session?.session ?? null);
await next();
},
);
优点: auth.$Infer.Session 可确保 c.get("user") 的类型正确,先配置 CORS 再配置 auth 可避免预检请求失败,c.req.raw 提供 Better Auth 所需的 Web 标准 Request
// BAD: No type annotation - c.user is any, bypasses type system
app.use("*", async (c, next) => {
const session = await auth.api.getSession({ headers: c.req.raw.headers });
c.user = session?.user; // any - no autocomplete
await next();
});
缺点: 没有 AuthVariables 类型意味着任何访问都将失去类型检查,直接赋值属性会绕过类型化 Variables
受保护路由模式请参见 examples/core.md。
模式 3:插件添加后生成架构
每个插件都会添加数据库表。添加或修改插件后,请运行 CLI:
# Step 1: Generate Better Auth schema (outputs ORM-specific files)
npx auth@latest generate
# Step 2: Generate migration with your ORM tool
npx drizzle-kit generate
# Step 3: Apply migration
npx drizzle-kit migrate
务必运行全部 3 个步骤。Better Auth 的 migrate 命令仅适用于 Kysely 适配器;对于 Drizzle,请使用 generate + Drizzle Kit。
模式 4:电子邮件/密码与验证
配置带验证和密码重置回调的电子邮件/密码身份验证。
export const auth = betterAuth({
database: drizzleAdapter(db, { provider: "pg" }),
emailAndPassword: {
enabled: true,
minPasswordLength: 8,
maxPasswordLength: 128,
requireEmailVerification: true,
sendResetPassword: async ({ user, url }) => {
await sendEmail({
to: user.email,
subject: "Reset password",
html: `<a href="${url}">Reset</a>`,
});
},
},
emailVerification: {
sendVerificationEmail: async ({ user, url }) => {
await sendEmail({
to: user.email,
subject: "Verify email",
html: `<a href="${url}">Verify</a>`,
});
},
},
});
优点: 电子邮件验证可防止虚假注册,密码要求在服务器端强制执行
包含错误处理的客户端注册/登录钩子请参见 examples/core.md。
模式 5:会话策略
三种会话方案,各有不同的权衡:
| 策略 | 需要数据库 | 可撤销 | 适用场景 |
|---|---|---|---|
| 数据库(默认) | 是 | 是 | 大多数应用 |
| Cookie 缓存 + 数据库 | 是 | 是(延迟) | 减轻数据库负载 |
| 无状态 | 否 | 否(仅限版本) | 边缘/无服务器 |
// Cookie cache: reduces DB hits by caching session in signed cookie
session: {
cookieCache: { enabled: true, maxAge: CACHE_SECONDS, strategy: "compact" },
}
// Stateless: omit database option entirely
const auth = betterAuth({
// No database = fully stateless
session: { cookieCache: { enabled: true, strategy: "jwe" } },
});
Cookie 缓存策略:compact(最小,内部使用)、jwt(标准格式,可由第三方验证)、jwe(加密,隐藏数据)。
完整配置和撤销模式请参见 examples/sessions.md。
<red_flags>
高风险事项
- 硬编码密钥(源代码中的 clientId/clientSecret)——必须使用环境变量
- 在 auth 路由之后配置 CORS——预检请求会失败
- 缺少
BETTER_AUTH_SECRET环境变量——会话将无法工作 - 添加插件后未生成架构——运行时会出现数据库错误
- 会话中间件未指定类型——失去 TypeScript 类型安全,
c.user会变成any - 对 Drizzle 适配器使用
auth.migrate()——仅适用于 Kysely,请使用generate+ Drizzle Kit - 调用
auth.handler()时缺少c.req.raw——必须传入原始 Web 标准 Request
注意事项与边缘情况:
- Google 仅在首次授权时签发刷新令牌——请使用
accessType: "offline"和prompt: "consent" - GitHub OAuth 应用不会签发刷新令牌(访问令牌的有效期很长)
- 无状态会话无法单独撤销——递增
version可使所有会话失效 - 在其他设备上,Cookie 缓存撤销要等到
maxAge到期后才生效 - 跨域部署时,会话 Cookie 需要设置
SameSite=None+Secure authClient.forgotPassword在 v1.4 中更名为authClient.requestPasswordResetInferUser/InferSession在 v1.5 中移除——请使用better-auth中的泛型User和Session类型
反模式的代码示例、决策框架和版本说明请参见 reference.md。
</red_flags>
<critical_reminders>
重要提醒
(必须在任何依赖会话的其他中间件之前,将 Better Auth 处理程序挂载到身份验证路由上)
(当客户端和服务器位于不同源时,必须在身份验证路由之前配置 CORS 中间件)
(必须使用环境变量存储所有密钥(clientId、clientSecret、BETTER_AUTH_SECRET)——绝不硬编码)
(添加插件后,必须先运行 npx auth@latest generate,然后再运行 ORM 迁移工具)
(必须在中间件中使用 auth.$Infer.Session 类型,以类型安全的方式访问会话)
不遵守这些规则将导致身份验证失败、安全漏洞或运行时错误。
</critical_reminders>