代表用户执行操作
源站目前处于早期 beta 版阶段,后续可能会有变动。
源站 App 使用安装用户 token 代表其所安装命名空间中的成员执行操作。每个请求的权限都不能超出安装和用户各自的权限范围。
使用源站 API 的 base URL 和错误模型。使用应用 JWT 签发 token。
工作原理
- 工作区管理员为你的应用安装批准
namespace:user_tokens:write作用域。 - (可选) 确认用户的 Cherri Code 身份。源站会返回一份签名回执,其中包含该用户的
user_…ID。 - 签名生成一个应用 JWT,并为该用户的 ID 或电子邮件签发安装用户 token。
- 在
expiresAt之前使用安装用户 token 调用 REST API 或进行 Git over HTTPS 操作,到期后再签发一个新的 token。
请求作用域
在安装 URL 的 scope 参数中添加 namespace:user_tokens:write。如果是已有的安装,还需同时发送 include_granted_scopes=true,这样管理员只需批准新增的作用域。
/codebase/apps/install ?client_id=APP_ID &scope=namespace:user_tokens:write%20repository:pull_requests:write &redirect_uri=REGISTERED_CALLBACK &state=RANDOM_ANTI_FORGERY_VALUE &include_granted_scopes=true该作用域允许此安装为其命名空间中的任意活跃成员签发 token。你无法将其加入 token 的 scopes 中。管理员批准的其他作用域仍会限制每个 token 的权限。
何时确认用户
用户确认并非必需:管理员批准 namespace:user_tokens:write 后,该权限即适用于命名空间中的所有成员。
通过用户确认,可以将用户在你产品中的账户关联到其 Cherri Code 账户,也可以验证用户身份,而不必仅凭其输入的电子邮件地址判断。确认回执可证明已登录用户在确认时的 user_… ID、电子邮件地址及命名空间成员身份。
确认回执只能证明身份,不授予任何权限。创建安装用户 token 时,既不接受也不需要确认回执。
用户确认
将用户引导至源站
在用户的浏览器中打开此 URL:
/codebase/apps/user-confirmation ?installation_id=INSTALLATION_ID &redirect_uri=REGISTERED_CALLBACK &state=RANDOM_ANTI_FORGERY_VALUE| 参数 | 必填 | 描述 |
|---|---|---|
installation_id | 是 | 你的应用在该用户命名空间中处于启用状态的安装对应的 i_… ID。 |
redirect_uri | 是 | 回调 URI。必须与该应用的 installationRedirectUris 中的某一项完全匹配,该列表是安装流程使用的允许列表。 |
state | 强烈建议 | 随机防伪值,会作为确认回执中的 state 认领原样返回。 |
每个参数最多只能发送一次。缺少必填参数或包含重复参数时,登录后将报错。
用户看到的内容
未登录的用户会先登录 Cherri Code,再返回带有原参数的同一链接。源站会在登录后验证参数,因此即使链接无效,用户也会先进入登录流程,之后才看到错误提示。
源站会显示应用的名称、图标和描述,以及本次安装所在的命名空间。页面还会列出应用将收到的信息:
- Cherri Code 用户 ID (
user_…) - 电子邮件
- 源站命名空间的 slug 和 ID
页面会说明,确认后将共享用户身份和当前命名空间的成员身份,但不会授予代码仓库访问权限。用户可以选择确认或取消。
只有所属团队的活跃成员,或个人命名空间的所有者,才能确认。
回调
确认后,源站会重定向到你的回调地址:
https://app.example.com/origin/confirm?confirmation_receipt=RECEIPT_JWT&state=RANDOM_ANTI_FORGERY_VALUE读取确认回执中的用户认领前,请先验证回执。仅当确认 URL 提供了非空的 state 值时,回调才会包含 state;请以已签名的 state 认领为准,而非查询参数。
用户取消或确认失败时,不会触发回调或重定向。应将未收到回调视为 "未确认",并让用户重新开始。
确认回执
confirmation_receipt 是由源站签名的紧凑型 JWT,所用密钥与安装回执相同。
JOSE 头部:
{ "alg": "EdDSA", "kid": "origin-key-id", "typ": "origin-user-confirmation-receipt+jwt"}认领:
{ "iss": "https://api.cursor.com/v1/origin", "aud": "app_01...", "sub": "user_01...", "installation_id": "i_01...", "namespace_id": "ns_01...", "email": "[email protected]", "iat": 1786465200, "exp": 1786465500, "jti": "RECEIPT_UUID", "state": "ORIGINAL_VALUE"}aud是你的 app ID;sub是已确认用户的user_…ID,签发时用作userId。installation_id和namespace_id标识成员身份得到确认的安装和命名空间。email是用户确认时所用账户的电子邮件。- 回执在签发五分钟后过期。每个回执的
jti都是唯一的。 - 仅当确认 URL 提供非空值时,回执中才会包含
state。
在信任回调之前,请先验证回执:
- 根据
kid请求头,从 JWKS 中解析签名密钥。 - 要求
alg为EdDSA,typ为origin-user-confirmation-receipt+jwt,以区分确认回执、安装回执和访问令牌。 - 验证签名、
iss、aud和exp。 - 检查
installation_id和已签名的state是否与你发送的值一致。
任一检查未通过时,拒绝该回调。
确认错误
发生失败时,页面会停留在 Cherri Code 上,不会调用你的回调函数。
| 错误 | 原因 |
|---|---|
| 链接无效 | installation_id 或 redirect_uri 缺失或为空,或有参数重复。 |
| 未授权 | 该安装不存在或未启用、redirect_uri 未在该应用中注册,或用户不是该安装所属命名空间的成员。页面不会指明具体原因。 |
| 暂时不可用 | 确认后,源站未能对回执进行签名。用户可以重试。 |
签发安装用户 token
使用 应用 JWT 调用 创建安装用户 token,即 POST /v1/origin/app/installations/{installationId}/user_access_tokens。通过 userId 或 userEmail 指定用户,且只能提供其中之一。
curl --request POST \ --url 'https://api.cursor.com/v1/origin/app/installations/INSTALLATION_ID/user_access_tokens' \ --header 'Authorization: Bearer APP_JWT' \ --header 'Content-Type: application/json' \ --data '{ "userId": "user_01...", "scopes": [ "repository:pull_requests:write" ], "repositoryIds": [ "repo_01..." ]}'{ "token": "YOUR_INSTALLATION_USER_TOKEN", "expiresAt": "2026-01-01T00:15:00Z"}| 字段 | 描述 |
|---|---|
userId | 用户的 user_… ID,来自确认回执的 sub 或 actor 负载。 |
userEmail | 用户的账户电子邮件。必须与该安装所属命名空间中的一名活跃成员唯一匹配。 |
scopes | 可选限制。值不得重复,且必须属于该安装已批准的作用域。namespace:user_tokens:write 以及以 app: 或 installation: 为前缀的作用域不可委派。为空或省略时,使用当前权限。 |
repositoryIds | 可选限制,最多可包含 50 个不重复且该安装可访问的代码仓库 ID。为空或省略时,使用当前权限。 |
用户必须拥有活跃的 Cherri Code 账户,并符合命名空间成员资格规则。未知用户、非成员,以及匹配到多名成员的电子邮件,均会返回相同的 403。
同时设置 scopes 和 repositoryIds 时,只有该安装和该用户在列出的每个代码仓库上都拥有所请求的全部作用域,才能成功签发。限制较少时,则会在每次请求时检查权限。
有效期
expiresAt 最晚为签发后 15 分钟,且不会晚于应用 JWT 的 exp,与安装访问令牌相同。不提供刷新令牌:到期后,请使用新的应用 JWT 重新签发令牌。每次签发会占用应用 JWT 速率限制中的 1 点额度。
使用 token
请将安装用户 token 视为不透明值:不要检查或解析其内容。将 token 作为 Bearer 凭据发送给 REST API;或在通过 Git over HTTPS 访问时,以 x-access-token 为用户名,将 token 作为密码使用:
Authorization: Bearer YOUR_INSTALLATION_USER_TOKEN每个请求都必须符合安装的已批准作用域和代码仓库选择、用户的源站授权,以及 token 的限额。否则,请求就会返回 403;若该 resource 不可见,则返回 404。
Actor 字段用于标明用户,并可包含 performedVia.app,其中包含你的应用的 id 以及可选的 displayName。归属信息仅适用于该字段所描述的操作:在评论的作者字段中,它标识的是创建该评论的应用,而非之后编辑或删除该评论的应用。对于用户直接执行的操作,不会返回 performedVia;当委托数据不可用时,也可能不返回该字段。
签发错误
| HTTP 状态码 | 原因 |
|---|---|
400 | 请求未在 userId 和 userEmail 中恰好设置一项,使用了无效的 user_… ID 或电子邮件地址,包含重复、格式错误或不可委派的作用域,或者包含重复的代码仓库 ID 或超过 50 个代码仓库 ID。 |
401 | 应用 JWT 无效或已过期,或者该安装不存在、属于其他应用或已被暂停。 |
403 | 该安装缺少 namespace:user_tokens:write 授权;请求的限额超出该安装的授权范围;该用户不符合条件;或者在同时指定两种限额的请求中,包含该安装或用户缺少的某项权限。 |
429 | 应用 JWT 的速率限制已用尽。请参阅超出限制。 |
503 | 源站无法查找该用户或签发 token。请采用退避策略重试。 |
吊销
无法吊销单个 token。以下更改会影响 token 的访问权限:
- 卸载或删除应用后,其用户 token 会在
expiresAt之前失效,请求将返回401。 - 关闭用户的 Cherri Code 账户后,该用户的 token 会失效,请求将返回
401。 - 移除
namespace:user_tokens:write或暂停该安装后,将无法再签发新 token。已签发的 token 会在expiresAt时过期。 - 安装或用户的授权发生更改后,最迟在
expiresAt时生效。
安全注意事项
- 仅在需要时签发 token,并只赋予所需的最小
scopes和repositoryIds。像保护密码一样保护 token;不要存储,也不要写入日志。 - 关联账户时,以
sub而非email为依据:用户的user_…ID 不会变,但电子邮件地址可能会变。 - 使用
userEmail签发 token 前,先验证电子邮件地址。输入的地址可能属于另一位成员。 - 每份回执只能使用一次。记录其
jti,并在五分钟有效期内拒绝重复使用。 - 回执不是凭据:不要将其作为 Bearer token 发送,也不要写入日志,因为其中包含用户的电子邮件地址。
- 回执反映的是确认时的成员资格。每次签发 token 都会重新检查成员资格,因此即使保存了回执,也无法为已离开的成员签发 token。