Better Auth 源码阅读指南
项目概述
Better Auth 是一个 框架无关 (framework-agnostic) 的 TypeScript 认证/授权框架,支持 Node.js、Bun、Deno 和 Cloudflare Workers。
学习前先克隆项目:
- 本地路径:
external/better-auth
核心包结构
packages/
├── better-auth/ # 主库入口
├── core/ # 核心类型和共用工具
├── cli/ # CLI 工具
└── [adapter-*]/ # 数据库适配器 (drizzle, prisma, kysely, mongo, ...)
[plugin-*]/ # 插件 (passkey, oauth-provider, 2fa, ...)
核心入口路径
1. 库入口(了解整体结构)
external/better-auth/packages/better-auth/src/index.ts— 主导出external/better-auth/packages/better-auth/src/auth/full.ts—betterAuth()函数入口external/better-auth/packages/better-auth/src/auth/base.ts—createBetterAuth()核心逻辑
2. 请求处理流程
external/better-auth/packages/better-auth/src/api/index.ts— 路由注册 (getEndpoints,router)external/better-auth/packages/better-auth/src/api/routes/— 所有 endpoint handler(signInSocial, signOut, getSession 等)
3. Context 初始化
packages/better-auth/src/context/— 请求上下文解析
4. 核心类型定义
external/better-auth/packages/better-auth/src/types/— 主库类型external/better-auth/packages/core/src/types/— 核心共享类型(BetterAuthOptions 等)
推荐阅读顺序
第一步:理解核心抽象
1. better-auth/src/auth/full.ts
→ betterAuth() 入口函数
2. better-auth/src/auth/base.ts
→ createBetterAuth() 核心实现
→ 理解 auth context 初始化和请求处理流程
3. better-auth/src/api/index.ts (前 100 行)
→ getEndpoints() 和 router()
→ 了解有哪些 endpoints 注册
第二步:理解请求处理
1. better-auth/src/api/index.ts (273-402 行)
→ router() 函数
→ onRequest / onResponse 中间件流程
→ 错误处理
2. better-auth/src/api/middlewares/
→ originCheckMiddleware(CSRF 防护)
第三步:理解核心 Features
1. Session 管理
→ packages/better-auth/src/api/routes/getSession.ts
→ packages/better-auth/src/api/routes/listSessions.ts
→ packages/better-auth/src/api/routes/revokeSession.ts
2. Email 认证流程
→ packages/better-auth/src/api/routes/signUpEmail.ts
→ packages/better-auth/src/api/routes/signInEmail.ts
→ packages/better-auth/src/api/routes/verifyEmail.ts
3. OAuth / Social Login
→ packages/better-auth/src/api/routes/signInSocial.ts
→ packages/better-auth/src/api/routes/callbackOAuth.ts
4. Password 管理
→ packages/better-auth/src/api/routes/changePassword.ts
→ packages/better-auth/src/api/routes/setPassword.ts
→ packages/better-auth/src/api/routes/resetPassword.ts
第四步:理解 Plugin 机制
1. packages/core/src/plugins/
→ 理解 BetterAuthPlugin 接口定义
2. 查看已有插件实现
→ packages/passkey/
→ packages/oauth-provider/
关键文件速查
| 功能 | 文件 |
|---|---|
| 主入口 | better-auth/src/auth/full.ts |
| 请求路由 | better-auth/src/api/index.ts |
| Session 读取 | better-auth/src/api/routes/getSession.ts |
| 登录注册 | better-auth/src/api/routes/signUpEmail.ts |
| Social Login | better-auth/src/api/routes/signInSocial.ts |
| CSRF 防护 | better-auth/src/api/middlewares/ |
| 类型定义 | core/src/types/ |
开发测试命令
API Key 插件
包: packages/api-key/
功能概述
API Key 插件通过 Hook 拦截 + 伪造 Session 的方式,让 API Key 可以像普通 Session 一样参与权限控制。
工作流程
请求 (x-api-key: xxx)
↓
before hook 拦截 (matcher 检测 header)
↓
validateApiKey() 验证 key
↓
伪造 session → 注入 ctx.context.session
↓
后续 endpoint 正常执行 (sessionMiddleware 通过)
核心文件
| 文件 | 用途 |
|---|---|
src/index.ts | 插件主入口,定义 before hook |
src/schema.ts | 数据库模型定义 |
src/routes/verify-api-key.ts | validateApiKey() 验证逻辑 |
src/routes/create-api-key.ts | 创建 API Key endpoint |
src/routes/list-api-keys.ts | 列出 API Keys |
src/routes/delete-api-key.ts | 删除 API Key |
密钥存储模型
apikey: {
fields: {
key: { type: "string" }, // SHA-256 hash 存储
prefix: { type: "string" }, // 前缀 (如 "sk_live_")
start: { type: "string" }, // 显示前几位字符
referenceId: { type: "string" }, // 关联 userId/orgId
enabled: { type: "boolean" }, // 是否启用
expiresAt: { type: "date" }, // 过期时间
remaining: { type: "number" }, // 剩余请求次数
refillInterval: { type: "number" }, // 自动补充间隔
refillAmount: { type: "number" }, // 自动补充数量
rateLimitMax: { type: "number" }, // 速率限制
permissions: { type: "string" }, // JSON 权限配置
metadata: { type: "string" }, // 自定义元数据
}
}
metadata 用途
存储与 API Key 关联的任意自定义数据(需 enableMetadata: true 开启):
// 创建时附带 metadata
const { data: apiKey } = await client.apiKey.create({
name: "Production Key",
metadata: {
environment: "production",
team: "backend",
owner: "john@example.com",
}
});
// 验证时返回 metadata
const result = await auth.api.verifyApiKey({ key: "..." });
console.log(result.key.metadata);
// { environment: "production", team: "backend", ... }
典型用途:
- 环境标识 (
{ env: "production" }) - 负责人记录 (
{ owner: "john@company.com" }) - 成本中心 (
{ costCenter: "CC-1234" })
验证逻辑 (validateApiKey)
async function validateApiKey({ hashedKey, ... }) {
// 1. 数据库查找
const apiKey = await getApiKey(ctx, hashedKey, opts);
// 2. 启用状态检查
if (apiKey.enabled === false) throw APIError("UNAUTHORIZED", "KEY_DISABLED");
// 3. 过期时间检查 (自动删除过期 key)
if (apiKey.expiresAt && now > expiresAt) throw APIError("UNAUTHORIZED", "KEY_EXPIRED");
// 4. 剩余次数检查 (用完可自动删除)
if (apiKey.remaining === 0) throw APIError("TOO_MANY_REQUESTS", "USAGE_EXCEEDED");
// 5. 速率限制检查
if (isRateLimited(apiKey)) throw APIError("UNAUTHORIZED", "RATE_LIMITED");
// 6. 权限验证 (可选)
if (permissions) r.authorize(permissions);
// 7. 更新使用统计 (remaining--)
// 更新数据库...
}
配置选项
apiKey({
configurations: [{
apiKeyHeaders: "x-api-key", // 默认 header 名
defaultKeyLength: 64, // 密钥长度
enableMetadata: true, // 开启 metadata
disableKeyHashing: false, // 是否 hash 存储
rateLimit: {
enabled: true,
timeWindow: 1000 * 60 * 60 * 24, // 24小时窗口
maxRequests: 1000,
},
keyExpiration: {
defaultExpiresIn: 60 * 60 * 24 * 365, // 1年
},
enableSessionForAPIKeys: true, // 伪造 session
}]
})
Client 端使用
// 1. 安装插件
import { apiKey } from "@better-auth/api-key";
import { apiKeyClient } from "@better-auth/api-key/client";
// 2. 服务端配置
const auth = betterAuth({
plugins: [apiKey()]
});
// 3. 客户端配置
const authClient = createAuthClient({
plugins: [apiKeyClient()]
});
// 4. 创建 API Key
const { data: apiKey } = await authClient.apiKey.create({
name: "My Key",
expiresIn: 60 * 60 * 24 * 30, // 30 days
});
// 5. 使用 API Key 请求 (自动伪造 session)
const session = await auth.api.getSession({
headers: { "x-api-key": apiKey.key }
});
Endpoints
| Endpoint | Method | 用途 |
|---|---|---|
/api-key/create | POST | 创建 API Key |
/api-key/get | GET | 获取单个 Key |
/api-key/list | GET | 列出所有 Key |
/api-key/update | POST | 更新 Key |
/api-key/delete | POST | 删除 Key |
/api-key/verify | POST | 验证 Key |
开发约束(来自 CLAUDE.md)
- 禁止使用
any和class - 使用
Uint8Array而非Buffer - 使用
import type进行类型导入 - 使用
node:protocol 引入 Node.js 内置模块 - 必须为 bug fix 和新功能编写测试
Backlinks (1)
flowchart LR
n0["AI"]
n1["Database"]
n2["Dev Tools"]
n3["Emoji"]
n4["Frontend"]
n5["Game Dev"]
n6["Collection"]
n7["Languages"]
n8["Maps"]
n9["Media"]
n10["Monitor"]
n11["Plans"]
n12["对象存储基本用法(Bucket / Object / 常用操作)"]
n13["对象存储数据迁移(R2 → MinIO / 跨厂商搬迁)"]
n14["Object Storage"]
n15["挂载 Bucket 为本地文件系统(FUSE Mount)"]
n16["对象存储签名 URL(Signed URL)原理与实战"]
n17["对象存储供应商对比(S3 / R2 / OSS / Supabase / MinIO)"]
n18["Prototypes"]
n19["Research"]
n20["Better Auth 源码阅读指南"]
n21["DuckDB 环境与基本使用"]
n22["DuckDB 实战研究"]
n23["DuckDB 模拟数据"]
n24["PostgreSQL 数据用 DuckDB 加速查询"]
n25["HK 角色阅读"]
n26["HK 台词阅读"]
n27["Hollow Knight 英语主题"]
n28["HK 物品阅读"]
n29["HK 地点阅读"]
n30["HK 世界观 / Lore 阅读"]
n31["HK 英语学习素材清单"]
n32["英语学习 Dashboard"]
n33["English Scraps Archive"]
n34["English Scraps 使用指南"]
n35["Jellyfin 源码阅读指南"]
n36["Lux 资料整理"]
n37["Nest Commander 学习资料"]
n38["NestJS 源码阅读指南"]
n39["Protomaps 自建底图研究"]
n40["自制 PMTiles 地图(最简单例子)"]
n41["MapLibre 集成 Protomaps"]
n42["PMTiles 格式与工具链"]
n43["上海地区底图项目"]
n44["Redash 源码阅读指南"]
n45["Rust 学习计划"]
n46["shadcn/ui 源码阅读指南"]
n47["TRIP 项目核心原理与代码阅读指南"]
n1 --> n22
n6 --> n0
n6 --> n1
n6 --> n2
n6 --> n3
n6 --> n4
n6 --> n5
n6 --> n7
n6 --> n8
n6 --> n9
n6 --> n10
n6 --> n11
n6 --> n19
n12 --> n13
n12 --> n16
n12 --> n17
n12 --> n18
n13 --> n12
n13 --> n15
n13 --> n16
n13 --> n17
n14 --> n12
n14 --> n13
n14 --> n15
n14 --> n16
n14 --> n17
n15 --> n12
n15 --> n16
n15 --> n17
n16 --> n18
n17 --> n12
n17 --> n13
n17 --> n16
n17 --> n18
n18 --> n12
n18 --> n15
n18 --> n16
n18 --> n17
n18 --> n39
n19 --> n20
n19 --> n22
n19 --> n32
n19 --> n35
n19 --> n36
n19 --> n37
n19 --> n38
n19 --> n39
n19 --> n44
n19 --> n45
n19 --> n46
n19 --> n47
n21 --> n23
n22 --> n1
n22 --> n19
n22 --> n21
n22 --> n23
n22 --> n24
n23 --> n21
n23 --> n24
n24 --> n22
n24 --> n23
n27 --> n25
n27 --> n26
n27 --> n28
n27 --> n29
n27 --> n30
n27 --> n31
n27 --> n34
n31 --> n26
n32 --> n27
n32 --> n33
n32 --> n34
n34 --> n32
n34 --> n33
n39 --> n8
n39 --> n40
n39 --> n41
n39 --> n42
n39 --> n43
n40 --> n42
n41 --> n18
n41 --> n43
n42 --> n40
n42 --> n43
n43 --> n41
n43 --> n42
click n0 "../../../collection/ai/" "AI"
click n1 "../../../collection/database/" "Database"
click n2 "../../../collection/dev-tools/" "Dev Tools"
click n3 "../../../collection/emoji/" "Emoji"
click n4 "../../../collection/frontend/" "Frontend"
click n5 "../../../collection/game-dev/" "Game Dev"
click n6 "../../../collection/" "Collection"
click n7 "../../../collection/languages/" "Languages"
click n8 "../../../collection/maps/" "Maps"
click n9 "../../../collection/media/" "Media"
click n10 "../../../collection/monitor/" "Monitor"
click n11 "../../../collection/scraps/plans/" "Plans"
click n12 "../../../knowledge/infrastructure/cloud/object-storage/basic-usage/" "对象存储基本用法(Bucket / Object / 常用操作)"
click n13 "../../../knowledge/infrastructure/cloud/object-storage/data-migration/" "对象存储数据迁移(R2 → MinIO / 跨厂商搬迁)"
click n14 "../../../knowledge/infrastructure/cloud/object-storage/" "Object Storage"
click n15 "../../../knowledge/infrastructure/cloud/object-storage/mount-bucket/" "挂载 Bucket 为本地文件系统(FUSE Mount)"
click n16 "../../../knowledge/infrastructure/cloud/object-storage/signed-url/" "对象存储签名 URL(Signed URL)原理与实战"
click n17 "../../../knowledge/infrastructure/cloud/object-storage/vendors-comparison/" "对象存储供应商对比(S3 / R2 / OSS / Supabase / MinIO)"
click n18 "../../../prototypes/" "Prototypes"
click n19 "../../" "Research"
click n20 "./" "Better Auth 源码阅读指南"
click n21 "../duckdb/basic-usage/" "DuckDB 环境与基本使用"
click n22 "../duckdb/" "DuckDB 实战研究"
click n23 "../duckdb/mock-data/" "DuckDB 模拟数据"
click n24 "../duckdb/postgresql-acceleration/" "PostgreSQL 数据用 DuckDB 加速查询"
click n25 "../english/hollow-knight/characters/" "HK 角色阅读"
click n26 "../english/hollow-knight/dialogues/" "HK 台词阅读"
click n27 "../english/hollow-knight/" "Hollow Knight 英语主题"
click n28 "../english/hollow-knight/items/" "HK 物品阅读"
click n29 "../english/hollow-knight/locations/" "HK 地点阅读"
click n30 "../english/hollow-knight/lore/" "HK 世界观 / Lore 阅读"
click n31 "../english/hollow-knight/resources/" "HK 英语学习素材清单"
click n32 "../english/" "英语学习 Dashboard"
click n33 "../english/scraps/archive/" "English Scraps Archive"
click n34 "../english/scraps/" "English Scraps 使用指南"
click n35 "../jellyfin/" "Jellyfin 源码阅读指南"
click n36 "../lux/" "Lux 资料整理"
click n37 "../nest-commander/" "Nest Commander 学习资料"
click n38 "../nestjs/" "NestJS 源码阅读指南"
click n39 "../protomaps/" "Protomaps 自建底图研究"
click n40 "../protomaps/make-own-map/" "自制 PMTiles 地图(最简单例子)"
click n41 "../protomaps/maplibre/" "MapLibre 集成 Protomaps"
click n42 "../protomaps/pmtiles/" "PMTiles 格式与工具链"
click n43 "../protomaps/shanghai-map/" "上海地区底图项目"
click n44 "../redash/" "Redash 源码阅读指南"
click n45 "../rust/" "Rust 学习计划"
click n46 "../shadcn-ui/" "shadcn/ui 源码阅读指南"
click n47 "../trip/" "TRIP 项目核心原理与代码阅读指南"