# @authlocker/better-auth 中文文档

规范地址：https://npmcn.com/package/%40authlocker/better-auth/

版本：0\.0\.2
npm 元数据更新时间：2026-09-02T08:36:17.435Z
中文译文更新时间：2026-11-07T06:04:19.429Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40authlocker/better-auth
原文对照：https://npmcn.com/package/%40authlocker/better-auth/?lang=original

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：213 kB，14 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- 运行依赖：2 个
- peer 依赖：better-auth \>=1\.7\.0
- 首次发布：2026-09-01T15:14:23.197Z
- 最新版本发布：2026-09-02T08:36:17.120Z
- 近 30 天下载量：3348（2026-10-07 至 2026-11-05，npm 官方下载统计）
- 已发布版本数：2（近 12 个月 2 个）

## 中文简介

AuthLocker 更好的 Auth 插件: 由 authlocker.dev 验证的电子邮件和短消息代码, 并为您创建会话 .

## 安装

```sh
npm install @authlocker/better-auth
```

也可以使用：`pnpm add @authlocker/better-auth`、`yarn add @authlocker/better-auth`、`bun add @authlocker/better-auth`

## README

# @authlocker/ 更好 - auth

更好的认证插件 [奥特洛克](https://authlocker.dev/)电子邮件和短信 由 AuthLocker 生成并检查的一次性代码, 并带有更好的 Auth 为您创建会话 .

```bash
pnpm add @authlocker/better-auth better-auth
```

要求数 `better-auth` **1.7.0或更新**大量更好的认证材料 互联网上写着1.6或更早 下文在1.7中有所改变——它们被称作重要之处.

## 它做什么,它故意没有

三个端点,安装在您已有的更好的 Auth 处理器内:

| 终点 | 客户端呼叫 | 对 |
| --- | --- | --- |
| `POST /api/auth/authlocker/send-otp` | `authClient.authlocker.sendOtp()` | 请 AuthLocker 生成并发送代码 |
| `POST /api/auth/authlocker/verify-otp` | `authClient.authlocker.verifyOtp()` | 检查、找到或创建用户、设置会话 cookie |
| `POST /api/auth/authlocker/resend-otp` | `authClient.authlocker.resendOtp()` | 再次发送相同的验证 |

**AuthLocker 生成并检查每个代码.** 这个插件从不薄荷, 永远不要存储一个, 从来没有计算尝试。 更好的奥特 `verification` 表格完全没有使用——重放保护,五通关卡 10分钟后, 三档预算和第六十二档 都住在AuthLocker,按键 `verificationId`。 。 。 .

如果你打开线人 期待检察官办公室的正常账簿记录, 因此,应当明确指出:这里没有任何人。 这也是重点所在。 满 授权就是让Twilio验证欺诈的分数 节流阀和短消息 花帽在玩。 仅限插件 _已交付_ 消息会把一切都扔掉的.

唯一不住在奥特洛克的地方 是限制你的速度 应用程序将调用它, 因此插件宣布它自己的费率限制为防御 深度:每分5发,每分10次验证,每个客户端.

## 设置

### 1\. 联合国. `lib/auth.ts`

```ts
import { betterAuth } from "better-auth";
import { nextCookies } from "better-auth/next-js";
import { authlocker } from "@authlocker/better-auth";

export const auth = betterAuth({
  database: /* your adapter */,
  plugins: [
    authlocker({
      clientId: process.env.AUTHLOCKER_CLIENT_ID!,
      clientSecret: process.env.AUTHLOCKER_CLIENT_SECRET!,
    }),
    // `nextCookies()` must be LAST. It works by hooking every response after
    // the other plugins have written their cookies; anything registered after
    // it sets cookies that never reach the browser.
    nextCookies(),
  ],
});
```

客户端的秘密永远留在服务器上. `POST /api/v1/verify/*` 带有 HTTP Basic 和 AuthLocker 的认证 发送任何 CORS 头, 所以 a 浏览器无法调用它, 即使你愿意将这个秘密传送给一个. 这个限制是这个插件存在的原因 .

从 `POST /oauth/register`,或 `npx botparty authlocker provision`。 。 。 .

### 2\. 联合国. `app/api/auth/[...all]/route.ts`

```ts
import { toNextJsHandler } from "better-auth/next-js";
import { auth } from "@/lib/auth";

export const { GET, POST } = toNextJsHandler(auth.handler);
```

### 3个. `lib/auth-client.ts`

```ts
import { createAuthClient } from "better-auth/react";
import { authlockerClient } from "@authlocker/better-auth/client";

export const authClient = createAuthClient({
  plugins: [authlockerClient()],
});
```

方法名称来源于端点路径 kebab- case 到 caham- case, 所以 `/authlocker/send-otp` 变成 `authClient.authlocker.sendOtp()`您没有 宣布他们.

### 4\. 管理移徙

该插件添加 `phoneNumber` 财务报告和审定财务报表 `phoneNumberVerified` 页:1 `user` 页:1 短消息频道需要放置一个已核实的号码和更好的 Auth 用户 模型没有一栏。 名字和Auth的内置一致 `phoneNumber()` 插件是故意的,所以运行两个应用程序都会有一个 页:1.

```bash
npx @better-auth/cli migrate
```

## 用这个

```tsx
"use client";
import { useState } from "react";
import { getAttemptsRemaining } from "@authlocker/better-auth/client";
import { authClient } from "@/lib/auth-client";

export function SignIn() {
  const [verificationId, setVerificationId] = useState<string | null>(null);
  const [attemptsLeft, setAttemptsLeft] = useState(5);
  const [message, setMessage] = useState("");

  async function send(to: string) {
    const { data, error } = await authClient.authlocker.sendOtp({
      channel: "email",
      to,
    });
    if (error) return setMessage(error.message ?? "Could not send a code");
    setVerificationId(data.verificationId);
    // `data.to` is masked — "a**@example.com". Safe to show back.
    setMessage(`Code sent to ${data.to}`);
  }

  async function verify(code: string) {
    const { error } = await authClient.authlocker.verifyOtp({
      verificationId: verificationId!,
      code,
    });
    if (!error) return; // Session cookie is set. You are signed in.

    switch (error.code) {
      case "INVALID_CODE": {
        const left = getAttemptsRemaining(error) ?? 0;
        setAttemptsLeft(left);
        return setMessage(`Wrong code — ${left} left`);
      }
      case "VERIFICATION_LOCKED":
        return setMessage("Too many tries. Start again.");
      case "VERIFICATION_EXPIRED":
        return setMessage("That code expired. Send a new one.");
      default:
        setMessage(error.message ?? "Something went wrong");
    }
  }
}
```

短信,通过 `channel: "sms"` 和E.164的电话号码(`+15551234567`) (中文(简体) ).

### 错误是 API

该插件通过AuthLocker的出错代码而不是平分它们, 因为一个签到的形式 真正不同的事情 来谈论每一个. 把它们全部折叠到一个赤裸的401——这就是手卷的代理端点 通常是的——使正确的UI无法构建.

| `error.code` | 状态 | 这是什么意思 |
| --- | --- | --- |
| `INVALID_CODE` | 400个 | 错误的代码。 还带着 **`attemptsRemaining`**。 。 。 . |
| `VERIFICATION_LOCKED` | 409个 | 5次尝试。 终端——发送新代码. |
| `VERIFICATION_EXPIRED` | 400个 | 过了10分钟TTL。 责无旁贷;提供再版. |
| `VERIFICATION_ALREADY_VERIFIED` | 409个 | 单用. 通常为双提交表. |
| `RESEND_TOO_SOON` | 429个 | 60秒窗内. |
| `RESEND_LIMIT_REACHED` | 429个 | 3次重新进行核查. |
| `NOT_FOUND` | 404 (韩语) | 未知或已收获 `verificationId`。 。 。 . |
| `SMS_REQUIRES_CLAIMED_CLIENT` | 403 (韩语) | 见下文. |
| `SMS_COUNTRY_BLOCKED` | 403 (韩语) | 此客户端没有启用拨号代码 . |
| `SMS_DAILY_CAP_REACHED` | 429个 | 客户端自有"每日短信"封顶. |
| `USER_NOT_FOUND` | 400个 | `disableSignUp` 没有人拥有那个地址。 密码是 _对_;不要告诉当事人这是错的. |
| `AUTHLOCKER_UNREACHABLE` | 第503条 | 腾讯网. 故意在AuthLocker的词汇之外,所以一个DNS的失败永远不会被误认为是一个错误的代码. |

`attemptsRemaining` 以兄妹身份抵达 `error` 在电线上,不是里面. 插件将它提升到错误的正文上 `getAttemptsRemaining(error)` 从 `@authlocker/better-auth/client` 读回 — 更好的 Auth 客户端错误类型 固定在 `{ code, message, status, statusText }`,所以额外的字段到达 浏览器,但不包括类型,而这个帮助者是替代铸件的替代.

### 你发送的第一个短消息可能会失败

`SMS_REQUIRES_CLAIMED_CLIENT` 是最可能的首发失败. AuthLocker只为归属于BotParty命名空间的客户发送短信, 因为每条消息都要花很多钱 电子邮件和 OAuth 的未声明工作 客户端,所以没有 警告你直到第一个 `channel: "sms"`。 。 。 .

向客户索赔 `registration_access_token`,或 `npx botparty authlocker provision`,设置 `verify.dailySmsCap` 当你 在那边.

插件还记录了像这样的配置类失败 `ctx.context.logger` 在服务器上, 不仅仅是呼叫者 第一次在浏览器内获取,其中半构件形式极有可能 吞下尸体,展示一个通用的红色土司.

## 社会登录 : `genericOAuth`,没有我们的插件

AuthLocker是符合标准的OIDC供应商,所以Better Auth的内置 `genericOAuth` 用发现处理Google和GitHub。 没有 这个包裹已经涉及到了.

```ts
import { betterAuth } from "better-auth";
import { genericOAuth } from "better-auth/plugins";
import { nextCookies } from "better-auth/next-js";
import { authlocker } from "@authlocker/better-auth";

export const auth = betterAuth({
  database: /* your adapter */,
  plugins: [
    authlocker({
      clientId: process.env.AUTHLOCKER_CLIENT_ID!,
      clientSecret: process.env.AUTHLOCKER_CLIENT_SECRET!,
    }),
    genericOAuth({
      // One entry per upstream provider, sharing a single client_id.
      config: (["google", "github"] as const).map((provider) => ({
        providerId: provider,
        clientId: process.env.AUTHLOCKER_CLIENT_ID!,
        clientSecret: process.env.AUTHLOCKER_CLIENT_SECRET!,
        discoveryUrl:
          "https://authlocker.dev/.well-known/openid-configuration",
        // The discovered authorization_endpoint is /oauth/authorize, which
        // answers 400 unless the request names a provider.
        authorizationUrlParams: { provider },
        scopes: ["openid", "email", "profile"],
        // Defaults to true in 1.7. Written out because AuthLocker *requires*
        // PKCE — leaving it implicit hides a hard requirement.
        pkce: true,
      })),
    }),
    nextCookies(),
  ],
});
```

```ts
await authClient.signIn.social({ provider: "google" });
```

6个容易出错的东西,都会产生混乱 失败,而不是明显的失败:

-   **每个上游供应商一个配置,一个不叫 `"authlocker"`。 。 。 .** 这个 发现 `authorization_endpoint` 实值 `/oauth/authorize`,和 AuthLocker 键 拒绝一个不指定提供者的请求——所以每个条目都需要 `authorizationUrlParams: { provider: "google" }`编辑 `providerId` 同时是 您所传递的字符串 `signIn.social()` 还有 `<SocialButtons>` 从 登记发送,所以命名他们 `"google"` 财务报告和审定财务报表 `"github"`。 。 。 .
-   **回电是 `{baseURL}/api/auth/callback/{providerId}`** ——每笔 输入,所以 `/api/auth/callback/google` 财务报告和审定财务报表 `/api/auth/callback/github`选择 `/api/auth/oauth2/callback/...`,这是前1.7,也是大多数博客贴出的内容 仍然显示。 用 AuthLocker 注册确切的字符串 : `redirect_uri` 实值 准确匹配,登记后不能更改,不登记 再来一次.
-   **奥米 `redirectURI`** 让更好的Auth从中得来 `baseURL`编辑 上游的文献对此自相矛盾 匹配上面的路径.
-   **`authClient.signIn.social({ provider })`。 。 。 .** `signIn.oauth2()` 不再继续 已存在.
-   **没有 `genericOAuthClient()` 再来一次.** 客户端没有要添加的内容 用于社交登录.
-   **`nextCookies()` 最后一个**,如上. (中文(简体) ).

### 每个应用程序注册客户端一次,而不是每个功能一次

AuthLocker 问题 **双向** 主题标识符,取自 `client_id :: provider :: upstream user id`。注册客户两次和 同一个Google账户在两个不同的下方到达 `sub`s, 哪个更好的 Auth 存储为两个账户,没有投诉。 每个应用程序一个注册——两个 `genericOAuth` 上面的条目是罚款 完全因为他们共享 a `client_id`;只有上游供应商不同,谷歌的身份和 GitHub的身份总是两个身份.

## 已经使用更好的 Auth `emailOTP()`? 吗?

你无法做到 `emailOTP()` 我是奥特洛克的代表 它已经 **没有 `verifyOTP` 钩子** 它生成代码,储存在 `verification` 表格中, 盘点尝试,自己检查, 让你的回话来完成交付 只有这个 连接 AuthLocker 进入 `sendVerificationOTP` 会降级到邮件中 中继 : 消息中的代码将是更好的 Auth , 而 AuthLocker 的欺诈 计分,尝试关闭 和每个目标油门永远不会运行.

内置 `phoneNumber()` 插件 _已经_ 有个 `verifyOTP` 钩子和可以 代表适当的短信。 如果你已经是了,这才是真正的选择 投资了它,但它覆盖一个频道, 所以你最后会有两个 不同的客户端 API 为相同的流量, 它仍然留下电子邮件未授权 . 此插件以一个形状覆盖两个频道 .

如果你坚持 `phoneNumber()` 与此插件并列, 共享 `phoneNumber` 栏是有意的,两个定义合并.

## 选项

```ts
authlocker({
  clientId: string,
  clientSecret: string,

  // Base URL of the AuthLocker deployment. Default "https://authlocker.dev".
  issuer?: string,

  // Refuse to provision a user for an address nobody owns yet, so a correct
  // code signs in an existing account or fails with USER_NOT_FOUND.
  // Off by default: passwordless OTP sign-in is normally also sign-up.
  disableSignUp?: boolean,

  // User column holding a verified E.164 number. Default "phoneNumber".
  phoneNumberField?: string,

  // Placeholder address for a user who signed up by SMS — Better Auth's user
  // model requires a unique email and an SMS sign-up has none. The default
  // builds one under `.invalid`, which RFC 2606 reserves so it can never
  // resolve. It does copy the number into a second column; override this if
  // that matters to you.
  getTempEmail?: (phoneNumber: string) => string,

  // Display name for a newly created user. Empty by default — prompt for a
  // real one afterwards rather than guessing from an address.
  getName?: (to: string, channel: "email" | "sms") => string,
})
```

## 限制费率

插件声明 :

| 路径 | 窗口 | 马克斯 |
| --- | --- | --- |
| `/authlocker/send-otp`, (中文(简体) ), `/authlocker/resend-otp` | 60岁 | 页:1 |
| `/authlocker/verify-otp` | 60岁 | 10个 |

二事须知. 更好的 Auth 应用利率限制 **仅生产** 以 默认( e)`rateLimit.enabled`),这些是惰性的 `next dev`和一个 应用程序级 `rateLimit.customRules` 其中一条路径的条目将覆盖 插件集,这是支持的收紧或松动它们的方法 :

