跳转到内容

认证与权限

Chorus 将每个请求认证为统一的 AuthContext,再根据细粒度的权限集合管控智能体能做什么。本页 说明各种认证方式、智能体 API 密钥的约定,以及同时驱动 MCP 工具可见性与 REST 访问的权限模型。

可引用的稳定锚点:#统一的-authcontext、 #解析级联、#agent-api-key、 #权限模型、#角色预设、 #自定义权限与有效集合。

每个已认证的请求都会解析为三种上下文类型之一。多租户通过 companyUuid 强制隔离:所有数据访问都 以它为范围,只有 Super Admin 可以跨工作区操作。

上下文类型type关键字段由谁产生
UserusercompanyUuid、actorUuid、email、nameOIDC、本地账号、Default Auth
AgentagentcompanyUuid、actorUuid、roles[](预设选择器)、permissions[](有效集合)、agentName、ownerUuidAPI 密钥
Super Adminsuper_adminemail(无 companyUuid)Super Admin 会话

智能体的授权完全来自它的 permissions[],即扁平的有效权限集合。roles[] 字段只是预设选择器, 并不是授权来源。

单一入口按优先级依次尝试每种方式,第一个成功即返回:

1. Authorization: Bearer <token>
├─ cho_… 前缀 → API key 校验 → Agent 上下文
├─ RS*/ES* JWT → OIDC token 校验 → User 上下文
└─ HS256 JWT → Chorus JWT 校验 → User 上下文
2. 会话 Cookie
└─ user_session → User
3. OIDC Cookie(用于 SSE / EventSource,无 Authorization 头)
└─ oidc_access_token cookie → User 上下文
4. 无匹配 → 未认证

步骤 1 中的 token 按形态分类:cho_ 前缀即 API 密钥;否则视为三段式 JWT:头部算法为非对称 (RS*/ES*)时为 OIDC token,为 HS256 时为 Chorus 自签名会话 token。

NEXTAUTH_SECRET 用于签名本地账号和 Default Auth 的 user_session 以及 Super Admin 的 admin_session JWT。 Super Admin 路由会单独校验 admin_session,与普通用户认证相互独立。 OIDC token 用身份提供方的密钥校验,智能体 API 密钥则与数据库中保存的哈希比对。 轮换 NEXTAUTH_SECRET 只会使 Chorus 自签名会话失效,不会使 API 密钥或 OIDC token 失效。

npm 启动器默认将生成的密钥保存在 ~/.chorus-data/.secret,Docker 则使用 /app/data/.secret。 两者都会忽略环境变量中的已知公开占位值;若已保存的密钥是公开占位值,则拒绝启动。 直接启动应用时需自行提供密钥。0.18.1 升级、持久化与多副本设置参见 Docker 会话密钥。

智能体在每个 MCP 和 REST 请求上用 bearer API 密钥认证:

Authorization: Bearer cho_<random>

约定如下:

  • cho_ 前缀。 每个密钥以 cho_ 开头,后接 base64url 编码的随机字节。解析级联正是靠这个 前缀区分密钥与 JWT。
  • 仅展示一次。 原始密钥只在创建时返回一次。请当场复制;之后无法再取回。
  • 以 SHA-256 哈希形式存储。 数据库只存密钥的 SHA-256 哈希,从不保存原始值,因此即便数据库 被导出也不会泄露可用凭据。
  • 恒定时间比较。 校验时对提交的 token 做哈希,再用 constant-time 比较两个哈希值,因此无论前 缀匹配多少位,失败耗时都相同。
  • 轮换、吊销、过期。 密钥可被吊销,也可设置可选的过期时间;被吊销或过期的密钥校验失败。轮换 时创建一个替代密钥并吊销旧密钥。权限挂在智能体上而非密钥上,因此轮换密钥不会改变智能体的 权限;要更改权限,请编辑智能体。

创建、编辑、轮换、吊销密钥属于设置中的操作,而非 API 调用。凭据创建步骤见 为智能体创建访问权限,编辑与吊销见 管理智能体与 API 密钥,将密钥接入智能体见 连接智能体运行环境。

以下方式面向人类用户和平台管理员。这里只做概要说明,具体配置见运维指南。

面向人类用户的企业 SSO,由 Super Admin 按工作区配置(issuer、client ID、启用开关)。登录使用带 PKCE 的授权码流程,无需 client secret。身份提供方回调后,Chorus 按 (companyUuid, oidcSub) 查找或创建用户,并设置若干 HTTP-only cookie:

Cookie用途
oidc_access_token用于 API 调用的访问 token(约 1 小时)
oidc_refresh_token用于静默续期的刷新 token(约 30 天)
oidc_client_idtoken 刷新时使用的 client ID
oidc_issuer用于 JWKS 发现的 issuer

访问 token 依据身份提供方的 JWKS(带缓存)校验;Chorus 会在请求到达应用前,透明地续期 即将过期的访问 token。

本地账号按工作区管理,与 Default Auth 独立。超级管理员创建仅使用本地认证的工作区并邀请初始工作区管理员;该本地管理员激活后,在侧边栏中设置下方的工作区用户管理用户。普通用户、OIDC 或 Default Auth 用户及智能体管理员权限位都不会获得这一角色。本地认证与 OIDC 不能在同一工作区同时启用,也不能通过编辑工作区来切换模式。

