All posts

Better Auth 1.5

Auth CLI、MCP Auth、OAuth 2.1 Provider、Electron 集成、多语言支持、适配器拆分、动态基础 URL、Cloudflare D1 支持、CLI 初始化向导、基于席位计费、SAML 单点注销、测试工具、密钥轮换等等!

Alex Yang·@himseIf_65·Feb 28, 2026

Better Auth 1.5 版本发布

我们很高兴地宣布发布 Better Auth 1.5!🎉

这是迄今为止最大的一次发布,拥有超过 600 次提交、70 个新功能、200 多个错误修复,以及 7 个全新包。从 MCP 认证到 Electron 桌面支持,此版本将 Better Auth 拓展到更多平台和使用场景。

我们还推出了全新的 Infrastructure 产品。它让你可以使用完整的用户管理和分析仪表盘、安全防护工具、审计日志、自助式 SSO 界面等等,且都运行在你自己的 Better Auth 实例上。

从本次发布开始,自助式 SSO 仪表盘 —— 允许企业客户自主接入自己的 SAML 身份提供者而无需支持工单 —— 将由 Better Auth Infrastructure 支持。如果你在生产环境使用 SSO 插件,建议升级至 Pro 或 Business 版本,以获取仪表盘访问权限并简化企业客户入驻流程。

不久之后,你还可以将你的 Better Auth 实例托管到我们的基础设施上,按需拥有大规模的认证能力,而无需担心基础设施需求。

立即注册:https://dash.better-auth.com/sign-in 🚀

升级命令如下:

npx auth upgrade

🚀 亮点功能

全新 Better Auth CLI

我们推出了全新的独立 CLI:npx auth。它替代了之前的 @better-auth/cli 包,后者将在未来版本中弃用。

npx auth init

通过一个交互式命令,npx auth init 可以快速生成完整的 Better Auth 配置 —— 包括配置文件、数据库适配器、和框架集成。

现有的所有命令如 migrategenerate 也都通过新 CLI 提供:

npx auth migrate   # 运行数据库迁移
npx auth generate  # 生成认证 Schema
npx auth upgrade   # 升级 Better Auth 到最新版本

generate 命令现在支持 --adapter 标志,可以针对特定数据库适配器生成对应的 Schema 输出,无需完整 Better Auth 配置文件:

npx auth generate --adapter prisma
npx auth generate --adapter drizzle

远程 MCP Auth 客户端

MCP 插件现提供一个与框架无关的远程认证客户端。如果你的 MCP 服务器与 Better Auth 实例分离,可以用它验证令牌和保护资源,而不必重复认证逻辑。

👉 了解更多 MCP 认证

import { createMcpAuthClient } from "better-auth/plugins/mcp/client";

const mcpAuth = createMcpAuthClient({
    authURL: "<https://my-app.com/api/auth>",
});

// 作为请求处理器包装器使用
const handler = mcpAuth.handler(async (req, session) => {
    // session 包含 userId、scopes、accessToken、clientId 等信息
    return new Response("OK");
});

// 或直接验证令牌
const session = await mcpAuth.verifyToken(token);

它还内置了适用于 Hono 和类 Express 服务器的适配器:

import { mcpAuthHono } from "better-auth/plugins/mcp/client/adapters";

const middleware = mcpAuthHono(mcpAuth);

OAuth 2.1 提供者

新的 @better-auth/oauth-provider 插件可以将你的 Better Auth 实例变成完全兼容 OIDC 的 OAuth 2.1 授权服务器。它支持发放访问令牌、客户端注册及第三方应用认证,包括 MCP 代理。

👉 了解更多 OAuth Provider

import { betterAuth } from "better-auth";
import { jwt } from "better-auth/plugins";
import { oauthProvider } from "@better-auth/oauth-provider";

export const auth = betterAuth({
    plugins: [
        jwt(),
        oauthProvider({
            loginPage: "/sign-in",
            consentPage: "/consent",
        }),
    ],
});

