JWT 指南

JWT Claims 說明:我如何讀取 iss、aud、exp 與 sub

說明常見 JWT claims 的意義與判讀順序,並區分解碼、簽章驗證與應用程式自己的接受政策,以及實際驗證時應遵循的安全檢查流程。

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

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

iss · sub · aud · exp · nbf · iat · jti claim map
iss · sub · aud · exp · nbf · iat · jti

我打開 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,例如:

  • iss
  • sub
  • aud
  • exp
  • nbf
  • iat
  • jti

這些名字有標準語意,但不是每個 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,我仍會拒絕。

參考 JWT Audience Mismatch。

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:

  • roles
  • permissions
  • groups
  • tenant_id
  • scope

我不會因為 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 的順序

  1. iss 是否是 expected issuer;
  2. aud 是否包含目前 resource;
  3. exp 是否已過期;
  4. nbf 是否仍在未來;
  5. iat 是否合理;
  6. sub 是否符合預期 subject 格式;
  7. token-specific scope/role/type 是否正確;
  8. 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 的政策?

來源與參考資料

相關指南