# Remote HTTP OAuth

`autos.mcp.oauth` 0.1.0 是独立的桌面公共客户端授权模块；协议传输由 `autos.mcp` 处理，当前核心支持 `2025-11-25` 与 `2026-07-28`，默认使用前者。授权与传输代际分开，不增加 Autos 全局工具、全局 worker 或 GitHub 特例。

## 能力与边界

- 解析 Bearer 挑战；优先使用 `resource_metadata`，否则尝试路径级、根级受保护资源元数据。
- 支持 OAuth 授权服务器元数据及两种 OIDC 发现路径，校验 resource、issuer、PKCE S256 支持。
- 按预注册 `clientId` → 已托管 `clientMetadataUrl`（CIMD）→ 显式启用的 DCR 选择公共客户端注册方式。
- 系统浏览器 + 仅绑定 `127.0.0.1` 的临时回调监听；校验 state、重复参数、回调路径及 Host。AS 声明支持 `iss` 时要求匹配；未声明时仍拒绝不匹配的 `iss`。
- 授权与令牌请求均包含 `resource`。Bearer 只发给绑定的 MCP endpoint；请求不跟随重定向，不带 Cookie 或系统自动登录凭据，不忽略 TLS 证书错误。
- DPAPI 存储可选。刷新支持轮换；过期前 30 秒可主动刷新。不自动打开浏览器续授权，不自动重放 MCP 业务请求。
- 这是初版：已通过受控 HTTP/回调/刷新/界面测试，并完成真实 Linear Remote HTTP OAuth 的用户浏览器授权、只读身份调用和显式刷新后复测（DCR，MCP 2025-11-25）。官方静态 CIMD 已部署于 `https://aau.cn/oauth/mcp/client-metadata.json`；分支选择与动态回环监听已做本机测试，外部 AS 抓取该文档及真实 CIMD 授权仍未验收。单一服务验收不代表所有服务或 OAuth 扩展均已验证。

不支持 confidential client / clientSecret、Device Code、client_credentials、私钥 JWT、自动撤销、账户管理平台、并发刷新调度。**一个存储名只由一个活动 OAuth 实例使用**；不要跨线程传递实例或同时用多个实例刷新同一存储名。

## Autos 默认身份与中立构造函数

- `autos.mcp.createOAuth(config,storeName)`：Autos 应用便捷入口，按需导入本模块；仅在未指定 `clientId` 和 `clientMetadataUrl` 时补充官方 CIMD 候选，不修改调用方配置。
- `autos.mcp.oauth(config,storeName)`：通用、中立构造函数，没有产品身份默认值，供其他软件或完全自定义配置使用。
- 预注册 `clientId` 优先；自定义 `clientMetadataUrl` 保留。在 `createOAuth` 中传 `clientMetadataUrl=false` 可禁用默认候选，该便捷参数在传给通用构造函数前会被移除。预注册与自定义 CIMD 配置的凭据绑定不变。
- 仅在 AS 声明 `client_id_metadata_document_supported=true` 时使用 CIMD；不覆盖预注册身份。DCR 仍仅在 `allowDynamicRegistration=true` 时启用。已选择 CIMD 后不会因授权失败自动改用 DCR。
- 官方文件是静态 JSON，本机 `redirectPort` 默认 `0`，由系统分配端口。文档中回环 URI 的示例端口不要求客户端绑定该端口；不为端口变化生成新的文档 URL。
- 两种构造函数都不联网、不打开浏览器；不会因此重复用户已完成的授权。使用新默认候选形成的新配置与过去的 DCR 配置不同；要继续旧配置及其凭据，应保留原通用构造方式，或显式禁用默认候选。

## 最小登录窗口

Autos 可使用以下入口；只需将 endpoint 换为已信任的真实服务地址，不要填介绍网页。服务不支持 CIMD 时，按其要求提供预注册 `clientId` 或显式启用 DCR。

```aardio
import win.ui;
import autos.mcp;
import autos.mcp.oauth.login;

var auth,err = autos.mcp.createOAuth({
    url = "https://mcp.example.com/mcp";
    // clientId = "YOUR_REGISTERED_PUBLIC_CLIENT_ID"; // 已有预注册身份时优先
    // scope = "read:user"; // 按实际服务与用户任务设置最小权限
    // redirectPort 默认为 0，无需固定端口
}, "MyRemoteService");

if(!auth) return null,err;
var loginForm = autos.mcp.oauth.login(auth);
loginForm.show();
win.loopMessage();
```