主要功能:

  • OAuth 2.1 with OIDC: 支持 authorization_coderefresh_tokenclient_credentials 授权,并支持 openid 范围。
  • MCP-ready: 可直接作为 MCP 工具和代理的授权服务器使用。
  • Dynamic Client Registration: 允许客户端动态注册,支持公共和机密客户端。
  • JWT & JWKS verification: 将访问令牌以 JWT 形式签名,并通过 /jwks 端点远程验证。
  • Consent & authorization flows: 内置授权、账户选择和登录后重定向页面。
  • Token introspection & revocation: 符合 RFC 7662 和 RFC 7009 标准的端点。
  • Per-endpoint rate limiting: 可为每个 OAuth 端点配置速率限制。

OAuth 2.1 Provider 取代了之前的 OIDC Provider 插件,该插件将在未来版本中弃用。MCP 插件也将过渡到使用 OAuth 2.1 Provider 作为其基础。有关从 OIDC Provider 插件升级的迁移指南,请参见 migration guide


Electron 集成

为 Electron 应用提供完整的桌面认证支持。插件支持完整的 OAuth 流程 —— 启动系统浏览器,通过自定义协议交换授权码,并安全管理 Cookie。

👉 了解更多 Electron 集成

import { betterAuth } from "better-auth";
import { electron } from "@better-auth/electron";

export const auth = betterAuth({
    plugins: [electron()],
});
import { createAuthClient } from "better-auth/client";
import { electronClient } from "@better-auth/electron/client";

const client = createAuthClient({
    plugins: [
        electronClient({
            protocol: "com.example.myapp",
        }),
    ],
});

// 打开系统浏览器,处理回调,返回会话
await client.requestAuth();

国际化(i18n)

新的 i18n 插件支持类型安全的错误消息翻译,自动从请求头、Cookie 或 Session 中检测语言环境。

👉 了解更多 i18n

import { betterAuth } from "better-auth";
import { i18n } from "@better-auth/i18n";

export const auth = betterAuth({
    plugins: [
        i18n({
            defaultLocale: "en",
            detection: ["header", "cookie"],
            translations: {
                en: { USER_NOT_FOUND: "User not found" },
                fr: { USER_NOT_FOUND: "Utilisateur non trouvé" },
                es: { USER_NOT_FOUND: "Usuario no encontrado" },
            },
        }),
    ],
});

错误代码完全类型化 —— 你的 IDE 会自动补全所有已注册插件支持的错误码。


类型化错误码

每个错误响应现在均包含机器可读的 code 字段。所有官方插件都使用 defineErrorCodes 定义类型化错误码,APIError 类原生支持这些错误码。

import { defineErrorCodes } from "@better-auth/core";

export const MY_ERROR_CODES = defineErrorCodes({
    USER_NOT_FOUND: "User not found",
    INVALID_TOKEN: "The provided token is invalid",
});

// 路由处理器中使用:
throw APIError.from("BAD_REQUEST", MY_ERROR_CODES.USER_NOT_FOUND);

错误响应示例:

{
    "code": "USER_NOT_FOUND",
    "message": "User not found"
}

这是 i18n 插件的基础 —— 每个错误码在编译时可发现,因此翻译字典可以进行类型检查。


SSO —— 生产就绪

SSO 插件经过大量完善,具备生产环境所需的安全和合规性,迭代超过 23 次提交。

自助式 SSO 仪表盘

作为新 Infrastructure 产品的一部分,SSO 插件配备了面向企业客户自助接入的仪表盘。组织管理员能够生成一个可分享的链接,引导企业客户配置自己的 SAML 身份提供者,省去了反复的支持工单。

仪表盘地址为:

https://dash.better-auth.com/[project]/organization/[orgId]/enterprise

通过该地址,你可生成入驻链接、监控 SSO 连接状态、管理组织的身份提供者配置。

SAML 单点注销(SLO)

全面支持 SP 发起和 IdP 发起的 SAML 单点注销:

import { betterAuth } from "better-auth";
import { sso } from "@better-auth/sso";

export const auth = betterAuth({
    plugins: [
        sso({
            saml: {
                enableSingleLogout: true, 
                wantLogoutRequestSigned: true,
                wantLogoutResponseSigned: true,
            },
        }),
    ],
});

