SSO 和域名
SSO(单点登录)让人们使用自己公司的账户提供方登录。 组织可以为它拥有的邮箱域名添加自己的 OpenID Connect 提供方。OpenID Connect(OIDC)是一种标准方式,让另一个服务来确认一个人的身份。
本页说明如何验证域名,如何添加 SSO 连接,以及登录时如何选择提供方。
所有路由都在 /v1/organization 下。读取需要 sso.read。修改需要 sso.write。见 权限。
已验证的域名
邮箱域名是邮箱地址中 @ 后面的部分,例如 example.com。在域名起作用之前,组织必须证明它拥有这个域名。它通过一条 DNS TXT 记录来证明。
添加域名
curl -H "Authorization: Bearer $OPENBOT_TOKEN" \ -H "Content-Type: application/json" \ -d '{"domain":"example.com"}' \ https://api.example.com/v1/organization/domains{ "domain": "example.com", "recordName": "_openbot-verification.example.com", "recordValue": "openbot-verification=4f7d...", "verifiedAt": null, "createdAt": "2026-10-21T09:00:00.000Z"}添加 TXT 记录
在你的 DNS 服务商那里添加一条 TXT 记录。名称使用 recordName,值使用 recordValue。
验证域名
curl -X POST -H "Authorization: Bearer $OPENBOT_TOKEN" \ https://api.example.com/v1/organization/domains/example.com/verifyOpenBot 会查询这条 TXT 记录。记录正确时,回答中会有 verifiedAt 时间。
如果 OpenBot 找不到这条记录,它返回 409 和 DomainNotVerified。DNS 的修改可能需要一些时间生效,所以请稍后再试。
一个域名只能由一个组织验证。如果另一个组织先验证了它,OpenBot 返回 409 和 DomainTaken。
GET /v1/organization/domains 列出所有域名。DELETE /v1/organization/domains/:domain 删除一个域名。如果某个 SSO 连接正在使用这个域名,删除会返回 409 和 DomainInUse。
按域名加入
已验证的域名还决定谁能加入组织。当 组织设置 中的 joinByDomain 为 true 时,拥有该域名下已验证邮箱的人在登录时就会加入组织。他们会得到组织的 defaultRoles。joinByDomain 默认为 true。
SSO 连接
SSO 连接是组织的一个 OpenID Connect 提供方。邮箱属于它的域名的人,通过它登录。
注册客户端
先在你的提供方那里把 OpenBot 注册为客户端。OpenBot 会请求 openid profile email 这几个 scope(权限范围)。
创建连接后,把它的 redirectUri 添加到该客户端允许的重定向 URI 中。
创建连接
curl -H "Authorization: Bearer $OPENBOT_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Example SSO", "issuer": "https://login.example.com", "clientId": "openbot", "clientSecret": "your-client-secret", "domains": ["example.com"], "enforce": true }' \ https://api.example.com/v1/organization/sso_connections| 字段 | 规则 |
|---|---|
name |
必填。1 到 120 个字符。 |
issuer |
必填。提供方的 HTTPS 地址,末尾不能有斜杠。 |
clientId |
必填。提供方给出的 client ID。 |
clientSecret |
可选。如果是公共客户端,就不要填。这时 OpenBot 使用 PKCE,这是一种保护登录代码的检查。 |
domains |
必填。组织的 1 到 50 个已验证域名。其他连接不能使用这些域名。 |
enforce |
必填。见 强制使用 SSO。 |
{ "id": "sso_2b9c...", "name": "Example SSO", "issuer": "https://login.example.com", "clientId": "openbot", "clientSecret": { "set": true, "hint": "…cret" }, "domains": ["example.com"], "enforce": true, "redirectUri": "https://api.example.com/auth/callback/sso_2b9c...", "version": 0, "createdAt": "2026-10-21T09:00:00.000Z", "updatedAt": "2026-10-21T09:00:00.000Z"}redirectUri 是 <publicOrigin>/auth/callback/<connectionId>。请在提供方那里注册它。
client secret 永远不会返回。回答中显示的是 { set, hint }。见 Platform。
修改或删除连接
| 路由 | 作用 |
|---|---|
GET /v1/organization/sso_connections |
列出所有连接。 |
GET /v1/organization/sso_connections/:connectionId |
读取一个连接。 |
PATCH /v1/organization/sso_connections/:connectionId |
修改一个连接。 |
DELETE /v1/organization/sso_connections/:connectionId |
删除一个连接。 |
PATCH 的请求体需要 expectedVersion,也就是你读到的 version。如果在你读取之后有人修改了这个连接,OpenBot 返回 409 和 SsoConnectionConflict。
对于 clientSecret,不填就保留当前的 secret。发送 null 会把它变成公共客户端。
每个实例都会立即使用新的或修改过的连接。如果某个实例漏掉了变更通知,它也会在 30 秒内获取到变更。
强制使用 SSO
当 enforce: true 时,邮箱属于该连接域名的人必须通过它登录。他们不能使用平台提供方。
当 enforce: false 时,他们也可以使用平台提供方登录。
规则
- 一个连接只让邮箱属于它自己域名的人登录。
- 通过某个连接登录的人会加入该连接的组织。即使
joinByDomain为false,也是如此。 - OpenBot 从不关联账户。每个账户只有一个登录提供方。所以,一个人先用平台提供方登录,再用 SSO 连接登录,会得到两个不同的账户。
使用正确的提供方登录
POST /auth/sign-in 开始浏览器登录。它不需要凭据。它会检查 Origin 请求头,和每次使用 cookie 的写操作一样。见 身份验证。
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":"/"}'{ "url": "https://login.example.com/authorize?..." }两个字段都是可选的。OpenBot 这样选择提供方:
- 如果
email的域名有 SSO 连接,url就指向该连接。 - 否则,
url指向平台提供方。 - 如果两者都没有,OpenBot 返回
503和SignInUnavailable。
把浏览器跳转到 url。这个回答还会设置登录状态 cookie,Better Auth 需要它来完成登录。登录后,浏览器会跳转到 returnTo。见 返回路径。
错误
| 状态码 | 错误 | 何时出现 |
|---|---|---|
400 |
SsoConnectionInvalid |
某个值无效,例如域名未验证或已被使用。 |
403 |
PermissionDenied |
调用者没有 sso.read 或 sso.write。 |
404 |
DomainNotFound |
组织没有这个域名。 |
404 |
SsoConnectionNotFound |
组织没有这个 ID 的连接。 |
409 |
DomainNotVerified |
OpenBot 没有找到 TXT 记录。 |
409 |
DomainTaken |
另一个组织先验证了这个域名。 |
409 |
DomainInUse |
某个 SSO 连接仍在使用这个域名。 |
409 |
SsoConnectionConflict |
在你读取之后,有人修改了这个连接。 |
503 |
SsoUnavailable |
OpenBot 无法连接到它的数据库。 |
完整的数据结构见 SSO 参考。