身份验证与作用域
platform API 使用您组织的 key 进行身份验证。它有两种形式 — 同一组织、相同 scopes、不同 runtime:
| Form | Credential | Sent as |
|---|---|---|
| Server (backend) | kld_sk_live_… | Authorization: Bearer … 或 X-Api-Key |
| Publishable (browser) | kld_pk_live_… | 由 SDK 交换为短期 session;绝不会作为 raw bearer 发送 |
Authorization: Bearer kld_sk_live_…
# or
X-Api-Key: kld_sk_live_…
Server keys 是您从 backend 在每个 request 中发送的 bearer。
Publishable keys 用于浏览器:SDK 会在 runtime 将其交换为短期、
绑定 origin 的 session token,因此 publishable key 本身不会成为
page source 中长期存在的 credential。直接将 publishable key 作为
bearer 提交会被拒绝 — 请通过 SDK 使用。server key 不会获得任何 CORS
grant,因此页面永远无法 读取 使用它产生的 response — 但 CORS 无法
阻止 request 离开浏览器,因此一旦 server key 被放入 page
source,它就已经泄露。API 拒绝它时已经太迟。SDK 正是因为这个原因在 mount 时拒绝
kld_sk_… key:请始终将 server key 保留在
server-side。
现有 legacy kld_live_… key 会继续在两种场景中作为 direct bearer 使用。
作用域
key 携带 capability scopes;每个 route family 都需要其中一个:
| Scope | Route family | Used by |
|---|---|---|
ai | /inference-api/b2b/v1/chat/*, /retrieval/* | chat embed |
design | /inference-api/b2b/v1/design/* | editor embed |
maps | designed basemaps | the tile embed |
vendor | (modifier, not a route) | the chat embed, on your own data |
默认情况下,Pro/Enterprise key 会使用 ai、design 和 maps 进行 mint。
Free-plan key 仅限 maps + tile 产品;请参阅
获取 API 密钥 中的正式
plan × scope × product 表。
Effective admission = stored key × current tier。 Runtime session-exchange
会在每次 call 时重新计算 admission,因此 Pro-tier key 降级为 Free 后,
从那一刻起只能 mint tile session — 即使 stored key 中仍然
包含 ai 和 design 限制。rejection subcode 会
区分两种情况:
insufficient_scope— key 从未拥有该 capability。tier_capability_not_allowed— key 曾经拥有,但 current tier 已不再允许。升级 plan 即可恢复。
stored key 中空的 allowed_products 表示所有产品(不是
没有产品)。tier 仍会将该 superset 收窄到 plan 允许的范围。
vendor — 有意请求,并且只在真正需要的地方使用
vendor 不是 route gate。它不决定 request 是否被允许;它决定
AI chat 在回答时是否可以查询您组织上传的 vendor data。
其他所有 scope 回答的是“这个 key 能否调用这个 endpoint”;vendor
回答的是“这个 key 能否代表我们的内部数据进行回答”。
因此它绝不会默认包含 — 请在 mint 时明确请求:
{ "name": "our-site-widget", "scopes": ["ai", "vendor"] }
哪个 key 携带 vendor,本身就是整个安全决策。 chat embed 是
browser widget:它会将 publishable key 交换为短期 session,因此
vendor-enabled key 必然存在于 public page 中。对于愿意展示给每位访客的数据,
例如 property list、营业时间、公开 rate,这是可以接受的。
对于任何不愿公开的信息则不合适。保护 exchange 的 origin
allowlist 是 browser convention,而不是 confidentiality boundary:
能够自行设置 Origin header 的 caller 不会被它阻止。
因此:
- 每个 surface 使用一个 key。 Marketing site、demo page 和 customer-facing
app 不应共享同一个 key。只有必须基于您数据回答的 surface 才获得
vendor。 - 绝不要把 rate sheet、cost basis 或任何未公开信息放在 publishable key 后面。 如果某个回答出现在 public page 上会让您感到不合适,那么该数据就不应放入 vendor-scoped embed。
- Session 会被限制到其 product,因此即使 parent key 持有
vendor,tile或viewersession 也绝不会携带vendor。
如需撤销,请编辑 key 的 scopes 或 revoke 它 — 两者都会在 下一个 request 立即生效,包括已经运行中的 session。撤销不会 延迟到 session expiry。
401 与 403
二者有意区分:
- 401 Unauthorized — key 缺失 / 无效 / revoked / expired。重新检查
key 值并确认未被 revoke。还包括 publishable key 被作为 raw bearer 发送时的
publishable_requires_session。 - 403 Forbidden — key 存在,但在此处不被允许。常见
subcodes:
insufficient_scope(从未拥有)、tier_capability_not_allowed(曾经拥有,但 tier 已不再允许)、session_origin_mismatch、ip_not_allowed(server keys)、server_key_in_browser、product_not_allowed。
二者都采用 fail closed:没有 scopes 的 key 在任何地方都会被拒绝。
Session tokens
SDK 用 publishable key 交换得到的 session 类似:
kld_sess_{env}_{jwt}
例如 kld_sess_live_eyJhbGciOi…。runtime call 中通过
Authorization: Bearer 或 X-Api-Key 提交。默认 TTL 为 900 秒(15
分钟); server 最大值为 30 分钟。session 会被限制到 mint 时对应的 product,
每个 request 都会重新读取 parent key 的 live policy。
撤销是立即生效的;新增 grant 则不是。 两个方向有意 不对称,并采用 fail closed:
| Change to the parent key | Effect on a session already in flight |
|---|---|
| Revoked or deleted | 下一个 request 即被拒绝 |
| A scope removed | 下一个 request 即消失 |
| Plan downgraded | tier-gated capability 在下一个 request 被拒绝 |
| Rate limit or monthly cap set to a new value | 下一个 request 即生效 |
| A scope added, plan upgraded, or a limit lifted entirely | 不可见 — 需要 mint 新 session |
session 只能相对其 parent 收窄权限,绝不能扩展到超过其 mint 时拥有的 scopes, 因此新的 grant 需要新的 exchange。session 很短(默认 15 分钟),正是为了让 这个间隔尽可能小。
完整 status table 请参阅 Errors。