我打開 JWT payload 時,不只想知道「有哪些 claim」,還會先判斷每個值屬於哪一類:只是資訊、會影響 token trust,還是最後會進入 authorization 決策。因為 JWT Decoder 能顯示的內容仍然是未驗證資料。
我會把流程分成:
decode claims
→ verify signature
→ validate issuer/audience/time
→ evaluate scope/role permissions
Registered claims 是什麼
RFC 7519 定義了常見 registered claim names,例如:
isssubaudexpnbfiatjti
這些名字有標準語意,但不是每個 JWT 都強制必須包含所有欄位。哪些 claim 必須存在,仍取決於 protocol profile 與應用程式政策。
iss:誰聲稱簽發 token
{ "iss": "https://id.example.com/" }
我會把它與 configured expected issuer 做 exact match,並把 issuer 綁定到 trusted metadata/JWKS,而不是看到 token 裡的 URL 就動態信任。
完整流程可看 JWT Issuer Validation。
sub:token 的 subject
sub 常用來表示 user 或 service principal,但它的意義通常是在 issuer context 裡成立。不同 issuer 完全可能使用相同 sub 字串。
所以如果我需要全域 identity key,會考慮 issuer + subject 的組合,而不是單獨把 sub 當全世界唯一。
aud:token 是發給誰的
aud 可以是字串:
{ "aud": "https://api.example.com" }
也可以是陣列:
{ "aud": ["api-a", "api-b"] }
API 應確認自己的 expected audience 存在。如果 signature 正確但 audience 是另一個 resource,我仍會拒絕。
exp:expiration time
exp 是 Unix epoch 秒的 NumericDate。
{ "exp": 1789323600 }
JavaScript 要乘以 1000 才能和 Date.now() 或 Date 的毫秒單位一致。
快速檢查時我會用 JWT Expiry Checker。
nbf:not before
如果目前時間還沒到 nbf,token 還不應該被接受。分散式系統可以設計小幅 clock skew tolerance,但我不會用非常大的 tolerance 掩蓋時間同步問題。
iat:issued at
iat 告訴我 token 何時發行。它常用來:
- 計算 token age;
- 用
exp - iat看 lifetime; - 發現 issuer clock 明顯偏移;
- 排查 rotation/incident timeline。
iat 本身不是 authentication 證據。
jti:JWT ID
jti 可以當 token identifier,用於 replay detection、denylist 或 audit correlation。但只有 claim 存在不會自動防 replay,server 還需要真正的 storage/policy。
Custom claims 怎麼看
常見 custom/產品 claim:
rolespermissionsgroupstenant_idscope
我不會因為 payload 裡寫著 admin 就立刻相信。只有當 signature、issuer、audience、time policy 都已驗證,這些 claim 才有資格進入 authorization decision。
Claim 存在也要驗資料型別
例如這個 exp:
{ "exp": "1789323600" }
是 string,不是我預期的 NumericDate number。
aud 則必須正確處理 string 或 array。custom claims 如果 application 有 schema,我也會驗型別,而不是靠 JavaScript truthy/falsy 隱式處理。
Claim 不存在時怎麼辦
我不採用「標準說 optional,所以永遠可以沒有」的推論。
例如 API policy 可以要求:
required: iss, aud, exp
那缺少其中任一 claim 就應該 fail。這是 application profile,而不是和 RFC 衝突。
Signature、claims、authorization 三件事不能混在一起
我會明確區分:
signature valid
≠
claims acceptable
≠
request authorized
一個 token 可以由可信 issuer 正確簽署,但已過期、發給別的 API,或沒有目前 endpoint 需要的 scope。
JWT Validator 可以檢查結構與常見 time claims;JWT Debugger 更適合把 issuer/audience/401 問題一起排查。
ID token 與 access token 的 claims 不完全相同
兩者都可能是 JWT,但 validation profile 不同。我會先確認 token type,再使用對應規則,不把所有 JWT 都塞進同一個 verifier configuration。
我排查 claims 的順序
iss是否是 expected issuer;aud是否包含目前 resource;exp是否已過期;nbf是否仍在未來;iat是否合理;sub是否符合預期 subject 格式;- token-specific scope/role/type 是否正確;
jti若有使用,server 是否真的執行 replay/revocation policy。
Logging 時我避免整包 payload
JWT payload 可能包含 email、subject、tenant 或其他個資。production log 我只保留必要的診斷 metadata,不會把完整 token 或整份 payload 當成普通 debug log。
我的核心原則
我把 JWT claim 視為 token 提出的主張。只有 trusted key 驗證 signature,並通過 application 的 issuer、audience、time 與 token-type policy 後,我才會把這些 claim 用於安全決策。
因此我不會問「這個 claim 有沒有」,而會問:它來自哪個已驗證的 issuer?它的資料型別正確嗎?它是否符合目前 endpoint 的政策?