身分驗證與範圍
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。