我驗 JWT 時,會把 iss 看成信任鏈的起點,而不是 payload 裡普通的一個字串。因為真正的問題是:我到底信任哪個 issuer,以及這個 issuer 對應哪一組 key?
iss 告訴我什麼
{
"iss": "https://id.example.com/",
"aud": "https://api.example.com"
}
這只代表 token 聲稱由這個 issuer 發行。token 還沒驗證前,我不會因為看到這個 URL 就自動信任它。
application config 應先知道:
expected issuer = https://id.example.com/
我使用 exact match
這兩個值可能不是同一個 issuer identifier:
https://id.example.com
https://id.example.com/
tenant path 也一樣:
https://id.example.com/tenant-a
https://id.example.com/tenant-b
我不會用 prefix、suffix 或隨意 trim 讓它們「差不多」。安全 identifier 應與 provider metadata / application config 精確一致。
我不讓 token 的 iss 自動建立 trust
我避免:
讀未驗證 JWT 的 iss
→ 自動 fetch 該 URL 的 metadata
→ 自動信任那裡的 JWKS
→ 驗 token
這樣等於讓 untrusted input 選擇自己的 trust source。
我使用:
configured issuer
→ token iss exact match
→ trusted metadata
→ trusted jwks_uri
→ key selection
→ signature verify
Metadata 回傳的 issuer 也要一致
OIDC/OAuth metadata 可能包含:
{
"issuer": "https://id.example.com/",
"jwks_uri": "https://id.example.com/.well-known/jwks.json"
}
我會確認 returned issuer 和 discovery 使用的 issuer 精確一致。OIDC Discovery Checker 可以直接檢查這條關係。
Issuer 與 JWKS 要綁在一起
只找到一把能驗 signature 的 public key 不夠。我要知道這把 key 是否來自我信任的 issuer。
expected issuer
→ trusted metadata
→ trusted JWKS
→ kid candidate
→ signature verification
這可以避免把另一個 tenant/issuer 的 key 混進 verifier。
Multi-tenant 情況更需要清楚規則
一些 identity provider 有 tenant-specific issuer,也可能支援 multi-tenant。這時我會明確定義:
- 哪些 tenant 可以接受;
- expected issuer 如何形成;
- metadata/JWKS 是否共用;
- audience 是否也依 tenant/resource 不同。
我不只檢查 domain suffix。
Issuer 與 audience 是不同問題
iss:誰發的?aud:發給誰?
兩者都要通過。signature 正確也不代表這兩項一定正確。
Audience 問題見 JWT Audience Mismatch。
Rotation 時 issuer binding 仍然不變
出現新 kid 時,我不會去網路上任意找 key。我只 refresh 該 trusted issuer 的 JWKS,再找新 key。
JWT Key Rotation 說明 unknown kid 與 cache refresh 的完整流程。
jku / x5u 不能取代 issuer policy
JWT header 可以帶 remote key URL,但我不會讓 token 自己指定任意 URL 當信任來源。key source 應由 configured issuer / metadata 決定。
我怎麼排查 issuer mismatch
- 用 JWT Decoder 看 raw
iss。 - 找 server 真正 configured expected issuer。
- 比較 trailing slash、tenant path 等差異。
- 取得 trusted metadata,確認 returned issuer。
- 檢查
jwks_uri是否屬於這條信任設定。 - 在該 JWKS 中選
kidcandidate。 - 實際驗 signature。
- 再驗 audience 與 time claims。
JWKS Validator 可以同時輸入 expected issuer 重現這個流程。
我不採用的做法
- 所有 issuer 都接受;
- 只比 domain suffix;
- token 說去哪裡抓 JWKS 就去哪裡;
- signature 通過就忽略 issuer;
- 為了消除 slash mismatch 而做過度 normalize。
我的 issuer validation 清單
- configured expected issuer 是明確值。
- token
issexact match。 - metadata returned issuer exact match。
- JWKS source 綁定 issuer。
kid只在 trusted set 裡選 key。- 實際驗 signature。
- 再驗 audience、expiration、token type 與 permissions。
我重視 issuer validation,不只是要比較一個字串,而是要回答:這顆 JWT 的 cryptographic trust 到底屬於哪個身分系統、哪一組 key、哪個 security domain。