Koee Open API
Koee Open API 面向管理员授信的独立业务客户端。客户端可以由其他开发团队实现,部署在自己的服务器、容器或其他平台,通过 HTTPS API 使用 Koee 的账号和后续通信能力,为自己的业务服务。客户端不必部署在 Cloudflare Workers。
首版接入方案只定义邮箱验证码注册、登录、当前身份检查和退出。聊天、消息、联系人等能力将在本章节按模块扩展,首版不因此授予这些权限。
发布状态
本章是接入方案和目标接口规范,尚不是可直接上线调用的 Open API。 Koee 已有账号注册、认证及聊天等内部和客户端 API;本章定义的管理员域名准入、独立客户端凭据、受限业务会话,以及 /open-api/v1/ 接口需要实现、验收和单独启用。公开本章不会开启任何客户端权限。实施前请联系 Koee 管理员确认可用版本和测试环境。
koee.life 已通过 Koee 账户服务和内部 Service Binding 调用账户、会话、聊天、消息及联系人 API,是独立业务复用 Koee 能力的现有实例。本规范将这种接入方式整理为普通远程后端也能使用的独立客户端合同;不把 Life 的内部绑定或凭据直接开放给其他客户端。
客户端定位与第三方登录的区别
| 项目 | Koee Open API 独立业务客户端 | 第三方账号登录 |
|---|---|---|
| 目的 | 为自己的业务提供账号入口,逐步接入经批准的 Koee 能力 | 证明用户身份并建立第三方网站自己的账号 |
| 注册和登录位置 | 用户在业务客户端页面输入邮箱及验证码 | 用户在 Koee 认证中心登录并确认应用 |
| 新用户 | 按 Koee 注册规则创建真正的 Koee 账号 | 完成身份授权后由第三方业务处理本站账号 |
| 接入管理 | 管理员配置限定域名、具体客户端、凭据与能力 | 开发者登记应用,经过审核并取得用户授权 |
| 首版认证结果 | 绑定客户端和具体站点的业务访问凭据,仅支持身份检查与退出 | 短期身份 ID Token,不提供聊天权限 |
| 后续能力 | 单独批准聊天等模块后,按当前用户权限调用 | 身份验证本身不授予聊天、联系人等 API 权限 |
这里的“独立客户端”不意味着复制 Koee 的完整官方客户端,也不意味着管理员凭据可以访问任意用户。每次用户操作都必须有真实的用户登录凭据;客户端权限和用户业务权限都通过校验才能执行。
只需身份验证的网站继续使用 第三方账号登录。本章不使用它的应用 ID、ID Token 或 SDK;普通浏览器 SSO 与 Koee App 内自动登录也是独立接入机制。
管理员设置限定域名
允许接入的域名由 Koee 管理员设置,开发人员不能自行添加或扩大。 管理员先维护域名规则,再为各业务登记具体的 HTTPS Origin。只有满足域名规则、已经登记且处于启用状态的客户端才能接入。
当前业务规划使用 *.koee.app 下的官方二级域名。例如管理员允许一级子域后,可以为 https://shop.koee.app、https://content.koee.app 分别登记客户端。*.koee.app 表示允许登记的范围,不能作为请求时的 Origin,也不会自动放行所有子域。
| 域名规则类型 | 管理员配置示例 | 匹配规则 |
|---|---|---|
| 精确主机 | koee.life | 只允许该主机;需管理员单独批准,不能由 koee.app 规则推导 |
| 一级子域 | koee.app,层级为 1 | 只允许 shop.koee.app 这种一级子域;不含根域和多级子域 |
客户端 Origin 必须是规范化的 https://主机名,不含路径、查询、片段、用户名或密码,使用标准 HTTPS 端口。拒绝 IP、localhost、尾随点及通配符 Origin。国际化域名按同一 IDNA 规则规范化后匹配;不能用字符串包含判断域名,也不能让 koee.app.example.com 或 fakekoee.app 通过。
管理员可以调整允许范围、暂停一个客户端、删除一个具体 Origin、缩减能力或轮换密钥。规则和客户端配置均有版本;安全相关修改必须递增版本,使旧认证事务和业务凭据失效。删除域名后,后续身份检查和业务调用必须拒绝,不能只阻止新注册而保留旧会话无限使用。
这是 Open API 专属准入配置,与普通链接的 WebView 域名列表、第三方登录应用的 Origin、官方 App 业务登记分别管理。修改其中一个列表不授予另一个接口的权限。
为每个业务单独登记客户端
每个独立业务、每个环境使用独立客户端配置,不复用官网、聊天 Web 或 Life 的密钥。一个客户端可以有管理员明确批准的多个精确 Origin,但每次事务和业务凭据都绑定其中一个;别名不自动继承访问凭据。
| 配置项 | 责任与用途 |
|---|---|
client_id | 管理员生成的稳定业务客户端标识,例如 koee_content_web |
display_name | 给用户、管理员和审计记录显示的业务名称 |
allowed_origins | 管理员登记的精确 HTTPS Origin 列表,且必须通过当前域名规则 |
client_secret | 独立服务端密钥,经安全渠道交给客户端后端;不进入网页代码或 Git |
capabilities | 首版仅批准 account:login、identity:read、session:revoke |
registration_source | 管理员确定的首次注册来源,例如 content.koee.app;不能由请求方覆盖 |
enabled、revision | 启用状态和配置版本;生产默认禁用,验收后由管理员开启 |
| 会话与配额策略 | 管理员设置的会话有效期上限、验证码与认证调用配额 |
| 业务资料 | 负责人、联系邮箱、隐私政策与用户条款;用于授信和后续维护 |
开发人员向管理员提交业务域名、后端部署位置、负责人、所需能力和测试计划。管理员确认域名及部署控制关系后配置规则和客户端,提供环境地址、客户端 ID、密钥以及适用的 API 版本。业务开发人员只负责部署自己的后端、用户界面及业务权限。
本方案要求增加专属管理配置和维护入口;目前不能假设后台已经存在“Open API 客户端”菜单。管理员操作必须鉴权、审计并按准确配置版本更新,不能由开发者控制台自助授予权限。
架构与用户流程
用户浏览器或业务客户端
│ 邮箱、验证码;本站会话 Cookie
▼
业务自己的后端
│ HTTPS;独立客户端密钥;服务端保存的业务访问凭据
▼
Koee Open API 网关
│ 域名与客户端准入;能力检查;验证码及账号规则
▼
Koee 账号服务
└ 已有用户登录;新用户注册;首次来源;受限会话
- 用户打开管理员批准的业务域名,业务后端创建属于当前浏览器的登录事务。
- 用户在业务页面输入邮箱。业务后端调用验证码发送接口,保存返回的事务凭证,页面只得到发送结果与倒计时数据。
- 用户输入验证码;业务后端提交同一事务的验证请求。Koee 检查验证码及注册规则,登录已有账号,或按允许的条件创建新账号。
- Koee 返回该客户端专属的受限访问凭据。业务后端绑定真实
user_sub、轮换本站会话标识,在自己的域名设置登录 Cookie。 - 页面通过本站会话调用业务后端。后端使用受限凭据检查 Koee 身份,再执行本站的内容、会员或交易权限判断。
邮箱登录同时处理注册与登录,不需要业务另建一套账号密码。用户注册前应看到 Koee 条款与隐私政策,以及该业务自身的条款与隐私政策。已有账号直接使用原账号;业务账号可以用稳定 user_sub 映射本地记录。
域名准入不会绕过 Koee 的邀请码、账号封禁、删除后注册冷却、认证方式限制或风控。如果当前环境要求邀请码,新用户仍要提供有效邀请码;客户端不能自行关闭该要求。
接口基础合同
以下为待实现的 v1 合同,示例地址目前不能视为已开放。
| 环境 | Open API 地址 | 使用要求 |
|---|---|---|
| Koee 生产 | https://ims.koee.app/open-api/v1 | 管理员单独批准并启用;使用生产客户端及允许域名 |
| Buko 测试 | https://ims.buko.app/open-api/v1 | 实现后使用独立测试客户端、测试密钥和测试域名;不得连接 Koee 生产 |
Buko 是完整资源测试环境。表中的 Buko 合同也是待实现方案,不代表已经存在该网关;不得通过移除其他功能的 Koee-only gate 来获得测试通路。
所有网关请求只由业务后端发起。通用请求头为:
Content-Type: application/json
X-Koee-Client-Id: koee_content_web
X-Koee-Client-Secret: CLIENT_SECRET_FROM_ADMIN
X-Koee-Site-Origin: https://content.koee.app
这些请求头是本章拟定的新合同,不是现有公开 /auth/* 接口已支持的业务认证机制。X-Koee-Site-Origin 从后端固定配置读取,不接受浏览器任意传入;网关用客户端凭据和管理员登记共同校验它。域名字符串或 Origin 请求头本身不能证明请求者身份。
网关拒绝带浏览器 Origin 的跨站直接调用,不向网页暴露客户端密钥。浏览器只访问本站后端,本站后端检查精确 Origin、CSRF 和会话代次。CORS 不能替代客户端认证。
响应均为 JSON,认证响应使用 Cache-Control: no-store。绝对时间字段为 Koee 服务端生成的 Unix epoch 毫秒安全整数;时长字段明确标注 ms 或 s。服务器以 now_ms >= expires_at_ms 判断过期,网页倒计时只是显示提示。
首版建议:验证码事务最长 5 分钟,重发间隔至少 60 秒,每个事务最多 5 次错误验证;会话默认最长 24 小时,管理员可设置更短期限,v1 硬上限为 7 天。配额按业务、邮箱、事务及可信网络来源共同计算,不能通过增加事务逃避限制。这些是目标合同,正式值以管理员交付的实现版本为准。
发送邮箱验证码
POST /auth/email/request,要求 account:login。
{
"email": "user@example.com",
"browser_transaction_id": "RANDOM_SERVER_GENERATED_BROWSER_TRANSACTION"
}
browser_transaction_id 是业务后端生成的至少 256 位随机事务标识,绑定当前浏览器的 HttpOnly 事务 Cookie。不能把邮箱、可猜测用户 ID 或前端传入的字符串直接作为它。
成功响应:
{
"ok": true,
"request_id": "oar_REQUEST_ID",
"request_secret": "RANDOM_REQUEST_SECRET",
"server_time_ms": 1790870400000,
"expires_at_ms": 1790870700000,
"resend_after_ms": 60000
}
时间值只是示例。request_secret、完整事务数据只留在后端;页面可得到倒计时数据和通用发送结果,不得到这些凭证。发送响应不提供 user_exists 或公开注册状态,避免批量查询邮箱是否属于 Koee 用户。
验证码用途和记录绑定产品、客户端、具体 Origin、事务和邮箱。一个客户端收到的验证码不能在另一客户端或普通 /auth/email/verify 中消费;实现需为此新增用途或严格的 context 绑定,而不是只在前端做检查。发送失败只取消本次未完成的发送,不清除其他测试人员或用户的状态。
验证并注册或登录
POST /auth/email/verify,要求 account:login。通用头之外,设置唯一的 Idempotency-Key,业务后端保存该值用于同一次验证的短期安全重试。
{
"request_id": "oar_REQUEST_ID",
"request_secret": "RANDOM_REQUEST_SECRET",
"browser_transaction_id": "RANDOM_SERVER_GENERATED_BROWSER_TRANSACTION",
"code": "123456",
"invite_code": "OPTIONAL_INVITE_CODE"
}
邮箱从发送事务读取,不能在验证时换邮箱;invite_code 不需要时可以省略。网关同时核对客户端、Origin、事务、凭证、配置版本、验证码有效期与尝试次数。
成功响应只交给后端:
{
"authenticated": true,
"registered": true,
"user": {
"user_sub": "u_STABLE_KOEE_USER_ID",
"display_name": "User",
"handle": "public_handle"
},
"access_token": "koa_CLIENT_BOUND_OPAQUE_TOKEN",
"session_id": "oas_BUSINESS_SESSION_ID",
"capabilities": ["identity:read", "session:revoke"],
"server_time_ms": 1790870400000,
"expires_at_ms": 1790956800000
}
registered=true 只在本次首次创建 Koee 用户时出现;已有账号为 false。昵称和公开 handle 可为空,客户端不能因缺少可选资料把成功登录误判为失败。首版不返回完整私人资料、IM 主令牌或其他业务的会话。
access_token 为本方案新增的不透明、客户端及 Origin 绑定的受限会话,服务端只存其散列,不能用于现有 /spaces/*、/contacts/* 等普通 IM 接口。它也不是第三方身份 ID Token;未来聊天能力必须经过独立批准和接口验收。
验证码消费、账号创建及首次注册来源、会话签发必须在受保护的事务中一致完成。相同幂等键、相同请求可在最长 60 秒且不超过凭据原有效期的恢复窗口内返回同一结果,不能再注册一次或签发第二个会话。恢复结果需加密暂存;重试仍核对当前域名、客户端版本、账号及会话状态。窗口外或结果无法安全恢复时返回明确错误并重新登录,不能无限自动重试验证码。
新用户缺少邀请码或邀请码无效时保留仍有效的验证码事务,允许补充邀请码后重试;改变请求内容时生成新的幂等键。错误验证码会消耗尝试次数,不自动重发;被封禁、删除或认证方式受限的账号按既有账号规则拒绝。
当前会话与身份检查
POST /sessions/introspect,要求 identity:read。发送通用客户端认证头,以及:
Authorization: Bearer koa_CLIENT_BOUND_OPAQUE_TOKEN
请求体为 {}。同一令牌不能从另一客户端或另一 Origin 使用。有效响应包含 active=true、session_id、最小 user、capabilities、server_time_ms 和 expires_at_ms;无效或已撤销的令牌返回 200 与 {"active":false},不返回历史身份。客户端认证失败仍返回 401 或 403。
网关每次检查域名规则、客户端启用与版本、账号状态、会话撤销及绝对期限。业务后端对每个受保护请求检查有效性,不使用正向身份缓存跳过撤销;网络故障返回暂时不可用,不能降级为继续使用旧身份。一次已通过授权的在途操作或已经显示的数据,无法由之后的撤销追溯收回。
退出当前业务会话
POST /sessions/revoke,要求 session:revoke,使用同样的通用头和 Bearer 业务访问凭据,请求体为 {"reason":"user_logout"},返回 {"ok":true}。
退出可重复执行,只撤销当前客户端的当前业务会话,不默认退出 Koee 官方客户端或其他业务。客户端停用后仍允许使用其未撤销的维护凭据完成会话撤销;其他 API 全部拒绝。密钥完全失效时由管理员执行清理。
业务后端先持久化本地退出标记并清除本站身份与 Cookie,再调用远端撤销;临时失败保留受保护的撤销队列,不能恢复页面的旧登录状态。队列不得在域名恢复后重新授权旧会话。账号封禁、删除和明确的账号级全部会话撤销,应同时使相关 Open API 会话无效;单个官方设备退出不自动等于账号级全部退出。
业务后端实现方法
后端至少提供本站的验证码发送、验证、会话查询、退出四个接口。名称由业务选择,例如 /api/koee/email/request、/api/koee/email/verify、/api/koee/session、/api/koee/logout。这些是业务自己实现的地址,不是 Koee 网关地址。
下面只是网关启用后的服务端请求示例,不能放进浏览器 bundle:
const base = process.env.KOEE_OPEN_API_BASE; // 管理员交付的固定环境地址
const origin = process.env.KOEE_SITE_ORIGIN; // 精确的本站 Origin
async function koeeRequest(path, body, { token, idempotencyKey } = {}) {
const headers = {
'Content-Type': 'application/json',
'X-Koee-Client-Id': process.env.KOEE_CLIENT_ID,
'X-Koee-Client-Secret': process.env.KOEE_CLIENT_SECRET,
'X-Koee-Site-Origin': origin,
};
if (token) headers.Authorization = `Bearer ${token}`;
if (idempotencyKey) headers['Idempotency-Key'] = idempotencyKey;
return fetch(`${base}${path}`, {
method: 'POST', headers, body: JSON.stringify(body),
redirect: 'error', signal: AbortSignal.timeout(10000),
});
}
部署时校验环境地址和所有必填配置,只允许上述四个固定路径,禁止用户指定上游 URL、path、业务 Origin 或客户端凭据。上例只演示 HTTPS 传输,不替代响应 schema 校验、会话存储和安全重试。
后端还必须完成以下处理:
- 用数据库或受保护的会话存储保存登录事务与业务访问凭据;浏览器只持有随机本站会话引用,不保存客户端密钥、请求凭证或 Koee access token。
- 登录成功轮换本站会话 ID。使用 host-only 的
__Host-koee-businessCookie,设置Secure; HttpOnly; Path=/; SameSite=Lax,不设置Domain=.koee.app;Cookie 期限不能超过服务器认证期限。 - 精确检查本站 Origin 与 CSRF。切账号、退出和开始新登录改变会话代次,旧验证码响应或并发回调不能覆盖新账号。
- 在每次保护操作前检查当前会话,使用返回的真实
user_sub做本站映射和业务授权;不得采信网页提交的任意用户 ID。 - 禁止 CDN 或 Service Worker 缓存认证响应。日志不记录验证码、客户端密钥、完整 Cookie、request secret 或访问令牌。
- 对错误码逐项处理;服务端失联不能按“未注册用户”自动创建另一个本地账号,也不能当作允许访问。
注册来源与获客统计
首次通过业务注册成功时,Koee 服务端从已认证的客户端登记中读取 registration_source,与账号创建在同一事务中保存。业务前端不能自行提交来源覆盖它;业务后端也不能冒用其他客户端的来源。
已有用户登录新业务时,保留其原始首次注册来源,不重复计为新增 Koee 用户。业务可以另记“首次进入本站”的事件,但该事件与“首次创建 Koee 账号”分开。客户端 ID、业务 Origin、环境、注册还是登录等归因信息进入可信审计;分析合同必须保留由服务端确认的来源,不把当前调用方声明的旧字段直接当作可信归因。
错误与重试
目标错误响应统一为 {"error":{"code":"origin_not_allowed","message":"This site is not enabled."},"request_id":"TRACE_ID"}。这里的顶层 request_id 是诊断关联 ID,不是验证码事务凭证;不能据此恢复登录。
| HTTP | 错误码示例 | 客户端处理 |
|---|---|---|
| 400 | invalid_request、invite_invalid | 修正输入;不要自动重发验证码 |
| 401 | invalid_client | 检查服务端凭据并联系管理员,不把它显示成用户验证码错误 |
| 403 | origin_not_allowed、client_disabled、capability_denied、account_unavailable、invite_required | 按准入、权限或账号问题处理;需要邀请码时允许补充 |
| 409 | transaction_changed、transaction_consumed、idempotency_conflict、account_reauthentication_required | 不覆盖当前账号;按相应问题重新发起或使用账号支持的认证方式 |
| 410 | request_expired | 丢弃该事务,用户主动重新发起 |
| 422 | code_invalid | 提示用户检查验证码;达到尝试上限后结束事务 |
| 429 | rate_limited、registration_cooldown | 按 Retry-After 秒数等待;不得通过换客户端规避 |
| 503 | open_api_unavailable、temporarily_unavailable | 保留安全的本地状态;只做受限重试,不降级授权 |
这些错误码是新合同,不是现有普通 /auth/* 错误码的逐字承诺。实现需提供明确适配。成功验证码兑换仅按前述幂等恢复规则重试;发送验证码不能因为网络超时无限重试。
Open API 应有独立的协议兼容性策略,不能让业务客户端冒报官方 App 的 X-App-Build 来通过现有版本准入。若未来需要客户端版本字段,由管理员交付真实版本合同;内部 Service Binding 的豁免也不能靠公网请求头获得。
上线验收
管理员启用生产客户端前,业务团队与 Koee 共同完成独立测试。至少覆盖:限定域名通过与伪造后缀拒绝、未登记客户端拒绝、密钥错误与轮换、跨客户端和跨 Origin 使用凭据拒绝、新用户注册、老用户登录、邀请码、首次来源不被覆盖、验证码过期和重放、幂等结果恢复、切账号并发、本站退出、账号级撤销、业务禁用、网络故障和配额。
验证令牌和认证响应不会进入网页存储、日志、CDN 或另一业务 Cookie;登录和退出必须在实际部署的业务页面上验证。测试使用 Buko 独立账号、客户端和数据;正式 Koee 登记与启用属于生产发布步骤,不能用文档发布代替。
后续能力扩展
本章按“管理员域名准入 → 独立客户端 → 当前用户 → 能力许可 → 具体资源权限”的顺序扩展。后续可增加会话、聊天消息、联系人、文件等模块;每个模块必须单独提供接口合同、能力清单、配额、撤销行为、错误及测试。
聊天接口必须继续检查当前用户的空间成员关系、私有空间可见性、发言限制和频道角色;联系人接口继续检查关系、申请和拉黑规则。管理员授予客户端能力不会授予任意用户身份,也不保证用户能操作任何会话。
首版注册/登录凭据不自动扩展能力;新增权限需管理员批准、更新配置版本并按新的权限合同重新认证。不得以客户端身份新增能力为理由,把用户已经拥有的全部聊天历史自动暴露给业务客户端。
现有普通 /auth/email/request、/auth/email/verify 可作为账号核心实现参考,但没有本章所述的完整客户端与域名准入,且成功结果为普通 Koee session。实现 Open API 时复用验证码和账号领域逻辑,直接签发受限凭据;不能先签发完整 IM token,再把它藏在通用代理后面称作权限隔离。聊天及其他接口在此首版只记录扩展方向,不作为已开放模块。