看到 audience mismatch 時,我第一個問題不是「怎麼讓 verifier 不檢查 aud」,而是:這個 token 本來就是發給目前這個 API 的嗎? aud 是 JWT 用來表達 intended audience 的 claim,signature 正確也不能取代 audience validation。
aud 可以是字串,也可以是陣列
單一 audience:
{ "aud": "https://api.example.com" }
多個 audience:
{
"aud": [
"https://api.example.com",
"secondary-service"
]
}
因此 verifier 應檢查 expected audience 是否存在於 aud,而不是假設它永遠只有 string。
我最先檢查四件事
- 送到 API 的是不是 access token?
- token 的
aud是否包含目前 API? - API 的 expected audience 是否屬於現在這個環境?
- issuer 是否真的被設定為發出這個 API 的 token?
大部分 audience mismatch 都能在這四個問題裡找到方向。
ID token 與 access token 最容易混淆
兩者都可能長成 JWT。ID token 的 aud 通常和 OIDC client 有關,而 resource API 往往期待自己的 resource identifier。
例如 token:
{ "aud": "web-client-id" }
API 設定:
expected audience = https://api.example.com
這時即使 signature 正常,API 拒絕它也是合理的。
我不會因為「這是一個 JWT」就認為它是可用的 access token。
環境設定很常是根因
我會比較:
local → api://local
staging → api://staging
production → api://production
如果 frontend 拿的是 staging token,卻打 production API,audience mismatch 正是應該發生的保護。
我會同時檢查 client 取得 token 時指定的 resource/audience,以及 server verifier 的 expected audience。
我不隨便 normalize audience
這兩個字串可能不同:
https://api.example.com
https://api.example.com/
我不會只為了讓 validation 通過就自動去掉 slash、忽略大小寫或做 prefix match。應該讓 identity provider 與 API 使用一致的 canonical identifier。
Signature valid 仍然可以 audience invalid
我會把這兩步分開:
trusted key 驗 signature
→ token 的完整性/簽發者 key
expected audience check
→ 這個 token 是否真的給我這個 resource
JWKS Validator 可以同時提供 expected audience,重現 signature 與 claim policy。
azp 不是通用替代品
在特定 OIDC 情況,尤其多 audience ID Token,azp(authorized party)有定義好的用途。但我不會在 aud mismatch 時隨便改用 azp 讓 token 通過。
只有 protocol/profile 明確要求時,我才依規則驗證 azp。
401 時不要只盯著 audience
很多 API 會把 audience mismatch 回成 401 Unauthorized,但 401 也可能是:
- token 沒有送到;
- expired/not-yet-valid;
- signature fail;
- issuer mismatch;
- wrong token type;
- scope/role 不足。
我會依 JWT 401 Unauthorized 的順序完整排查。
我如何寫 audience test
至少準備:
correct aud string → pass
wrong aud → fail
aud array contains expected → pass
aud array missing expected → fail
missing aud → 依 policy fail
signature 與 issuer 保持一致,才能單獨驗證 audience policy。
我不採用的修法
- 關閉 audience validation;
aud不存在也一律放行;- production 同時接受 local/staging/prod 全部 audience;
- 用未定義 custom claim 代替 aud;
- 只要 signature 正確就忽略 resource boundary。
我的 audience mismatch 清單
- 用 JWT Decoder 看 raw
aud。 - 確認 token type 是正確 access token。
- 確認
aud是 string 還是 array。 - 找到 API 真正 configured expected audience。
- exact comparison,不做危險的模糊匹配。
- 檢查 local/staging/prod 是否混用。
- 確認 signature 與 issuer validation 也各自通過。
- 只在 protocol 明確要求時處理
azp。
我最後只問一件事:這個 token 是否真的被發給目前這個 API? 如果不是,audience mismatch 就不是 bug,而是 verifier 正在正確地阻止跨 resource 使用 token。