OAuth 资源权限(第三方 App 管理工作流)
第三方 OAuth 应用(access_token 前缀 wno-)除了调用已发布的工作流,还可以申请下列资源 scope,以授权用户的项目权限为边界管理整套工作流生命周期:发现项目 → 创建/编辑文档 → 草稿试跑 → 发布版本 → 固定版本调用 → 读取运行记录。
源码: apps/backend/src/routes/(projects / document-edit / document-versions / deployments / runs)
Scope 一览
| Scope | 说明 | 覆盖端点 | 风险级 |
|---|---|---|---|
projects:read | 读取你可访问的团队与项目 | GET /projects | 普通 |
documents:read | 读取文档内容与 revision 历史 | GET /documents/:id/content、GET /documents/:id/revisions、GET /documents/:id/revisions/:revisionId | 普通 |
documents:write | 创建文档、提交编辑 | POST /documents、POST /documents/:id/edit | 敏感 |
flows:execute | 草稿试跑 | POST /runs | 敏感 |
releases:publish | 创建 revision、发布 deployment | POST /documents/:id/revisions、POST /deployments | 敏感 |
runs:read | 读取当前授权用户通过本应用触发的运行记录 | GET /runs、GET /runs/:runId | 普通 |
调用已发布的 Release(含事件订阅 / 取消 / 续跑)使用既有的 release:invoke 等 scope,见 OAuth 2.0 与 API 运行接口。
普通项目 Scope 已纳入自助申请:开发者可自行选择并保存 Client 草稿,作者与名单内体验者沿用现有开发资格;公开使用仍须审核、发布及用户全新 OAuth 同意。旧 token 不自动增加权限。历史定向 grants 保留;管理员显式撤销对当前 Client 优先拒绝,管理员仍可按登记策略和版本 CAS 新建、撤销或恢复这 16 项的定向 grant。
自助清单为 projects:read、documents:read/write、flows:execute、runs:read、releases:publish、project:releases:read、project:data:read/write、project:files:read/write、project:skills:read/write、project:kb:read/write、billing:receipts,共 16 项。开发和公开自助资格均为 account;开发名单与项目成员资格、公开审核发布和每次资源 ACL 继续执行。消费回执仅限本人和当前 App。管理员、网页登录、官方 Host 和专用 vendor 权限不在此清单。
权限边界
- scope 只是入场券:端点内部仍按授权用户在目标项目上的实际权限判定(读 / 写 / 执行 / 管理员)。用户无权的项目,带 scope 也会 403。
- 运行记录按用户和 App 双重隔离:
runs:read只能看到当前授权用户通过本应用触发的运行;同一 App 的其他用户、当前用户的其他 App 或编辑器运行均不可见。列表与详情响应不公开内部执行快照。事件/追踪读取还要求对运行所属项目具有 read 权限(项目 owner 也可读);仅调用他人的公开 Flow 不授予此权限。 - 冲突校验、版本快照、乐观并发控制(
base_version409)等既有规则全部沿用。
requestId 幂等
创建运行类请求(POST /api/released-app/:deploymentId/run、POST /api/released-app/d/:documentId/run、POST /runs)支持调用方幂等键:
{
"inputs": { "text": "hello" },
"requestId": "jojo-event-000042",
"sessionId": "conv-abc",
"causationId": "msg-42",
"parentRunId": "0f0e0d0c-0b0a-4a09-8807-060504030201"
}requestId 是你自己生成并随请求携带的业务事件标识(同一 App 内唯一,≤128 字符);也可以使用 Idempotency-Key 请求头(≤200 字符,优先于 body requestId)。恢复查询按已验证的授权用户与 App 隔离,不能凭同一 App 和键查到其他用户的运行:
- 首次请求:正常执行。
- 同键、相同请求内容的新版本已受理运行(如网络超时后重试):不再执行、不再扣费,返回原运行的
200 { "runId": "...", "status": "...", "idempotentReplay": true }和X-Wainao-Request-Id响应头。status是原运行当前状态,不表示它一定成功。 - 同键对应不同请求内容,或旧 run 缺少新版本的请求指纹、无法证明相同时:
409 { "error": "idempotency_conflict" },不会重新执行或泄露其他用户的 runId。
它和 runId 的区别:runId 由服务器在执行开始时生成,放在响应里——网络断掉时你拿不到它,也就没法用它防重;requestId 在请求发出前就属于你,重试多少次服务器都能认出是同一件事。
其余三个字段为可选的来源标识(均 ≤128 字符):sessionId 会话归组、causationId 事件因果链、parentRunId 关联父运行(必须是已存在的 run UUID,否则 404 parent_run_not_found)。
Release 网关端点(
/api/released-app/r/:alias/...)的请求体就是业务输入,不支持这些保留字段;带凭据调用可改用Idempotency-Key请求头,匿名赞助调用不提供客户端幂等定位。也可继续使用上面的 deployment/document 端点。
典型接入流程
GET /projects(不带teamId)发现用户可访问的全部项目。POST /documents在目标项目创建 flow 文档,POST /documents/:id/edit写入内容(带base_version乐观锁)。POST /runs草稿试跑,订阅结果与日志。- 发布时按服务端版本化写开关选择路径:启用
DOCUMENT_VERSIONING_WRITE_ENABLED时,先POST /documents/:id/revisions创建不可变 revision,再带revision_id调用POST /deployments;未启用时,前者返回404 document_versioning_write_disabled,直接调用不带revision_id的POST /deployments发布当前草稿快照。该 404 不能视为 OAuth 授权失败。 - 固定版本并行调用(deployment/document 端点 + requestId),
GET /runs/GET /runs/:runId读取运行记录归档展示。
错误码
| 状态码 | 错误 | 说明 |
|---|---|---|
| 403 | insufficient_scope | token 未包含该端点所需 scope |
| 403 | 项目/文档权限类错误 | 授权用户在目标资源上无对应权限 |
| 400 | invalid_requestId 等 | 元数据字段非法(非字符串 / 超 128 字符 / parentRunId 非 UUID) |
| 409 | idempotency_conflict | 同键请求语义不同,或旧 run 缺少可核验的请求指纹;不重新执行 |
| 503 | run_replay_lookup_unavailable | 无法安全确认该键是否已有运行;稍后用同键重试 |
| 404 | parent_run_not_found | parentRunId 指向的运行不存在 |
| 404 | document_versioning_write_disabled | 修订写功能未启用;可按上述路径使用旧版 deployment 发布接口 |
| 400 | REVISION_REQUIRED | 修订写功能已启用,创建 deployment 时缺少 revision_id |
统一模型调用
申请已有 model-gateway:invoke 即可发现和调用后台已发布、工作流可用的模型。完整发现入口为 GET /api/model-gateway/v1/models?task=all;无参目录保持原文本、视觉、转写视图。新增模型和调价不需要逐模型申请权限,计费仍用后台配置。
本次定义升级扩展向量、重排、图片、语音、实时会话及原生协议,会移除旧 token 中的 invoke;应用需以新的 PKCE/state 让用户重新同意。旧 refresh 不会自动恢复它。mobile:full 和 vibe-board:cloud 整包不升级,需使用完整能力的客户端可以另行请求 invoke。旧任务 scope 只兼容对应任务;没有新的 native scope。项目资源权限与项目 ACL 仍独立检查。