Skip to content
ADP
API Design PrincipleBETA

[ADP-55] API 金鑰

概述

API 金鑰是一種 API 身份驗證方法,常用於識別和授權用戶。這是ADP-47的補充。一般來說 API 金鑰有別於建立在 token 之上的 JWT/OAuth token。

金鑰和令牌的差異

API 金鑰和令牌有幾個主要差異:

  • 結構:

    • API 金鑰通常是簡單的字串
    • 令牌(如 JWT)包含編碼的資訊和聲明
  • 用途:

    • API 金鑰主要用於識別和認證
    • 令牌通常包含授權資訊和使用者上下文
  • 生命週期:

    • API 金鑰通常具有較長的生命週期,可能不會過期
    • 令牌通常具有較短的生命週期,需要刷新
  • 安全性:

    • API 金鑰由於生命週期較長,一旦洩露風險較大
    • 令牌通過短期過期和刷新機制提供更好的安全性
  • 使用場景:

    • API 金鑰:簡單認證、伺服器對伺服器通訊
    • 令牌:使用者會話、OAuth 流程、無狀態認證

指導原則

  • API 金鑰可能(MAY)是可旋轉(rotate)的。
  • API 金鑰應該(SHOULD)是可撤銷的。
  • 應該(SHOULD)實做API金鑰的過期機制。
    • 應該(SHOULD)小心提供不過期的金鑰,並提供撤銷功能。
  • 應該不(SHOLD NOT)將 API 金鑰寫在程式碼中。
  • 可以(MAY)考慮為不同的API金鑰提供不同的權限。
  • 可以(MAY)區分用戶級API金鑰和系統級(機器對機器)API金鑰。
  • API金鑰應該(SHOULD)存儲在安全的位置,例如環境變量或安全金庫中。
  • API金鑰必須(MUST)通過HTTPS傳輸,以防止截獲。
  • API 金鑰應該(SHOULD)只在生成時顯示一次。當通過 API 或使用者介面列出 API 金鑰時,伺服器不應該(SHOULD NOT)返回實際的金鑰值。完整的 API 金鑰值應該(SHOULD)只在初始金鑰創建請求的回應中提供,除非特定的安全要求另有規定。

實施

生產

大多數API金鑰只在生成時對用戶可見;僅有少數應用程序允許用戶後續查看金鑰。

消費

推薦的使用 API key 的方式,從上往下作為推薦優先序。

  1. (建議) Authorization: Bearer 是最常用的方法。
  2. Authorization: ${custom schema}。見 ADP-363
  3. API-Key(其實,不是常見的HTTP標頭)。
  4. (不建議) X-API-Keyx- 前綴標頭已被 RFC6648 棄用)。

TIP

事實上,API-Key 並非標準,但在標準標頭 Authorization 出現之前就有一些應用程式支援它。因此,使用 API 金鑰最推薦的方式是使用相同的 Authorization: Bearer;如果您需要區分金鑰用途,可以(MAY)在其中加入前綴。例如,OpenAPI 使用 sk-proj- 作為個人 API 金鑰的前綴,使用 sk-svcacct- 作為服務類型 API 金鑰的前綴。其他不帶前綴的字串則可以視作 JWT Token。

其他使用 API Key 放在 Authorization: Bearer 的服務範例:

參考資料

示例請求

http
POST HTTP/1.1 https://api.apidog.com/v1/projects/552408/export-openapi?locale=en-US

X-Apidog-Api-Version	2024-03-28
Authorization	Bearer APS-XXXXX
User-Agent	Apidog/1.0.0 (https://apidog.com)
Content-Type	application/json
Accept	*/*
Cache-Control	no-cache
Host	api.apidog.com
Accept-Encoding	gzip, deflate, br
Connection	keep-alive
Body:
Content-Type : application/json
{
  "scope": {
    "type": "ALL",
    "excludedByTags": ["pet"]
  },
  "options": {
    "includeApidogExtensionProperties": false,
    "addFoldersToTags": false
  },
  "oasVersion": "3.1",
  "exportFormat": "JSON"
}