JWT 指南

我如何理解 JWT kid:它是 Key Selector,不是信任證明

JWT header 的 kid 用來在 trusted JWKS 中選 key。我會處理 unknown/duplicate kid、key compatibility、rotation/cache,再做真正 signature verification。

作者:JWTDecoder.tools最後確認 2026-09-13

編輯語氣說明:第一人稱敘述代表 JWTDecoder.tools 已文件化的驗證工作流程;發布者與組織作者皆為 JWTDecoder.tools。

kid + alg → compatible JWK
trusted issuer → JWKS → kid + alg → JWK

JWT header 的 kid 我會把它看成 在已信任 key set 裡尋找 candidate key 的 identifier,而不是「這把 key 已可信」的證明。

例如:

{
  "alg": "RS256",
  "kid": "2026-09-key-b"
}

真正的信任流程應該是:

configured issuer
→ trusted JWKS
→ 用 kid 選 candidate
→ 檢查 key/algorithm compatibility
→ signature verification
→ issuer/audience/time validation

為什麼需要 kid

issuer 可以同時公開多把 key,尤其 rotation 期間:

{
  "keys": [
    { "kid": "old-key", "kty": "RSA", "...": "..." },
    { "kid": "new-key", "kty": "RSA", "...": "..." }
  ]
}

header 的 kid 幫 verifier 快速找到應嘗試的 key。

kid match 不等於 verification success

我找到同名 JWK 後,還會檢查:

  • candidate 是否唯一;
  • kty 是否符合 algorithm family;
  • JWK alg 若存在是否一致;
  • use 若存在是否是 sig;
  • key_ops 若存在是否包含 verify;
  • EC curve 是否相容。

最後還要真正驗 signature。JWKS Validator 會明確區分「找到 key」與「signature verified」。

Unknown kid 怎麼處理

rotation 後最常見:

JWT kid = new-key
cached JWKS = old-key only

我會先查 cache,找不到時做一次受控、rate-limited refresh,再找一次;還是沒有就 fail closed。

我不讓每個 random kid 都造成 unlimited network fetch,避免攻擊者製造 refresh storm。

完整 rotation 流程見 JWT Key Rotation。

Duplicate kid 怎麼處理

如果 JWKS 有多個相同 kid,又無法透過 kty/alg/use/key_ops 唯一選出 candidate,我會把它當 ambiguous configuration error。

不會因為 array 第一個剛好能驗就依賴 key ordering。

沒有 kid 一定 invalid 嗎

不一定。如果 trusted key set 只有一把 compatible key,某些 verifier 可以明確選出它。但在多 key 與 rotation 環境,kid 能大幅降低 ambiguity。

我會為未來 rotation 設計,而不是只看今天 JWKS 只有一把 key。

kid 是 untrusted string

因為它來自未驗證 header,我不會把 kid 直接串到:

  • filesystem path;
  • SQL query;
  • shell command;
  • 任意 URL。

我偏好在已取得的 trusted JWKS object 裡做 exact string lookup,並限制過長、control characters 或 path-like pattern。

JWT Security Analyzer 也會對可疑 kid 提示 policy signal。

kid 與 jku 是不同概念

kid 用來選 key;jku 可以指向 remote JWK Set URL。

我避免:

JWT 給 jku
→ verifier 自動 fetch
→ 用 kid 找 key
→ 接受 token

因為這會讓 token 選自己的 key source。

我會從 trusted issuer metadata 決定 JWKS,再使用 kid。

Rotation 時我不重用舊 kid

new key material 如果重用 old kid,stale cache 可能仍指向舊 public key,造成難解的 invalid signature。

我通常為 new key 使用 new kid。JWK Inspector 的 RFC 7638 thumbprint 可用來確認兩份 JWK 的核心 public key material 是否相同。

kid 和 invalid signature 的排查順序

  1. 讀 token kid;
  2. 確認 expected issuer;
  3. 取得該 issuer 的 trusted JWKS;
  4. 計算 matching candidates;
  5. 檢查 key metadata compatibility;
  6. 實際驗 signature;
  7. 看 JWKS cache / rotation 是否 stale。

更完整 signature 排查可看 JWT Invalid Signature。

我會寫哪些測試

unique matching kid → candidate selected
unknown kid → controlled refresh / fail
duplicate kid → ambiguous fail
kid matches but wrong kty → fail
kid matches but wrong alg → fail
kid matches but signature wrong → fail

這能防止程式未來退化成「只要 kid 找得到就算 valid」。

我的 kid 清單

  1. 把 kid 當 untrusted identifier。
  2. 先確定 trusted issuer/JWKS。
  3. 只在 trusted set 裡做 exact lookup。
  4. duplicate/ambiguity fail closed。
  5. 驗 kty、alg、use、key_ops、curve。
  6. 真正執行 signature verification。
  7. unknown kid refresh 需要 rate limit。
  8. rotation 時 new key 用 new kid。
  9. 不把 kid 直接當 path/query/URL。
  10. signature 後仍驗 issuer/audience/time。

我對 kid 最重要的理解是:它可以告訴 verifier「先試哪一把 key」,卻不能告訴 verifier「這把 key 為什麼值得信任」。 Trust 仍然來自 configured issuer、trusted key source 與真正的 signature verification。

來源與參考資料

相關指南