---
title: "账号、配置与 OAuth 登录 · Finch Agent"
description: "finch.settings、API Key 与两条 OAuth 路径"
source: https://finchwork.app/zh/docs/minitools-oauth
---

# 账号、配置与 OAuth 登录

需要用户凭据的小程序有三条路径，按凭据类型选择。

## 结构化配置：`finch.settings`

manifest 声明字段，Finch 在工具箱详情页原生渲染，用户保存后自动重载小程序：

```json
{
  "settings": {
    "fields": [
      { "key": "endpoint", "type": "string", "label": "Endpoint" },
      { "key": "maxItems", "type": "number", "label": "最大条数", "default": 10 },
      { "key": "region", "type": "select", "label": "区域",
        "options": [{ "value": "us", "label": "US" }, { "value": "eu", "label": "EU" }] }
    ]
  }
}
```

代码里 `ctx.settings.get('endpoint')` 只读取，不能写入。字段类型：`string`、`number`、`boolean`、`select`、`list`；`string` 可标 `secret: true`（密码框）或 `multiline: true`（多行）。

## API Key / Token

用《[标准化 UI](/zh/docs/minitools-ui)》里的模态框表单收集，存入 `ctx.secrets`。manifest 需声明允许的密钥名：

```json
{ "permissions": { "secrets": ["apiKey"] } }
```

**入口放哪里**：ComposerAction 菜单、容器设置菜单（见《[Session 容器](/zh/docs/minitools-containers)》）、或一个 `setup_*` 工具。优先前两者——它们不依赖模型主动调用工具。

## OAuth 路径 A：小程序自己持有 provider

用于调用普通 HTTPS API（Google、GitHub 等）。manifest 声明 provider id：

```json
{ "permissions": { "oauth": ["google"] } }
```

代码定义 provider 并发起流程：

```ts
const google: finch.OAuthProviderConfig = {
  id: 'google',
  name: 'Google',
  icon: 'assets/google.png',              // 包内 PNG，显示在授权弹窗
  clientId: PUBLIC_CLIENT_ID,             // 发布者预先注册的公开 Client ID
  authorizationEndpoint: 'https://accounts.google.com/o/oauth2/v2/auth',
  tokenEndpoint: 'https://oauth2.googleapis.com/token',
  scopes: ['https://www.googleapis.com/auth/gmail.readonly'],
  resourceOrigins: ['https://gmail.googleapis.com'],  // HTTPS 白名单
};

await ctx.oauth.connect(google);
const status = await ctx.oauth.getStatus(google);
const res = await ctx.oauth.request(
  google,
  'https://gmail.googleapis.com/gmail/v1/users/me/profile',
);
await ctx.oauth.disconnect(google);
```

Finch 负责浏览器交互、加密存储、刷新加锁、Authorization 头注入。

**安全边界（必须理解）：**

-   只用 Authorization Code + PKCE 公开客户端，**不要内嵌 client secret**。
-   Access / refresh token **不会跨进程进入小程序**，只能通过 `ctx.oauth.request()` 代理调用。
-   `resourceOrigins` 是 HTTPS 白名单，不在名单内的地址会被拒绝。
-   `request()` 会剥离调用方自带的 `Authorization`、`Cookie`、`Host`、`Proxy-Authorization` 头。
-   凭据按小程序隔离存储，互相不可见。
-   `OAuthResponse.body` 是字符串，先判断 HTTP 状态再解析；不要记录可能含隐私的响应体。

**Device Flow**：GitHub 这类 Web Flow 需要 secret 的服务，设 `flow: 'device_code'` 并提供 `deviceAuthorizationEndpoint`，Finch 负责展示、复制用户码并轮询令牌端点。

**OAuth 客户端由发布者注册和维护**，公开 Client ID 随包分发，不要让终端用户自己去申请 OAuth 应用。`icon` 强烈建议配置，否则授权弹窗没有品牌标识。

![oauth](/assets/docs/minitools/oauth.png)

## OAuth 路径 B：OAuth 保护的 MCP server

远程 MCP 端点要求 OAuth 时，**不要走路径 A**。声明 `contributes.mcpServers[].oauth`，由 MCP Client 完成 discovery、动态客户端注册（DCR）、PKCE 和 token 生命周期——你无需注册任何 OAuth 客户端，也不需要 `permissions.oauth`。品牌图标通过 `mcpServers[].oauth.providerIcon` 提供。

**判断法则**：同一个服务同时声明了 `permissions.oauth` 和 `mcpServers[].oauth`，一定是选错了路径。

## 登录状态怎么呈现

推荐组合：容器设置菜单里放一行 `disabled` 的状态行 + 一行可点击的登录/退出行。后台登录状态变化时调 `notifyUpdate()` 让菜单立即刷新。详见《[Session 容器](/zh/docs/minitools-containers)》。