构造和显示窗口都不自动授权。用户单击“开始授权”才开始；等待期间“重新打开浏览器”和“取消”可用。取消后可在同一窗口重新开始。关闭窗口会先取消当前操作，再释放回调监听。

原生回环回调使用默认动态端口，静态元数据不需随之变化。回环 IP 和路径仍须与注册信息一致；自定义产品身份应使用自己的 CIMD 文档。DCR 仅在 `allowDynamicRegistration=true` 时注册，不主动向未知服务创建客户端。

## 与现有 session 组合

完成授权后，在同一上下文中创建 resolver，不必修改 MCP 核心：

```aardio
import autos.mcp.session;

var mcp = autos.mcp.session(function(options){
    return auth.getConfig(options); // 配置含令牌，不要打印
});

var tools,err,detail = mcp.listTools();
// 使用实际服务器提供并经审核的工具。
mcp.close();
auth.close();
```

重启后用完全相同的配置与存储名重新构造 `auth`，`getConfig()` 会读取 DPAPI。若没有有效凭据，返回 `authorization_required`，调用者应显式显示登录窗口。

若已有未经授权的 MCP 请求返回 `detail.wwwAuthenticate`，传入 `authorize({challenge=detail.wwwAuthenticate})` 或登录窗口的第 3 个参数。不要重放那次业务调用；授权后是否再次调用由业务层决定。

## 信任来源与安全回调

初始 endpoint 的 origin 来自本机配置。新发现的其他 origin 默认拒绝继续，返回 `trust_required`，不会静默请求该地址。登录窗口会显示来源并请求用户确认；可信本机代码也可显式提供 `trustedOrigins=["https://auth.example.com"]` 或 `confirmOrigin(origin,purpose)`。

`trustedOrigins` 是 origin 数组，不能带路径或查询；不要根据服务返回数据直接把所有地址加入白名单。这是本机显式信任策略，不是 DNS 重绑定沙箱。只连接可信服务；不支持无需用户确认的任意来源抓取。

`openBrowser(url)` 是给本机集成/测试的可选回调：**必须启动浏览器后立即返回，不要在回调内等待登录结束**。默认使用系统浏览器。URL 含敏感 state/PKCE 参数，不得送给模型、写日志或回传聊天。`onStatus(state)` 只收到安全状态名。`shouldStop()` 可用于取消。

授权服务器、回调和 HTTP 错误只输出有界错误类型/状态，不输出原始 OAuth 正文、令牌、授权码或 `error_description`。

## 凭据生命周期

- `storeName` 省略：仅当前实例内存保存。
- `storeName` 指定：存于 settings 管理的 `oauth<storeName>` DPAPI 文件，不进入技能资源。
- 凭据绑定配置哈希、endpoint、resource、issuer、clientId、token endpoint。配置改变（包括超时等配置项）时拒绝静默套用旧凭据，应重新授权。
- `close()` 清理内存和监听，不删除 DPAPI。
- `forget()` 删除本机凭据，不声称服务端撤销。
- 为避免重用可能已消耗的轮换令牌，刷新前先删除旧记录；刷新失败后须重新授权。这是初版偏保守的策略，不做静默重试。
- API 所说“通用”指上述标准公共客户端流程；不是保证每个服务只填 URL 都能登录。

## Playground 两类验收不能混淆

网站 HTML 说明页提供 `POST /api/auth/token`：可签发 30 分钟测试 Bearer 令牌，再访问 `mcp-auth-server?rev=2025-11-25`。已经实际验证无令牌 401、签发、带令牌初始化、列工具和调用 `get_user`。

这覆盖认证后的业务小闭环，不能替代 `authorization_code + PKCE + redirect + refresh_token` 的 OAuth 验收。网站的 `.md` 摘要缺少签发接口，不能仅看摘要就断言 Auth 服务只能测 401。

## 规范依据

- MCP 2025-11-25 Authorization：`https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization.md`
- PKCE：`https://www.rfc-editor.org/rfc/rfc7636`
- Native Apps：`https://www.rfc-editor.org/rfc/rfc8252`
- Playground HTML 说明：`https://mcpplaygroundonline.com/mock-mcp-servers`