统一登录先根据邮箱或本地用户名识别登录方式,选择工作区或身份后才要求密码。用户名和邮箱会按不区分大小写的方式规范化,仅在工作区内唯一。不提供公开注册或自助重置。管理员私下分享一次性邀请、重置链接;24 小时后过期,不会自动发送邮件。密码至少 8 个字符、最多 72 个 UTF-8 字节,以 bcrypt 哈希存储。接受链接会设置密码,但不会创建会话。

本地登录成功后签发有效期为一小时的 user_session,没有刷新令牌流程。请求会检查账号活跃状态和会话版本。账号编辑、重新签发凭据链接及接受密码设置都会使此前的会话、链接失效。禁用或移除所有者后,其智能体 API 密钥无法认证;仅重置密码会保留密钥。复用被移除账号的用户名或邮箱只会创建新身份,不继承历史、归属、权限或凭据。最后一位有效工作区管理员不能被移除、禁用或降级。

具体操作见本地用户管理,邀请、显示名称和头像见账号设置。个人资料由已认证用户自行修改,不能通过智能体或平台管理员修改。名称与生成式头像分别显式保存;修改显示名称不会改变登录凭据。

身份识别、本地密码登录、本地邀请及重置接受均受限流保护。429 响应包含 Retry-After,请等待后再试,不要重复提交凭据。Redis 在副本间共享计数;未配置 Redis 或发生故障时,退回单实例内存限流。超出该回退机制的意外错误会记录日志并放行请求。配置见部署运维,它与 SSE 连接限制不同。

通过环境变量定义的单个邮箱、密码账号,适用于无需 OIDC 提供方的个人、开发或演示使用。同时设置以下变量即启用,并非只能在开发模式使用:

Terminal window
DEFAULT_USER="you@example.com"
DEFAULT_PASSWORD="choose-a-strong-password"

登录时自动创建工作区和用户,并签发有效期为 365 天的 user_session,没有刷新令牌流程,过期后须重新登录。该账号不提供本地工作区管理员的用户管理权限或超级管理员权限。共享工作区请使用受管理的本地账号或 OIDC,而不是共享环境密码。即使配置了 Default Auth,登录界面仍先识别身份。

负责跨工作区的平台级管理(工作区管理、按工作区配置 OIDC)。通过环境变量配置一个邮箱和一个 bcrypt 密码哈希:

Terminal window
SUPER_ADMIN_EMAIL="admin@example.com"
SUPER_ADMIN_PASSWORD_HASH="$2b$10$…" # bcrypt 哈希

登录成功后设置 admin_session cookie。Super Admin 上下文没有 companyUuid,因此不受工作区 范围限制,是唯一能跨租户读取数据的上下文。

智能体授权由一组权限位构成。智能体持有的有效集合在每一层都决定着它能做什么。

权限写作 {resource}:{action}。五个资源乘以三个动作,共 15 个可能的位:

readwriteadmin
idea查看想法创建 / 认领 / 释放 / 更新想法;运行细化轮次关闭 / 删除想法
proposal查看提案和草稿创建 / 提交 / 拒绝 / 撤回;管理草稿;批量创建任务;管理任务 DAG;分配任务批准 / 关闭提案
document查看文档创建 / 更新文档删除文档
task查看任务认领 / 释放 / 提交 / 上报;自检验收标准验收 / 重开 / 关闭 / 删除任务;标记验收标准
project查看项目与项目组创建 / 更新 / 删除项目与项目组;移动项目保留位(由 admin_agent 授予,尚未管控)

这些动作通常一起授予,但彼此不会相互隐含:授予 task:admin 并不隐含 task:read 或 task:write,每个位都要显式授予。

三个具名预设展开为 15 个位的固定子集。预设只是快捷方式,不是独立的授权机制。

预设数量展开的权限
developer_agent6*:read + task:write
pm_agent10*:read + idea:write + proposal:write + document:write + task:write + project:write
admin_agent15全部位(*:read + *:write + *:admin)

展开后,各预设为:

developer_agent (6):
idea:read proposal:read document:read project:read task:read
task:write
pm_agent (10):
idea:read idea:write
proposal:read proposal:write
document:read document:write
task:read task:write
project:read project:write
admin_agent (15):
idea:read idea:write idea:admin
proposal:read proposal:write proposal:admin
document:read document:write document:admin
task:read task:write task:admin
project:read project:write project:admin

在预设之外,智能体还可携带自定义权限位。有效集合是展开后的预设与自定义位的并集:

effective = expand(preset) ∪ custom

顺序无关,它是纯粹的集合并集。常见形态:

  • 只读审计员:无预设,仅自定义 *:read,可查看一切但不能改动。
  • 自验收开发者:developer_agent + task:admin:无需等待管理员即可验收任务。
  • 带批准权的 PM:pm_agent + proposal:admin:可直接批准提案。

同一个有效集合驱动两个集成面:

  • MCP 工具可见性。 每个受管控的 MCP 工具声明恰好一个所需权限。连接时,只有当工具的所需权限 在有效集合中,它才会注册到该智能体的服务器上,否则这个工具直接不出现在智能体的工具列表里。 公共工具(discover / read / list / search / comment / session,以及 chorus_create_tasks / chorus_update_task)不设管控,对每个智能体都可见。
  • REST 管控。 受管控的 REST 路由会检查所需的 {resource}:{action} 权限位。缺少该位的智能体 会得到 403 Missing permission。人类用户不受这些智能体权限检查 约束(其访问权限通过会话检查),Super Admin 则跳过所有权限检查。