其他 SSO 改进

  • Signed SAML AuthnRequests: 可配置签名和摘要算法。
  • Multi-domain providers: 将 SSO 提供者绑定到多个域。
  • InResponseTo validation: 防止 SAML 断言重放攻击。
  • Algorithm restrictions: 阻止已弃用的签名/摘要算法。
  • Clock skew tolerance: 可配置对 SAML 时间戳校验的容忍度。
  • OIDC ID token aud 声明验证: 在 OpenID Connect 流程中验证受众。
  • Provider CRUD endpoints: 通过 API 列出、获取、更新和删除 SSO 提供者。
  • Shared OIDC redirect URI: 所有 OIDC 提供者共用一个重定向 URI。

API 密钥插件

API 密钥插件经历重大改进。

插件被拆分成独立包,安装方式为:

npm install @better-auth/api-key

请更新你的引入语句:

auth.ts
- import { apiKey } from "better-auth/plugins";
+ import { apiKey } from "@better-auth/api-key";
auth-client.ts
- import { apiKeyClient } from "better-auth/client/plugins";
+ import { apiKeyClient } from "@better-auth/api-key/client";

组织拥有的 API 密钥

期待已久的组织拥有 API 密钥支持现已加入! 你现在可以创建归属于组织而非个人用户的 API 密钥。

import { apiKey } from "@better-auth/api-key";

export const auth = betterAuth({
    plugins: [apiKey({ references: "organization" })],
});

创建组织拥有的 API 密钥示例:

import { auth } from "@/lib/auth";

const apiKey = await auth.api.createApiKey({
    body: { organizationId: "org_123" },
});

多配置支持的 API 密钥

你可以在应用内支持多种 API 密钥使用场景!

export const auth = betterAuth({
    plugins: [
        apiKey([
            {
                configId: "user-keys",
                prefix: "usr_"
            },
            {
                configId: "org-keys",
                prefix: "org_",
                references: "organization"
            }
        ])
    ]
});

创建指定配置的 API 密钥时,调用:

const key = auth.api.createApiKey({
    body: {
        configId: "user-keys",
        //...
    }
});

统一的 Before & After 钩子

插件钩子和全局钩子的中间件现在共享相同的 AuthMiddleware 类型,实现整个认证流程中钩子系统的一致性和组合性。

import { betterAuth } from "better-auth";
import { createAuthMiddleware } from "better-auth/api";

export const auth = betterAuth({
    hooks: {
        before: createAuthMiddleware(async (ctx) => {
            // 在每个端点前执行
            console.log("请求路径:", ctx.path);
        }),
        after: createAuthMiddleware(async (ctx) => {
            // 在每个端点后执行,访问响应内容
            console.log("响应内容:", ctx.context.returned);
        }),
    },
});

插件支持使用相同类型的中间件,并结合匹配器实现定向拦截:

hooks: {
    before: [{
        matcher: (ctx) => ctx.path === "/sign-in/email",
        handler: createAuthMiddleware(async (ctx) => { /* ... */ }),
    }],
},

动态基础 URL

Better Auth 现可从传入请求动态解析基础 URL,让它无缝适配 Vercel 预览部署、多域名配置以及反向代理。

👉 Read more about dynamic base URL

import { betterAuth } from "better-auth";

export const auth = betterAuth({
    baseURL: {
        allowedHosts: [
            "myapp.com",
            "*.vercel.app",       // 任意 Vercel 预览域
            "preview-*.myapp.com", // 模式匹配
        ],
        fallback: "<https://myapp.com>",
        protocol: "auto",
    },
});

次级存储的验证存储

验证令牌现在可以存储在次级存储中(例如 Redis),替代或补充数据库存储。识别符可进行哈希以增强安全性。

import { betterAuth } from "better-auth";

export const auth = betterAuth({
    secondaryStorage: {
        // ...你的 Redis 配置
    },
    verification: {
        storeIdentifier: "hashed",     // 哈希验证标识符
        storeInDatabase: false,        // 仅使用次级存储
    },
});

也支持为不同标识符配置不同策略:

verification: {
    storeIdentifier: {
        default: "plain",
        overrides: {
            "email-verification": "hashed",
            "password-reset": "hashed",
        },
    },
},

限流器改进

