Skip to content

Better Auth 源码阅读指南

项目概述

Better Auth 是一个 框架无关 (framework-agnostic) 的 TypeScript 认证/授权框架,支持 Node.js、Bun、Deno 和 Cloudflare Workers。

学习前先克隆项目:

cd external
git clone --depth 1 https://github.com/better-auth/better-auth.git
  • 本地路径: 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.tsbetterAuth() 函数入口
  • external/better-auth/packages/better-auth/src/auth/base.tscreateBetterAuth() 核心逻辑

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/

开发测试命令

# 单个测试文件
pnpm vitest packages/better-auth/src/auth/full.test.ts -t "pattern"

# 类型检查
pnpm typecheck

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)

  • 禁止使用 anyclass
  • 使用 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 项目核心原理与代码阅读指南"