# Agent Auth (/docs/plugins/agent-auth)

AI Agent 的身份认证、注册、发现以及基于能力的授权。



`AI Agents` `MCP` `Capabilities`

<Callout type="warn">
  此插件是一个处于重度开发阶段的协议标准实现。它尚未稳定，未来可能会发生变化。请在 [Github](https://github.com/better-auth/agent-auth) 上报告任何问题或错误。
</Callout>

Agent Auth 插件让你的 Better Auth 服务器充当一个 **Agent Auth 提供者**。它是 [Agent Auth Protocol](https://agentauthprotocol.com) 的服务端实现。

它为 AI agents 提供了一种标准方式来发现你的服务、注册自己、请求审批，并使用短期签名 JWT 执行受限能力。它自带 **OpenAPI** 和 **MCP** 适配器——因此你无需手写能力，就能将现有的 REST API 或 MCP 服务器转换为支持 agent-auth 的服务。

## 特性 [#特性]

* **OpenAPI 适配器** — 从 OpenAPI 3.x 规范直接派生能力、输入/输出 Schema 以及代理 `onExecute` 处理器
* **MCP 适配器** — 将 agent-auth 暴露为 MCP 工具，以便任何 MCP 兼容的 AI agent 可以发现并调用你的能力
* 在 `/.well-known/agent-configuration` 提供发现文档
* 能力列表、描述和执行（每个能力可选配 `location` URL）
* 委托和自主代理模式
* 设备授权和 CIBA 审批流程
* 具有防重放保护的短期签名 JWT
* 用于审批、授权和执行的审计/事件钩子

## 安装 [#安装]

<Steps>
  <Step>
    ### 安装依赖包 [#安装依赖包]

    <CodeBlockTabs defaultValue="npm" groupId="persist-install">
      <CodeBlockTabsList>
        <CodeBlockTabsTrigger value="npm">
          npm
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="pnpm">
          pnpm
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="yarn">
          yarn
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="bun">
          bun
        </CodeBlockTabsTrigger>
      </CodeBlockTabsList>

      <CodeBlockTab value="npm">
        ```bash
        npm install @better-auth/agent-auth
        ```
      </CodeBlockTab>

      <CodeBlockTab value="pnpm">
        ```bash
        pnpm add @better-auth/agent-auth
        ```
      </CodeBlockTab>

      <CodeBlockTab value="yarn">
        ```bash
        yarn add @better-auth/agent-auth
        ```
      </CodeBlockTab>

      <CodeBlockTab value="bun">
        ```bash
        bun add @better-auth/agent-auth
        ```
      </CodeBlockTab>
    </CodeBlockTabs>

    客户端和 CLI 包（可选）：

    ```bash
    npm install @auth/agent @auth/agent-cli
    ```
  </Step>

  <Step>
    ### 将插件添加到认证配置 [#将插件添加到认证配置]

    首先定义你的服务所暴露的能力，以及一个用于执行认证代理操作的 `onExecute` 处理器。

    ```ts title="auth.ts"
    import { betterAuth } from "better-auth";
    import { agentAuth } from "@better-auth/agent-auth"; // [!code highlight]

    export const auth = betterAuth({
      plugins: [
        agentAuth({ // [!code highlight]
          providerName: "Acme", // [!code highlight]
          providerDescription: "Acme 项目与部署 API，适用于 AI Agent。", // [!code highlight]
          modes: ["delegated", "autonomous"], // [!code highlight]
          capabilities: [ // [!code highlight]
            { // [!code highlight]
              name: "deploy_project", // [!code highlight]
              description: "将项目部署到生产环境。", // [!code highlight]
              input: { // [!code highlight]
                type: "object", // [!code highlight]
                properties: { // [!code highlight]
                  projectId: { type: "string" }, // [!code highlight]
                }, // [!code highlight]
                required: ["projectId"], // [!code highlight]
              }, // [!code highlight]
            }, // [!code highlight]
            { // [!code highlight]
              name: "list_projects", // [!code highlight]
              description: "列出当前用户可访问的项目。", // [!code highlight]
            }, // [!code highlight]
          ], // [!code highlight]
          async onExecute({ capability, arguments: args, agentSession }) { // [!code highlight] 
            switch (capability) { // [!code highlight]
              case "list_projects": // [!code highlight]  
                return [{ id: "proj_123", name: "marketing-site" }]; // [!code highlight]
              case "deploy_project": // [!code highlight]
                return { // [!code highlight]
                  ok: true, // [!code highlight]
                  projectId: args?.projectId, // [!code highlight]
                  requestedBy: agentSession.user.id, // [!code highlight]   
                }; // [!code highlight]
              default: // [!code highlight]
                throw new Error(`不支持的能力: ${capability}`); // [!code highlight]
            } // [!code highlight]
          }, // [!code highlight]
        }), // [!code highlight]
      ], // [!code highlight]
    }); // [!code highlight]
    ```
  </Step>

  <Step>
    ### 暴露发现文档 [#暴露发现文档]

    插件提供了 `auth.api.getAgentConfiguration()`，但你应该将其从应用根路径暴露为 `/.well-known/agent-configuration`。

    ```ts title="app/.well-known/agent-configuration/route.ts"
    import { auth } from "@/lib/auth";
    import { NextResponse } from "next/server";

    export async function GET() {
      const configuration = await auth.api.getAgentConfiguration();
      return NextResponse.json(configuration);
    }
    ```
  </Step>

  <Step>
    ### 迁移数据库 [#迁移数据库]

    运行迁移或生成模式以添加 agent、host、grant 和 approval 表。

    <Tabs items="[&#x22;migrate&#x22;, &#x22;generate&#x22;]">
      <Tab value="migrate">
        <CodeBlockTabs defaultValue="npm" groupId="persist-install">
          <CodeBlockTabsList>
            <CodeBlockTabsTrigger value="npm">
              npm
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="pnpm">
              pnpm
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="yarn">
              yarn
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="bun">
              bun
            </CodeBlockTabsTrigger>
          </CodeBlockTabsList>

          <CodeBlockTab value="npm">
            ```bash
            npx auth migrate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="pnpm">
            ```bash
            pnpm dlx auth migrate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="yarn">
            ```bash
            yarn dlx auth migrate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="bun">
            ```bash
            bun x auth migrate
            ```
          </CodeBlockTab>
        </CodeBlockTabs>
      </Tab>

      <Tab value="generate">
        <CodeBlockTabs defaultValue="npm" groupId="persist-install">
          <CodeBlockTabsList>
            <CodeBlockTabsTrigger value="npm">
              npm
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="pnpm">
              pnpm
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="yarn">
              yarn
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="bun">
              bun
            </CodeBlockTabsTrigger>
          </CodeBlockTabsList>

          <CodeBlockTab value="npm">
            ```bash
            npx auth generate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="pnpm">
            ```bash
            pnpm dlx auth generate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="yarn">
            ```bash
            yarn dlx auth generate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="bun">
            ```bash
            bun x auth generate
            ```
          </CodeBlockTab>
        </CodeBlockTabs>
      </Tab>
    </Tabs>
  </Step>

  <Step>
    ### 可选：添加 Better Auth 客户端插件 [#可选添加-better-auth-客户端插件]

    如果你想从 Better Auth 客户端对插件端点进行类型安全的访问，请同时添加客户端插件。

    ```ts title="auth-client.ts"
    import { createAuthClient } from "better-auth/client";
    import { agentAuthClient } from "@better-auth/agent-auth/client"; // [!code highlight]

    export const authClient = createAuthClient({
      plugins: [
        agentAuthClient(), // [!code highlight]
      ],
    });
    ```
  </Step>
</Steps>

## 工作原理 [#工作原理]

Agent Auth 流程通常如下：

1. Agent 从 `/.well-known/agent-configuration` 发现你的提供者
2. Agent 列出能力并决定所需能力
3. Agent 向你的服务器注册并请求能力授权
4. 你的用户通过设备授权或 CIBA 完成审批
5. Agent 签署短期 JWT（`aud&#x60; 匹配所调用的 URL），并在 &#x2A;*`default_location`*&#x2A; 或该能力自定义的 &#x2A;*`location`**（若已设置）调用每个已授权的能力

## 发现 [#发现]

发现文档告诉 Agent 如何与你的服务器交互。插件包含提供者元数据、支持模式、审批方法、绝对端点 URL 以及 &#x2A;*`default_location`** 字段。

需要执行的重要字段：

* **`issuer`** — 提供者的基础 URL（Better Auth 的 `baseURL`）。
* **`endpoints`** — 每个路由的绝对 URL（例如 `execute` 指向该基础路径下的 `POST /capability/execute`）。
* **`default_location`** — 默认执行端点的完整 URL。它始终与 `endpoints.execute&#x60; 匹配。当能力未定义自定义 URL 时，Agent 会将其用作 JWT 的 &#x2A;*`aud`**，并用于调用这些能力。

从应用根路径暴露它：

```ts title="app/.well-known/agent-configuration/route.ts"
import { auth } from "@/lib/auth";
import { NextResponse } from "next/server";

export async function GET() {
  const configuration = await auth.api.getAgentConfiguration();
  return NextResponse.json(configuration);
}
```

<Callout>
  发现路由应位于 `/.well-known/agent-configuration`，即使你的 Better Auth 基础路径是 `/api/auth`。
</Callout>

## OpenAPI 适配器 [#openapi-适配器]

如果你的服务已有 OpenAPI 规范，只需几行代码就能将整个 API 转换为 Agent Auth 提供者。&#x2A;*`createFromOpenAPI`** 读取规范并生成插件所需的一切：每个 `operationId&#x60; 对应一个能力、输入/输出 JSON Schema、代理 &#x2A;*`onExecute`*&#x2A; 处理器，以及可选的 &#x2A;*`providerName`*&#x2A; / &#x2A;*`providerDescription`**（从 `info` 中获取）。

```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { agentAuth } from "@better-auth/agent-auth";
import { createFromOpenAPI } from "@better-auth/agent-auth/openapi";

const spec = await fetch("https://api.example.com/openapi.json").then((r) =>
  r.json(),
);

export const auth = betterAuth({
  plugins: [
    agentAuth({
      ...createFromOpenAPI(spec, {
        baseUrl: "https://api.example.com",
      }),
    }),
  ],
});
```

就这么简单。规范中每个具有 `operationId` 的操作都会成为一个能力，其名称为该 ID。路径、查询和头参数以及 JSON 请求体被合并为一个 `input` Schema，而 200/201 响应体成为 `output`。

### 上游认证 [#上游认证]

代理处理器代表 Agent 调用你的上游 API。使用 &#x2A;*`resolveHeaders`** 注入每个请求所需的凭证（例如内部服务令牌或从 `agentSession` 查找的用户作用域访问令牌）。

```ts title="auth.ts"
createFromOpenAPI(spec, {
  baseUrl: "https://api.example.com",
  async resolveHeaders({ agentSession }) {
    const token = await getAccessToken(agentSession.user.id);
    return { Authorization: `Bearer ${token}` };
  },
});
```

### 默认主机能力 [#默认主机能力]

控制哪些能力自动授予新主机。你可以传递 `true`（全部）、单个 HTTP 方法字符串、方法数组，或接收完整运行时上下文的回调。

```ts title="auth.ts"
createFromOpenAPI(spec, {
  baseUrl: "https://api.example.com",
  defaultHostCapabilities: ["GET", "HEAD"],
});
```

### 每个方法的审批强度 [#每个方法的审批强度]

将 HTTP 方法映射到 &#x2A;*`approvalStrength`**，使修改操作需要更强的用户验证（例如 WebAuthn），而读取操作使用普通会话。

```ts title="auth.ts"
createFromOpenAPI(spec, {
  baseUrl: "https://api.example.com",
  approvalStrength: {
    GET: "session",
    POST: "webauthn",
    PUT: "webauthn",
    DELETE: "webauthn",
  },
});
```

### 每个能力的 `location` [#每个能力的-location]

当你设置 &#x2A;*`location`** 时，每个派生的能力都会获得该 URL。Agent 会直接调用它（使用 Agent JWT），而不是通过默认执行端点——当你希望 Agent 访问真实 API URL 并在你的中间件中处理会话时很有用，而不是通过 `onExecute` 代理。

```ts title="auth.ts"
createFromOpenAPI(spec, {
  baseUrl: "https://api.example.com",
  location: "https://api.example.com/agent/execute",
});
```

### 单独使用各个部分 [#单独使用各个部分]

如果你只需要部分管道，适配器也导出了较低级别的辅助函数：

* **`fromOpenAPI(spec)`** — 仅返回 `Capability[]`（不包含处理器和主机能力）。
* **`createOpenAPIHandler(spec, opts)`** — 仅返回 `onExecute` 代理处理器，因此你可以将其与手写能力或自行过滤规范搭配使用。

```ts title="auth.ts"
import {
  fromOpenAPI,
  createOpenAPIHandler,
} from "@better-auth/agent-auth/openapi";

const capabilities = fromOpenAPI(spec);
const onExecute = createOpenAPIHandler(spec, {
  baseUrl: "https://api.example.com",
});

agentAuth({ capabilities, onExecute });
```

## 功能 [#功能]

功能是应用程序与代理之间的契约。每个功能都有名称、描述，以及可选的 JSON Schema `input` 定义。

默认情况下，代理调用发现中的 &#x2A;*`default_location`*&#x2A;（执行 URL），插件运行 &#x2A;*`onExecute`*&#x2A;。如果在功能上设置了 &#x2A;*`location`**，代理将改为调用该绝对 URL —— 例如现有的 REST 路由 —— 并且&#x2A;*这些请求不会使用 `onExecute`**；你需要使用下面的辅助工具解析代理会话，并自行实现处理器。

使用功能来公开狭窄、可审查的操作，而不是广泛的 API 访问。

### 定义功能 [#定义功能]

```ts title="auth.ts"
agentAuth({
  capabilities: [
    {
      name: "create_issue",
      description: "在当前工作空间中创建问题。",
      input: {
        type: "object",
        properties: {
          title: { type: "string" },
          body: { type: "string" },
        },
        required: ["title"],
      },
    },
  ],
});
```

可选的 &#x2A;*`location`** — 代理使用代理 JWT 调用此 URL，而不是默认执行 URL：

```ts title="auth.ts"
{
  name: "create_issue",
  description: "在当前工作空间中创建问题。",
  location: "https://api.example.com/v1/issues",
}
```

### 默认执行与自定义 `location` [#默认执行与自定义-location]

* **无 `location`*&#x2A; — Agent 向 &#x2A;*`default_location`**（`endpoints.execute`）发送 `POST` 请求，并携带 `{ capability, arguments }`。插件验证 JWT 和附加的 `agentSession&#x60; 后，运行 &#x2A;*`onExecute`**。
* **带有 `location`*&#x2A; — Agent 直接调用该 URL（你的 REST 处理器、其他服务或 OpenAPI 操作 URL）。**`onExecute` 不会为此调用运行**；你需要使用下面的会话辅助工具解析 `agentSession`，并自行实现处理器。

### `onExecute` 之外的代理会话 [#onexecute-之外的代理会话]

对于自定义 &#x2A;*`location`*&#x2A; 路由（或任何非执行处理器），代理仍会发送带有代理 JWT 的 &#x2A;*`Authorization: Bearer`*&#x2A; 头。无论你使用什么框架，获取传入的 &#x2A;*`Headers`*&#x2A;（例如 &#x2A;*`request.headers`*&#x2A;，或你运行时的等效项）并传递它们 — 验证流程相同：签名、&#x2A;*`aud`*&#x2A;、重放（&#x2A;*`jti`**）、过期，以及（存在时）请求绑定声明。

**`auth.api.getAgentSession({ headers })`*&#x2A; 在进程内运行该流程并返回 &#x2A;*`AgentSession`*&#x2A; 或 &#x2A;*`null`*&#x2A;。&#x2A;*`verifyAgentRequest(request, auth)`*&#x2A; 同样通过将 &#x2A;*`Request`*&#x2A; 的 headers 转发到 &#x2A;*`GET /agent/session`*&#x2A;（通过 &#x2A;*`auth.handler`**）来实现相同功能 — 选择适合你代码结构的方式；没有框架区分，只有“headers 进、session 出”。

```ts title="api/issues/route.ts"
import { auth } from "@/lib/auth";

export async function POST(request: Request) {
  const agentSession = await auth.api.getAgentSession({
    headers: request.headers,
  });
  if (!agentSession) {
    return new Response("Unauthorized", { status: 401 });
  }
  // 检查授权、执行约束、运行你的处理器……
}
```

```ts
// 当你已有 `Request` + `auth` 并偏好辅助工具时的等效写法：
import { verifyAgentRequest } from "@better-auth/agent-auth";
const agentSession = await verifyAgentRequest(request, auth);
```

**检查授权和输入**

获取 &#x2A;*`agentSession`*&#x2A; 后，检查 &#x2A;*`agentSession.agent.capabilityGrants`**。这些是与执行时相同的数据库活跃授权（与 JWT 中的 `capabilities` 声明取交集）。对于此路由实现的功能，确保存在匹配的授权：

```ts
const CAP = "create_issue";
const allowed = agentSession.agent.capabilityGrants.some(
  (g) => g.capability === CAP && g.status === "active",
);
if (!allowed) {
  return new Response("Forbidden", { status: 403 });
}
```

如果该授权有 &#x2A;*`constraints`*&#x2A;，以与 &#x2A;*`POST /capability/execute`*&#x2A; 相同的方式验证请求体或查询 —— 否则客户端可以通过调用你的自定义 URL 绕过约束。插件不会在任意路由上重新运行执行的约束辅助工具；该逻辑保留在你的处理器中（或调用你从 &#x2A;*`onExecute`** 路径中提取的共享代码）。

**会话中包含的内容**

* **`agentSession.user`*&#x2A; — 解析出的用户（托管用户或 &#x2A;*`resolveAutonomousUser`**）。
* **`agentSession.agent`*&#x2A; — ID、名称、模式、&#x2A;*`capabilityGrants`**、托管 ID 和元数据。
* **`agentSession.host`** — 当 Agent 与托管关联时的托管记录。

类型从 &#x2A;*`@better-auth/agent-auth`*&#x2A; 导出（例如 &#x2A;*`AgentSession`**）。

### JWT 受众（`aud`） [#jwt-受众aud]

JWT &#x2A;*`aud`** 必须与你正在调用的 URL 匹配：

* **无每个能力的 `location`*&#x2A; — 使用 &#x2A;*`default_location`*&#x2A; / &#x2A;*`endpoints.execute`**，或插件已允许的发行者 / 基础路径值。
* **带有 `location`*&#x2A; — &#x2A;*`aud`** 应为该相同的绝对 URL。`GET /capability/list` 在设置时会包含 `location`。配置中的无效 `location` 值会在启动时失败。

**单一功能的 JWT** — 如果 `capabilities&#x60; 只列出一个 ID，设置时 &#x2A;*`aud`*&#x2A; 可以等于该功能的 &#x2A;*`location`**。

**多个功能的 JWT*&#x2A; — 不接受每个功能的 &#x2A;*`location`*&#x2A; 值作为 &#x2A;*`aud`**；改用发行者、基础路径或默认执行端点。

在反向代理后面，如果需要 &#x2A;*`Host`*&#x2A; / &#x2A;*`X-Forwarded-Proto`*&#x2A; 与 &#x2A;*`aud`*&#x2A; 验证对齐，请设置 &#x2A;*`trustProxy`**。

### 过滤可见的功能 [#过滤可见的功能]

使用 `resolveCapabilities` 向不同调用者展示不同的功能集，例如按计划、用户或组织限制的功能。

### `onExecute` [#onexecute]

用于使用**默认执行 URL**（无每个功能的 `location`）的功能。插件验证 JWT（包括 `aud`）、附加 `agentSession`、检查授权，然后运行 `onExecute`。具有自定义 `location` 的功能永远不会到达此路径 — 你使用上面的会话辅助工具在自己的路由中处理它们。

```ts title="auth.ts"
agentAuth({
  capabilities: [
    {
      name: "create_issue",
      description: "在当前工作空间中创建问题。",
    },
  ],
  async onExecute({ capability, arguments: args, agentSession }) {
    if (capability !== "create_issue") {
      throw new Error("不支持的功能");
    }

    return {
      ok: true,
      title: args?.title,
      createdBy: agentSession.user.id,
    };
  },
});
```

## 授权流程 [#授权流程]

插件支持两种授权方法：

* `device_authorization` 用于基于浏览器的审批（用户代码）
* `ciba` 用于后台通道审批流程

默认情况下，两者都启用。你可以使用 `approvalMethods` 和 `resolveApprovalMethod` 来限制或自定义它们。

```ts title="auth.ts"
agentAuth({
  approvalMethods: ["ciba", "device_authorization"],
  resolveApprovalMethod: ({ preferredMethod, supportedMethods }) => {
    if (preferredMethod && supportedMethods.includes(preferredMethod)) {
      return preferredMethod;
    }
    return "device_authorization";
  },
  deviceAuthorizationPage: "/device/capabilities",
});
```

<Callout type="warn">
  插件不会为你渲染设备授权 UI。你的应用必须提供 `deviceAuthorizationPage` 引用的页面。
</Callout>

## 事件与审计 [#事件与审计]

* 代理创建和撤销

* 主机创建和注册

* 能力请求和审批

* 能力执行

* 代理创建和撤销

* 主机创建和注册

* 能力请求和审批

* 能力执行

## 配置 [#配置]

Agent Auth 插件支持许多选项。这些是你通常首先使用的：



<TypeTable type="agentAuthOptionsType" />