限流器现在区分请求与响应阶段处理,强化默认配置,支持 IPv6。

  • Separate request and response phases: 被拒绝的请求不再计入限流。
  • Hardened default rules: 登录/注册在 10 秒内限制为 3 次;密码重置/OTP 在 60 秒内限制为 3 次。
  • IPv6 subnet support: 按 IPv6 前缀限流,并可配置子网大小。
  • Plugin-level rate limit rules: 插件可以定义自己的限流规则。
  • Expired entry cleanup: 为内存存储后端提供自动清理。
import { betterAuth } from "better-auth";

export const auth = betterAuth({
    advanced: {
        ipAddress: {
            ipv6Subnet: 64, // 按 /64 子网限流
        },
    },
});

非破坏性的密钥轮换

Better Auth 现支持在不使现有会话、令牌或加密数据失效的情况下,轮换 BETTER_AUTH_SECRET。无论是计划轮换还是应急响应,都可添加新密钥同时保留旧密钥解密能力。

import { betterAuth } from "better-auth";

export const auth = betterAuth({
    secrets: [
        { version: 2, value: "new-secret-key-at-least-32-chars" },   // 当前(数组第一项为活动密钥)
        { version: 1, value: "old-secret-key-still-used-to-decrypt" }, // 旧密钥
    ],
});

或通过环境变量配置:

BETTER_AUTH_SECRETS="2:new-secret-key,1:old-secret-key"

新数据总是采用最新密钥加密(数组首项),解密时自动尝试所有密钥。实现无中断的密钥平滑切换。


基于席位的计费(Stripe)

Stripe 插件新增组织席位计费支持。成员变更会自动同步席位数至 Stripe。

import { betterAuth } from "better-auth";
import { stripe } from "@better-auth/stripe";
import { organization } from "better-auth/plugins";

export const auth = betterAuth({
    plugins: [
        organization(),
        stripe({
            stripeClient,
            stripeWebhookSecret: "whsec_...",
            subscription: {
                enabled: true,
                plans: [
                    {
                        name: "team",
                        priceId: "price_base_monthly",
                        seatPriceId: "price_per_seat", 
                    },
                ],
            },
            organization: { enabled: true }, 
        }),
    ],
});

插件还支持基于用量的计费(lineItems)、订阅排程(scheduleAtPeriodEnd)及计费周期跟踪。


测试工具插件

全新 testUtils 插件提供工厂函数、数据库助手及认证工具,支持集成测试和端到端测试。

👉 了解测试工具

import { betterAuth } from "better-auth";
import { testUtils } from "better-auth/plugins";

export const testAuth = betterAuth({
    plugins: [testUtils({ captureOTP: true })],
});

建议仅在测试用的认证实例中添加 testUtils,例如 auth.test.ts。它不会暴露公开路由,但会在 ctx.test 上添加特权级辅助函数,并且条件化的插件数组可能会削弱类型推断。

const ctx = await testAuth.$context;
const test = ctx.test;

// 创建并保存测试用户
const user = test.createUser({ email: "test@example.com" });
const savedUser = await test.saveUser(user);

// 登录并获取认证请求头
const { headers, session, token } = await test.login({ userId: user.id });

// 捕获一次性密码用于验证测试
const otp = test.getOTP("test@example.com");

更新会话接口

新增 /update-session 端点,可动态更新自定义会话字段,无需重新认证。

// 客户端调用
await authClient.updateSession({
    theme: "dark",
    language: "en",
});

适合需要动态修改会话附加字段的场景。


适配器拆分

数据库适配器已拆分成独立包。这是一项重大的架构调整,减少了主包体积并支持适配器独立版本管理。

PackageDescription
@better-auth/drizzle-adapterDrizzle ORM adapter
@better-auth/prisma-adapterPrisma adapter
@better-auth/kysely-adapterKysely adapter
@better-auth/mongo-adapterMongoDB adapter
@better-auth/memory-adapterIn-memory adapter

主包 better-auth 仍会重新导出所有适配器,现有导入无需修改。但你可选择只安装所需适配器,以减小打包体积:

import { drizzleAdapter } from "@better-auth/drizzle-adapter";
import { betterAuth } from "better-auth/minimal";

