身份验证
本页说明人如何登录 OpenBot,以及程序如何调用 API。 一个人在浏览器中登录一次。然后这个人为脚本和服务创建用户令牌。
调用 /v1 下的业务路由有两种方式:
| 方式 | 谁使用 | 发送什么 |
|---|---|---|
| 用户令牌 | 脚本、后端服务、机器人 | Authorization: Bearer <token> |
| Session cookie | 运行在 OpenBot 源(origin)上的浏览器客户端 | __Host-openbot-session cookie |
两种方式在每次调用时都需要权限。见 权限。
登录
OpenBot 不保存密码。它使用 OpenID Connect 提供方。OpenID Connect(OIDC)是一种标准方式,让另一个服务来确认一个人的身份。 提供方有两种:
要开始登录,你的客户端从 OpenBot 源发送这个请求:
curl -X POST https://api.example.com/auth/sign-in \ -H "Origin: https://api.example.com" \ -H "Content-Type: application/json" \ -d '{"email":"ada@example.com","returnTo":"/settings/keys"}'{ "url": "https://id.example.com/authorize?..." }两个字段都是可选的。OpenBot 根据 email 的域名选择提供方。如果该域名有 SSO 连接,url 就指向它。否则指向平台提供方。如果两者都没有,OpenBot 返回 503 和 SignInUnavailable。
把浏览器跳转到这个 url。这个回答还会设置登录状态 cookie。这个人登录后,提供方把浏览器送回 OpenBot。OpenBot 设置 session cookie,然后把浏览器跳转到 returnTo。见 返回路径。
如果登录失败,浏览器会跳转到 /auth/error?error=<code>,并且不会得到 cookie。
Better Auth 路由
OpenBot 使用 Better Auth 处理登录。Better Auth 在 /auth/* 下提供自己的路由,做法和它的 Effect 指南 一样。这些路由不在 API 参考中。Better Auth 文档 描述了它们。
你仍然可以直接使用它们。平台提供方的提供方 ID 是 oidc,回调地址是 /auth/callback/oidc。SSO 连接用自己的 ID 作为提供方 ID,它的回调地址是 /auth/callback/<connectionId>。
curl -X POST https://api.example.com/auth/sign-in/social \ -H "Origin: https://api.example.com" \ -H "Content-Type: application/json" \ -d '{ "provider": "oidc", "callbackURL": "https://api.example.com/settings/keys" }'callbackURL 必须在 OpenBot 源上。如果不在,Better Auth 返回 403。
设置平台提供方
在你的提供方那里,把 OpenBot 注册为一个客户端。重定向 URI 使用 <publicOrigin>/auth/callback/oidc。OpenBot 会请求 openid profile email 这几个 scope(权限范围)。
然后把提供方告诉 OpenBot。在新平台上,设置程序通过 --oidc-issuer、--oidc-client-id 和 --oidc-client-secret 完成这件事。之后,平台管理员用 PATCH /v1/platform/settings 修改它。见 Platform。
| 设置 | 值 |
|---|---|
identityProvider.issuer |
issuer URL,例如 https://id.example.com。必须是 HTTPS,末尾不能有斜杠。 |
identityProvider.clientId |
提供方给出的 client ID。 |
identityProvider.clientSecret |
client secret。如果是公共客户端,就不要填。 |
publicOrigin |
OpenBot 的公开 HTTPS 源,例如 https://api.example.com。 |
没有 client secret 时,OpenBot 作为公共客户端,使用 PKCE 登录。PKCE 是一种检查,用来保护登录代码。 平台也可以完全没有提供方。这时人们只能通过 SSO 连接登录。
开发账户
开发服务器(devenv shell -- pnpm dev)使用一个本地测试账户,不使用提供方。这个账户是 developer@localhost.test,它是平台管理员。
只有开发入口提供这个账户。生产程序从不提供。见 配置。
下面的命令会登录,并把 cookie 保存到文件中:
curl -c cookies.txt -X POST https://localhost:8443/auth/development/sign-in \ -H "Origin: https://localhost:8443" \ -H "Content-Type: application/json" \ -d '{}'读取和结束登录
GET /auth/session 返回已登录的账户和它的组织。它需要 session cookie。
{ "userId": "u_123", "profile": { "name": "Ada", "email": "ada@example.com", "emailVerified": true }, "memberships": [ { "organizationId": "org_8f3a", "name": "Example", "status": "active", "roles": ["member"] } ], "platformAdmin": false, "expiresAt": "2026-11-19T10:00:00.000Z"}| 字段 | 含义 |
|---|---|
memberships |
账户所在的组织,以及它在每个组织中的状态和角色。 |
platformAdmin |
账户是平台管理员时为 true。这时它可以使用 /v1/platform。见 Platform。 |
POST /auth/sign-out 结束登录。这是一个 Better Auth 路由。发送一个 JSON 请求体({})和 Origin 请求头(见下文)。它返回 200。
成员资格
一个平台有很多组织。一个账户可以是其中多个组织的成员。账户登录时,OpenBot 会检查它属于哪里:
- 如果某个组织验证了该账户已验证邮箱的域名,并且允许
joinByDomain,账户就加入这个组织。 - 如果账户是通过 SSO 连接登录的,它就加入该 SSO 连接所属的组织。
- 如果账户仍然没有组织,并且平台允许任何人创建组织,它会得到一个名为 “Personal” 的新组织。它是那里的 Super Administrator(超级管理员)。
- 否则它没有组织。这时组织路由会返回
403和MembershipRequired。
OpenBot 在每个带 session cookie 的请求上也会做这些检查。见 组织。
被暂停的成员使用 cookie 时,会得到 403 和 MembershipRequired。他们的令牌会立即失效,并得到 401 和 AuthenticationRequired。
选择组织
带 session cookie 的请求必须说明它在哪个组织中执行。在 OpenBot-Organization 请求头中发送组织 ID:
curl -b cookies.txt \ -H "OpenBot-Organization: org_8f3a" \ https://api.example.com/v1/sessions- 没有这个请求头时,OpenBot 使用你唯一的活跃组织。
- 如果你有多个活跃组织,又没有发送这个请求头,OpenBot 返回
400和OrganizationRequired。
用户令牌只属于一个组织。它会忽略这个请求头。
Session cookie
登录后,浏览器持有 cookie __Host-openbot-session。它带有 Secure、HttpOnly 和 SameSite=Lax。
- 一次登录有效 30 天。
- 使用满一天后,OpenBot 会续期它。
Origin 规则
浏览器的每个请求都会带上 cookie,即使请求来自其他网站。所以 OpenBot 会检查写操作来自哪里。
使用 cookie 时,每个 POST、PUT、PATCH 和 DELETE 请求都必须发送 Origin 请求头。
这个请求头必须和 平台设置 中的 publicOrigin 完全相同。如果不同,OpenBot 返回 403 和 ForbiddenOrigin。
curl -b cookies.txt \ -H "Origin: https://localhost:8443" \ -H "Content-Type: application/json" \ -d '{"title":"Notes"}' \ https://localhost:8443/v1/sessions使用用户令牌的请求不需要 Origin 请求头。
用户令牌
用户令牌让程序代表你执行操作。令牌能做的事永远不会超过你能做的事。它还可以有自己的策略,从而做得更少。见 权限。
你可以用 session cookie 管理令牌,也可以用带有 tokens.write 权限的令牌管理。没有策略的令牌不能管理令牌。
令牌属于一个组织:也就是创建它的那个请求所在的组织。使用 cookie 时,发送 OpenBot-Organization 请求头来选择组织。见 选择组织。
完整的数据结构见 User tokens 参考。
创建令牌
curl -b cookies.txt \ -H "Origin: https://api.example.com" \ -H "Content-Type: application/json" \ -d '{"name":"CI bot","expiresInDays":90}' \ https://api.example.com/v1/user/tokens| 字段 | 规则 |
|---|---|
name |
必填。去掉首尾空格后,长度为 1 到 80 个字符。 |
expiresInDays |
可选。1 到 365 之间的整数。不填时,令牌一直有效,直到你撤销它。 |
policies |
可选。用来限制令牌的策略。不填时,允许你能做的所有事,但 tokens.read 和 tokens.write 除外。 |
OpenBot 返回 201:
{ "token": { "id": "5f0c2a8e-7d1b-4c3e-9a55-2b6f1e8d4c10", "name": "CI bot", "prefix": "obut_Xr4pQ2aL", "policies": [ { "effect": "allow", "permissionGroups": [ "responses.run", "sessions.read", "sessions.write" ], "resources": ["openbot.org.{org}"] } ], "createdAt": "2026-10-20T09:00:00.000Z", "expiresAt": "2027-01-18T09:00:00.000Z", "lastUsedAt": null }, "secret": "obut_Xr4pQ2aL..."}每个 secret 都以 obut_ 开头,所以泄露的令牌很容易被发现。prefix 是前 13 个字符。用它来区分你的令牌。
列出令牌
curl -b cookies.txt https://api.example.com/v1/user/tokens回答是 { "items": [ ... ] },最早的排在前面。列表中从不包含 secret。
lastUsedAt 最多每分钟更新一次。过期的令牌会留在列表中,直到你撤销它们。
撤销令牌
curl -X DELETE -b cookies.txt \ -H "Origin: https://api.example.com" \ https://api.example.com/v1/user/tokens/5f0c2a8e-7d1b-4c3e-9a55-2b6f1e8d4c10OpenBot 返回 204 并删除这个令牌。令牌会立即失效。
检查令牌
GET /v1/tokens/verify 显示调用者是谁。对于令牌,它还显示令牌本身和它的策略。所有调用者都可以使用它。
{ "caller": { "kind": "user_token", "userId": "u_123", "organizationId": "org_8f3a", "tokenId": "5f0c2a8e-7d1b-4c3e-9a55-2b6f1e8d4c10" }, "token": { "id": "5f0c2a8e-7d1b-4c3e-9a55-2b6f1e8d4c10", "name": "CI bot" }}使用 session cookie 时,caller.kind 是 member,token 是 null。
限制和错误
| 状态码 | 错误 | 何时出现 |
|---|---|---|
400 |
TokenPolicyInvalid |
某个策略指定了你的组织或 openbot.platform 之外的资源。 |
401 |
AuthenticationRequired |
没有有效的 cookie 或令牌。 |
403 |
PermissionDenied |
调用者没有 tokens.read 或 tokens.write。 |
403 |
ForbiddenOrigin |
使用 cookie 写入,但没有完全相同的 Origin 请求头。 |
404 |
TokenNotFound |
你没有这个 ID 的令牌。 |
409 |
TokenLimitReached |
你已经有 25 个令牌。请求体中有 "limit": 25。 |
503 |
TokenStorageUnavailable |
OpenBot 无法连接到它的数据库。 |
一个成员同时最多持有 25 个令牌。过期的令牌也计算在内,所以请撤销旧令牌来腾出空间。
使用令牌
在任何 /v1 路由上,都在 Authorization 请求头中发送令牌:
curl -H "Authorization: Bearer $OPENBOT_TOKEN" \ https://api.example.com/v1/sessions已撤销、已过期或未知的令牌会得到 401 和 AuthenticationRequired。如果 OpenBot 无法检查令牌,它返回 503 和 AuthenticationUnavailable。
你自己的空间
在组织内,每个成员都有自己的 Sessions、Apps 和连接。你的令牌和 cookie 只能看到你自己的内容。
如果你请求另一个成员的 Session,OpenBot 会返回 404,就像它不存在一样。
返回路径
有些流程在一次往返之后,会把浏览器送回你的客户端。你用 returnTo 选择返回的位置。
返回路径必须是同一个源上的路径。它必须以一个 / 开头。它不能指向 /auth/*、/v1/* 或 /development/*,因为这些路径归 OpenBot 所有。默认值是 /。
OpenBot 没有页面,所以你的客户端必须提供这些路径。有两个流程会添加查询参数:
- App 授权。 当 App 登录返回、并且这个人已经登录时,OpenBot 会完成这个流程。浏览器会跳转到返回路径,并带上
?authorization=<flowId>。你的客户端可以用GET /v1/app-authorizations/<flowId>读取结果。 如果这个人没有登录,浏览器会跳转到/?authorization=<flowId>。你的客户端用POST /auth/sign-in让这个人登录(见 登录),并把这个地址作为returnTo。然后它调用POST /v1/app-authorizations/<flowId>/complete来完成流程。 - 开发者测试。 开发者测试授权会返回到
/?developerTest=<testId>。