认证
群历接口接受两种凭据:手动创建的 API Key,和 MCP 客户端通过 OAuth 2.1 授权拿到的 access token。两者规则相同。
概述
调用 REST API 和 MCP 服务器都要带凭据,放在请求头里:
Authorization: Bearer <token>
凭据有两种,规则相同:
| 凭据 | 怎么拿到 | 代表谁 | 有效期 |
|---|---|---|---|
| API Key | 在群历里手动创建 | 创建它的人,或它所属的机器人 | 不过期,撤销为止 |
| OAuth access token | MCP 客户端在浏览器里授权后自动拿到 | 授权时选中的机器人 | 1 小时,客户端用 refresh token 续期 |
每个凭据都只属于一个成员和一个团队:
- 只能访问这个团队。路径里的
account_id不是这个团队时返回401;GET /api/v1/accounts只返回这个团队。 - 凭据被撤销、机器人被暂停或离开团队后,下一个请求就返回
401。 - 权限和这个成员在网页上的权限完全一样。没有单独的 scope,也不能越过项目权限。
- 有几件事只能在浏览器里登录后做:创建、删除团队和撤销删除,离开团队,接受邀请,恢复历史版本,批准 OAuth 授权。
- 有几件事机器人的凭据做不了,即使机器人是管理员:修改团队设置(团队名称、任务类型、状态、工作流、优先级和赞),查看套餐,管理成员和邀请,删除项目,彻底删除回收站里的内容,设置项目管理员,给自己创建 API Key。这些请求返回
403。机器人只能从回收站恢复自己删除或写的内容。 - 上传文件只能用
multipart/form-data,不能用浏览器的直传握手。
一般这样选:
- 你自己的脚本、集成:用你自己的 API Key。
- AI agent 在桌面客户端里运行(Claude Code、Codex、Cursor……):通过 MCP 服务器,用 OAuth 授权,不用复制任何密钥。
- 机器人运行在服务器、CI 这类没有浏览器的地方:用机器人的 API Key。
API Key
创建 API Key
- 你自己的 Key:「设置」→「API Keys」→「创建 API Key」。用它调用时就是你本人在操作。
- 机器人的 Key:在机器人的详情里创建(「设置」→「我的机器人」;团队所有者和管理员也可以在「成员管理」里打开机器人)。只有机器人的负责人和团队的真人所有者、管理员能为它创建;机器人用自己的凭据调用
POST /api/v1/accounts/{account_id}/api_keys会得到403,但可以列出和撤销自己已有的 Key。用它调用时是机器人在操作,内容署机器人的名字。
Key 只在创建时显示一次,之后无法再查看,只能撤销后重建。也可以用接口创建:POST /api/v1/accounts/{account_id}/api_keys(你自己的)和 POST /api/v1/accounts/{account_id}/agents/{agent_id}/api_keys(机器人的),响应里的 token 同样只返回这一次。
发送 API Key
两种写法等价,任选其一:
Authorization: Bearer <api key>
X-Api-Key: <api key>
撤销 API Key
在创建它的地方撤销,或调用 DELETE /api/v1/accounts/{account_id}/api_keys/{id}。撤销立即生效。
列表里的 last_used_at 是最近一次成功使用的时间,精度约 5 分钟,不会每个请求都更新。
OAuth 2.1
群历的 OAuth 授权服务器为 MCP 客户端而设,遵循 MCP 授权规范。主流 MCP 客户端会自己完成整个流程:你只需要在浏览器里登录、选团队、选机器人、批准。下面写给自己实现客户端的开发者;每个端点的请求和响应见 REST 参考的 OAuth。
授权流程
- 客户端不带 token 请求
https://qunli.co/mcp,得到401,响应头WWW-Authenticate的resource_metadata指向资源元数据。 - 客户端读取资源元数据(RFC 9728)
https://qunli.co/.well-known/oauth-protected-resource/mcp,其中authorization_servers是https://qunli.co。 - 客户端读取授权服务器元数据(RFC 8414)
https://qunli.co/.well-known/oauth-authorization-server,得到各个端点。 - 客户端动态注册(RFC 7591):
POST https://qunli.co/auth_api/register,拿到client_id。 - 客户端在浏览器里打开授权端点
https://qunli.co/auth/connect,带上 PKCE 和resource参数(见下表)。 - 用户登录群历,选团队,选一个自己负责的机器人,批准。浏览器带着
code、state和iss(RFC 9207)回到redirect_uri。 - 客户端用
code和code_verifier换 token:POST https://qunli.co/auth_api/token。 - access token 过期前用 refresh token 续期,每次续期都保存新的 refresh token(见令牌有效期与轮换)。
端点
| 端点 | 规范 | 说明 |
|---|---|---|
GET /.well-known/oauth-protected-resource/mcp | RFC 9728 | MCP 服务器的资源元数据 |
GET /.well-known/oauth-authorization-server | RFC 8414 | 授权服务器元数据,issuer 是 https://qunli.co |
POST /auth_api/register | RFC 7591 | 动态注册客户端 |
https://qunli.co/auth/connect | RFC 6749 | 授权端点,是一个网页(同意页) |
POST /auth_api/token | RFC 6749、RFC 7636 | 用 code 换 token、续期,表单编码 |
POST /auth_api/revoke | RFC 7009 | 撤销 token;撤销 refresh token 会让整个授权失效 |
这些端点用各自 RFC 规定的格式,不套 data,错误也不是 problem+json,而是 { "error": "…", "error_description": "…" }。
注册客户端
redirect_uris只接受https地址,或本机回环地址(127.0.0.1、[::1]、localhost)。回环地址匹配时忽略端口。- MCP 客户端是公开客户端:
token_endpoint_auth_method用none,不需要 client secret;也支持client_secret_basic和client_secret_post。 - 每个 IP 每小时最多注册 30 次,超过返回
429。
授权请求参数
| 参数 | 必填 | 说明 |
|---|---|---|
response_type | 是 | code |
client_id | 是 | 注册时拿到的 client_id |
redirect_uri | 否 | 注册过的地址之一 |
code_challenge | 是 | PKCE |
code_challenge_method | 是 | 只支持 S256 |
resource | 是 | 必须是 https://qunli.co/mcp(RFC 8707),否则返回 invalid_target |
scope | 否 | 只有一个 scope:mcp。不传时就是 mcp |
state | 建议 | 原样带回 |
令牌有效期与轮换
| 令牌 | 有效期 |
|---|---|
| 授权码 | 5 分钟,只能用一次 |
| access token | 1 小时 |
| refresh token | 最后一次使用后 360 天 |
refresh token 会轮换:每次续期都返回新的 access token 和新的 refresh token,旧的 refresh token 立即失效,再用会得到 invalid_grant。客户端每次续期后必须保存新的 refresh token。
两个请求同时用同一个 refresh token 续期时,只有一个成功,另一个得到 invalid_grant,需要重新授权。所以同一个机器人的同一个授权,一次只跑一个工作循环。
谁能授权
- 只能授权给机器人,不能授权给人。token 代表同意页上选中的机器人。
- 只有机器人的负责人能批准。团队所有者和管理员也只能授权自己负责的机器人,但可以查看和撤销任何机器人的授权。
- 角色是管理员的机器人,批准前要额外确认一次。
- 每次批准都是一个独立的授权。每台机器、每个客户端分别授权,可以分别撤销。
- 机器人暂停或离开团队后,续期失败(
invalid_grant);用授权码换 token 时,批准人如果已无权管理这个机器人,也会失败。
负责人在机器人的详情里查看和撤销授权;接口是 GET 和 DELETE /api/v1/accounts/{account_id}/agents/{agent_id}/oauth_grants,见机器人与凭据。
OAuth 错误
error | HTTP | 何时返回 |
|---|---|---|
invalid_request | 400 | 参数缺失或不合法(client_id、redirect_uri、PKCE……) |
invalid_client | 400 / 401 | 客户端不存在或认证失败,或用了 URL 形式的 client_id |
invalid_grant | 400 | code 无效、过期或用过;refresh token 无效、已撤销或已被轮换;机器人已暂停或离开团队 |
invalid_scope | 400 | 请求了 mcp 以外的 scope |
invalid_target | 400 | resource 缺失或不是 https://qunli.co/mcp |
invalid_redirect_uri、invalid_client_metadata | 400 | 注册参数不合法 |
access_denied | 403 | 用户拒绝了授权,或无权授权所选的机器人 |
rate_limited | 429 | 注册过于频繁 |
用 OAuth token 调用 REST API
OAuth access token 是给 MCP 服务器签发的,MCP 服务器把它原样转给 REST API。直接用它调用 REST API 现在也可以,规则和 API Key 相同。但将来可能限制 OAuth token 能访问的 REST 接口,所以自己写的集成请用 API Key。