```ts
betterAuth({
  rateLimit: {
    customRules: {
      "/authlocker/send-otp": { window: 3600, max: 10 },
    },
  },
});
```

## 服务器端呼叫

每个终点都在 `auth.api` 此外,对于服务器动作和路由处理器:

```ts
const verification = await auth.api.sendOtp({
  body: { channel: "email", to: "ada@example.com" },
});
```

## 什麽 `verify-otp` 返回时

`{ verification, token, user }`。 。 。 . `token` 财务报告和审定财务报表 `user` 是其他更好的东西 认证登录返回; `verification` 是因为 `@authlocker/react` 类型 `AuthLockerAdapter.checkVerification` 以 `Verification` 财务报告和审定财务报表 把它开走 如果没有正确的代码, 将失败的解析 并显示为一个错误 对于已经获得一个会话饼干的人.

## 没有记录的东西

地址和代码,永远. `verify/check` 是一个 AuthLocker 响应 - 代码刚刚证明收件人 收到它——这个插件将这个值视为查找或创建输入:永远 已登录, 并且除属于用户行外, 无处写入 。 它确实会回来 打开 `verification.to`键入一个浏览器 与a并列 `user` 已经带有同一地址;这就是允许 `onVerified` 显示它自己的文件承诺。 到处都是 `to` 实值 已蒙上面罩( n)`a**@example.com`, (中文(简体) ), `+*******6789`) (中文(简体) ).

## 许可证

麻省理工学院

## 常见问题

### @authlocker/better-auth 是什么？

AuthLocker 更好的 Auth 插件: 由 authlocker\.dev 验证的电子邮件和短消息代码, 并为您创建会话 \.

### 如何安装 @authlocker/better-auth？

在项目目录运行 npm install @authlocker/better-auth，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：better-auth（\>=1\.7\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @authlocker/better-auth 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @authlocker/better-auth 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @authlocker/better-auth 可以商用吗？

@authlocker/better-auth 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @authlocker/better-auth 的下载量有多少？

根据 npm 官方下载统计，@authlocker/better-auth 在 2026/10/07 – 2026/11/05 这 30 天内被下载 3,348 次，日均约 112 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @authlocker/better-auth 还在维护吗？

最新版本 0\.0\.2 发布于 2026/09/02（2 个月前）；至今共发布 2 个版本，其中过去 12 个月发布了 2 个；首次发布于 2026/09/01。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

