JWT 指南

我如何正確理解與計算 JWT exp claim

JWT exp 是 Unix epoch 秒數的 NumericDate。我會同時檢查秒/毫秒轉換、iat、nbf、clock skew、token lifetime 與 server-side expiration enforcement。

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

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

顯示 iat、nbf、有效區間與 exp 的 JWT 時間軸
判定到期問題前,先檢查 iat、nbf、有效區間與 exp。

處理 JWT expiration 時,我第一件事是確認 exp 的單位。RFC 7519 的 NumericDate 是 Unix epoch 的秒數,但 JavaScript Date.now() 是毫秒;如果直接比較,結果會完全錯誤。

如果只是要快速看時間狀態,我會用 JWT Expiry Checker 同時查看 iat、nbf、exp 與 active window。

exp 真正代表什麼

例如:

{
  "iat": 1789320000,
  "exp": 1789323600
}

代表 token 在 exp 時刻之後不應再被接受。這只是一個時間條件,不代表 signature、issuer 或 audience 已經驗證。

JavaScript 最容易犯的錯

錯誤:

Date.now() >= payload.exp

正確做法要把秒轉成毫秒:

const expired = Date.now() >= payload.exp * 1000;
const expiresAt = new Date(payload.exp * 1000);

我也會先確認 exp 真的是 number,而不是字串。

iat、nbf、exp 我會一起看

我把它們畫成時間線:

iat -------- nbf ===== usable window ===== exp
  • iat:何時發行;
  • nbf:從何時開始可用;
  • exp:何時停止接受。

不是每個 token 都會同時包含三者,但如果有,我會看它們的關係是否合理。

用 exp - iat 看 lifetime

const lifetimeSeconds = payload.exp - payload.iat;

如果 access token 的 lifetime 遠高於產品預期,我會確認 issuer 設定是否錯誤。JWT Security Analyzer 也可以提供 maximum lifetime policy 做 deterministic check。

Clock skew 要小而有意識

分散式系統的 clock 可能差幾秒,因此 verifier 可以有有限度 tolerance。但我不會把 tolerance 調到幾分鐘甚至更長,只為了讓測試通過。

如果「剛發的 token 立刻 expired」,我會檢查:

  • issuer/server clock;
  • NTP/container clock;
  • iat、nbf、exp;
  • seconds vs milliseconds;
  • 是否其實拿到 cache 裡的舊 token。

Timezone 只影響顯示方式,不會改變 epoch 比較本身。

沒有 exp 一定 invalid 嗎

標準並沒有規定所有 JWT 都必須有 exp,但 application 可以要求它。

如果 API policy 是「所有 access token 必須有 expiration」,那 missing exp 就應該 fail。這是應用程式 profile 的要求。

Client-side expiration check 不是 security boundary

前端可以先檢查 exp,避免發出明知會失敗的 request,改善 UX。但真正的 resource server 仍要自己驗 expiration。

browser clock 與 client code 都不應成為最終 security authority。

還沒過期卻 401 怎麼辦

exp 正常只代表時間沒有失敗。我還會看:

  • signature;
  • iss;
  • aud;
  • nbf;
  • token type;
  • scope/role;
  • JWKS rotation/cache。

完整排查見 JWT 401 Unauthorized。

已過期應怎麼處理

我不會修改 payload 的 exp 再重新 Base64URL encode。那會破壞 signature。

正確流程通常是:

  • 使用合法 refresh flow 取得新 access token;或
  • refresh 不可用/失效時重新 authentication。

詳見 JWT Expired Token。

我會測哪些 edge cases

exp 在過去 → fail
exp 等於現在 → fail/依 library 規則
exp 在未來 → time check pass
exp 是 string → fail schema/policy
exp missing → 依 required-claim policy
nbf 在未來 → fail
iat 明顯在未來 → investigate/fail policy

production verifier 我會優先使用成熟 JWT library 的時間驗證功能,而不是只靠自己寫幾行 epoch comparison。

我的 exp 檢查清單

  1. exp 資料型別正確嗎?
  2. NumericDate 是秒,不是毫秒。
  3. JavaScript 是否正確 * 1000?
  4. iat、nbf 與 exp 關係合理嗎?
  5. issuer/verifier clock 是否同步?
  6. clock skew 是否有限且明確?
  7. server 端是否真的 enforcement expiration?
  8. expiration 通過後是否仍驗 signature、issuer、audience?

我處理 exp 的核心不是把 timestamp 轉成漂亮日期,而是確認 時間單位、token lifecycle 與 verifier policy 三者一致。

來源與參考資料

相關指南