export const auth = betterAuth({
    database: drizzleAdapter(db, { provider: "pg" }),
});

Cloudflare D1 支持

Better Auth 现原生支持 Cloudflare D1 作为首选数据库方案。直接传入 D1 绑定,无需自定义适配器配置。

import { betterAuth } from "better-auth";

export default {
    async fetch(request, env) {
        const auth = betterAuth({
            database: env.DB, // D1 绑定,自动检测
        });
        return auth.handler(request);
    },
} satisfies ExportedHandler<{ DB: D1Database }>;

内置 D1 方言支持通过 D1 原生接口执行查询、批量操作和模式推断。由于 D1 不支持交互式事务,Better Auth 使用 batch() API 实现原子操作。


✨ 更多新功能

认证与会话

  • verifyPassword API: 新增服务器端端点,用于验证当前用户的密码。
  • setShouldSkipSessionRefresh: 以编程方式跳过特定请求的会话刷新。
  • deferSessionRefresh: 支持只读副本数据库设置。
  • 可等待的社会化提供者配置: 提供者配置现在可以是异步的。
  • 注册时限制枚举: 当需要电子邮件验证时,注册不会泄露现有账户。
  • customSyntheticUser 选项: 在受枚举保护的响应中支持插件字段 (#8097)。
  • 邮箱登录/注册的表单数据支持: 除了 JSON 主体外。
  • VERCEL_URLNEXTAUTH_URL 自动检测基础 URL: 当未配置明确的 baseURL 时,客户端现在会回退到 VERCEL_URLNEXTAUTH_URL 环境变量,使在 Vercel 上的服务器端渲染开箱即用。

OAuth 与提供者

  • Railway OAuth 提供者: 新的社会化提供者。
  • 可信提供者回调: 动态可信提供者解析。
  • 不区分大小写的电子邮件匹配: 用于社会化账户关联。
  • 不带 PKCE 的遗留 OAuth 客户端: 向后兼容性支持。

Stripe 插件

  • seatPriceIdlineItems 支持灵活的订阅结账,兼容按席位和基于使用量的计费等现代定价模型。
  • scheduleAtPeriodEnd: 将计划变更延迟到计费周期结束。
  • 订阅计划跟踪: 监控即将发生的订阅变更。
  • 组织客户支持: 将组织作为 Stripe 客户。
  • 灵活的取消和终止: 对订阅生命周期有更多控制。

SCIM

  • SCIM 所有权模型: 将 SCIM 提供者连接与用户关联。
  • SCIM 连接管理: 列出、获取和删除 SCIM 提供者连接。
  • Microsoft Entra ID 兼容性: 对 Entra 配置提供完整支持。

OAuth Provider 插件

  • 重定向 URI 的 HTTPS 强制: 仅允许 localhost 使用 HTTP。
  • RFC 9207 iss 参数: 授权响应发行者标识符。
  • 每个客户端的 PKCE 配置: 可选择不为管理员创建的客户端启用 PKCE。
  • 同意时的范围缩小: 用户可以减少请求的范围。
  • prompt=none 支持: 用于 OIDC 的静默认证。
  • 可配置的速率限制: 每个端点的速率限制配置。

插件改进

  • magic-link: allowedAttempts 选项: 限制验证尝试次数。
  • email-otp: 带有 OTP 的更改邮箱流程: 用户可以通过 OTP 验证更改邮箱地址,并可选择使用当前邮箱确认以增强安全性。
  • email-otp: 登录时的名称、图片及其他字段: 更丰富的 OTP 登录体验。
  • phone-number: signUpOnVerification 中的其他字段: 传递额外数据。
  • two-factor: twoFactorCookieMaxAge 和服务器端信任设备过期.
  • one-tap: Google 登录的按钮模式.
  • anonymous: 删除匿名用户端点.
  • admin: 创建用户时可选密码.
  • api-keys: 列表端点的分页支持,通过元数据引用组织.
  • organization: 对 membershipLimit 的函数支持,拒绝过期的邀请。

核心与基础设施

  • BetterAuthPluginRegistry 类型系统: 通过 getPlugin()hasPlugin() 进行类型化的插件发现。
  • AuthContext 中的版本: 在运行时访问 Better Auth 版本。
  • Redis 次级存储: 提取到 @better-auth/redis-storage
  • 次级存储的会话 ID 处理: 当不使用数据库时,生成适当的 ID。

🔒 安全改进

  • 防止通过竞态条件重用 OTP: 在 OTP 使用时原子化失效。
  • 防止用户枚举: 在邮箱 OTP 且注册被禁用时,以及注册时需要邮箱验证时。
  • 防止在 /change-email 上的邮箱枚举: 始终返回 { status: true } 并模拟令牌生成以确保时序安全 (#8097)。
  • 更严格的默认速率限制: 针对密码重置和电话号码验证端点。
  • 分离 CSRF 和来源检查: 更细粒度的请求验证。
  • 防止试用滥用: 在授予免费试用前检查用户的所有订阅。
  • SAML ACS 错误重定向加固: 防止错误流程中的开放重定向。
  • IPv6 地址规范化与子网支持: 用于速率限制和基于 IP 的规则。
  • XML 解析器加固: 为 SAML 响应和元数据配置大小限制。

⚠️ 破坏性变更

建议逐条查看,确保顺利升级。

弃用接口移除

/forget-password/email-otp 端点已移除,请改用标准密码重置流程。

适配器导入调整

better-auth/adapters/test 导出已移除。请使用 @better-auth/test-utils/adapter 中的 testAdaptercreateTestSuite。详情见创建数据库适配器指南

API Key 插件迁移到 @better-auth/api-key

API Key 插件已拆分为独立包,需单独安装:

npm install @better-auth/api-key
- import { apiKey } from "better-auth/plugins";
+ import { apiKey } from "@better-auth/api-key";

Schema 变更:

  • ApiKey 表的 userId 字段已重命名为 referenceId
  • 新增 configId 字段(默认为 "default")。

插件选项变更:

permissions.defaultPermissions 回调的第一个参数由 userId 改为 referenceId

export const auth = betterAuth({
    plugins: [
        apiKey({
            permissions: {
-               defaultPermissions: async (userId, ctx) => {
+               defaultPermissions: async (referenceId, ctx) => {
                    return {
                        files: ["read"],
                        users: ["read"],
                    };
                },
            }
        })
    ]
})

客户端 SDK 变更:

- const ownerId = apiKey.userId;
+ const ownerId = apiKey.referenceId;
+ const ownerType = apiKey.references; // "user" 或 "organization"
+ const configId = apiKey.configId;

权限变更:

updateApiKey 接口服务器端现在至少需要传入 userId 参数或等效请求头。之前版本若未传入,则需变更调用逻辑。


🛠 开发者变更

如果你在基于 Better Auth 构建插件,请注意以下内容。

弃用 API 全部移除

所有之前标为弃用的 API 均被移除,包括弃用的适配器类型、客户端类型、辅助类型和插件选项。请将相关代码迁移至替代方案:

RemovedReplacement
AdapterDBAdapter
TransactionAdapterDBTransactionAdapter
Store (client)ClientStore
AtomListener (client)ClientAtomListener
ClientOptionsBetterAuthClientOptions
LiteralUnion, DeepPartial (from better-auth/types/helper)@better-auth/core 导入
onEmailVerificationafterEmailVerification
sendChangeEmailVerificationsendChangeEmailConfirmation
advanced.database.useNumberIdadvanced.database.generateId: "serial"
Organization permission fieldpermissions (plural)

@better-auth/core/utils 桶式导出移除

@better-auth/core/utils 桶式导出已拆分为单独子路径,以提升摇树优化效果:

- import { generateId, safeJSONParse, defineErrorCodes } from "@better-auth/core/utils";
+ import { generateId } from "@better-auth/core/utils/id";
+ import { safeJSONParse } from "@better-auth/core/utils/json";
+ import { defineErrorCodes } from "@better-auth/core/utils/error-codes";

$ERROR_CODES 类型变更为 RawError 对象

插件中的 $ERROR_CODES 字段不再是 Record<string, string>,而是 Record<string, RawError>。请使用 defineErrorCodes(),它返回包含 { code, message } 结构的对象:

- $ERROR_CODES: {
-     MY_ERROR: "My error message",
- },
+ $ERROR_CODES: defineErrorCodes({
+     MY_ERROR: "My error message",
+ }),
+ // 返回:{ MY_ERROR: { code: "MY_ERROR", message: "My error message" } }

抛出带有错误代码的异常请使用新的 APIError.from() 静态方法:

import { APIError } from "@better-auth/core/error";

throw APIError.from("BAD_REQUEST", MY_ERROR_CODES.MY_ERROR);

PluginContext 现在为泛型

PluginContext 加入了泛型参数 Options

type PluginContext<Options extends BetterAuthOptions> = {
    getPlugin: <ID extends string>(pluginId: ID) => /* 从注册表推断的结果 */ | null;
    hasPlugin: <ID extends string>(pluginId: ID) => boolean; // 如果返回 true,类型收窄为已注册插件
};

插件可通过模块声明合并注册自身,实现 getPlugin()hasPlugin() 的类型安全:

declare module "@better-auth/core" {
    interface BetterAuthPluginRegistry<AuthOptions, Options> {
        "my-plugin": { creator: typeof myPlugin };
    }
}

移除 InferUser / InferSession 类型

InferUser<O>InferSession<O> 类型已被移除,请改用通用的 UserSession 类型:

- import type { InferUser, InferSession } from "better-auth/types";
- type MyUser = InferUser<typeof auth>;
+ import type { User, Session } from "better-auth";
+ type MyUser = User<typeof auth.$options["user"], typeof auth.$options["plugins"]>;

After 钩子事务后执行

数据库的 "after" 钩子(如 create.afterupdate.afterdelete.after)现在在事务提交后执行,而非事务内。这可以防止钩子中调用外部系统(发邮件、调用 API)失败导致事务被回滚。

如需在事务中同步原子写入,请在主操作中直接使用适配器。

getMigrations 移至 better-auth/db/migration 子路径

getMigrations 函数的依赖较多,部分打包工具会因此引入额外依赖,导致包体积异常膨胀。现迁移到独立子路径:

- import { getMigrations } from "better-auth";
+ import { getMigrations } from "better-auth/db/migration";

次级存储 Session 移除 id 字段

id 字段用于数据库模型关系,次级存储中非必需,故已移除,简化存储逻辑。如插件依赖该字段,需要做相应调整。

插件 init() 上下文对象现为可变

插件 init() 回调传入的上下文,是整个认证生命周期中复用的同一对象。init() 也可以返回任意键值对,支持插件注入自定义上下文值供其他插件访问。


🐛 修复与改进

本次发布包含超过 220 项错误修复,覆盖全部核心功能:

  • Drizzle Adapter: 修复了日期转换崩溃和输入处理问题。
  • Cookie Handling: 集中解析,修复 Expo 首部分号问题,并完善安全检测降级方案。
  • Database Hooks: 延迟执行直到事务提交后,防止不一致。
  • Transaction Deadlock Prevention: 改进适配器的锁定策略。
  • Prisma Adapter: 修复空值条件处理和唯一字段检测。
  • OAuth: 修复 refresh_token_expires_in 处理、回调路由和令牌加密问题。
  • Organization: 修复角色删除预防、活动成员重新获取和动态访问控制推断。
  • Expo: 修复在 Cloudflare Workers 上的不可变头部、Cookie 注入通配符,以及 ID 令牌请求中跳过 Cookie/Expo 来源头部。
  • Kysely Adapter: 修复别名连接表名的边缘情况。
  • Last Login Method: 修复多个 Set-Cookie 头的处理。
  • Session Listing: 修复当存在超过 100 个非活动会话时返回空数组的端点问题。
  • Organization: 修复活动成员信号路径匹配。
  • OAuth: 修复在提供者省略刷新令牌时保留刷新令牌。
  • Secondary Storage: 同步 updateSession 变更并移除重复写入。
  • 以及更多修复!

大量细节打磨,带来更流畅、更快、更可靠的体验。 👉 查看完整更新日志

❤️ 感谢贡献者

Thanks to all the contributors for making this release possible!