第一次看到 JWT 時,很多人會以為「沒有 secret 就看不到 payload」。一般的 signed JWT/JWS 並不是這樣。header 與 payload 通常只是 Base64URL 編碼,不是加密,所以任何人都能把它解碼成 JSON。
我使用 JWT Decoder 的目的,就是先讀取 token 自己聲稱的資訊,再決定下一步要驗證什麼。但我會把一句話放在最前面:decode 不等於 verify。
沒有 secret 可以看到哪些內容
常見 3-part signed JWT:
header.payload.signature
header 可能是:
{
"alg": "RS256",
"typ": "JWT",
"kid": "2026-key-03"
}
payload 可能是:
{
"iss": "https://id.example.com/",
"aud": "https://api.example.com",
"sub": "user-123",
"exp": 1789323600
}
這些都不需要 secret 才能讀。但這也代表我不會把 password、private key 或其他真正秘密資料放進 JWT payload。
我把 JWT 狀態拆成三層
Decoded
我能解析 header/payload。這只代表「token 說了什麼」。
Signature verified
我用可信任的 shared secret、public key 或 JWKS 確認簽章真的正確。
Application accepted
即使 signature 正確,我還是會檢查 iss、aud、exp、nbf、token type、scope/role 是否符合應用程式政策。
只說「JWT valid」太模糊,我會明確說是哪一層通過。
我先看 header 的哪些欄位
alg
它告訴我 token 聲稱使用哪個 signing algorithm,但不讓 token 自己決定 verifier policy。伺服器應該先有明確 allowlist。
kid
它幫助我在 trusted JWKS 裡選 key。kid match 不等於 signature verified。
typ
它可能提供 token type 提示,但我不只靠 typ 做安全決策。
Payload 我先看什麼
iss
誰聲稱簽發這個 token。真正驗證時要與 configured expected issuer exact match。
aud
這個 token 是發給哪個 resource/API。signature 正確但 audience 不對,一樣應該拒絕。
exp、nbf、iat
我把三者當成時間線一起看。快速檢查時用 JWT Expiry Checker。
為什麼 Base64URL 可讀不代表不安全
Base64URL 是 encoding,不是 encryption。signed JWT 的安全價值主要來自 signature integrity 與後續 trust policy,而不是讓 payload 保密。
我會把流程記成:
Base64URL decode
→ 讀內容
Signature verification
→ 確認 trusted key 是否簽過
Claim validation
→ 確認 issuer/audience/time 是否能接受
HS256 沒有 secret 可以做到什麼
HS256 使用 shared secret。沒有 secret,我仍可讀 header/payload,但不能證明 HMAC signature 正確。
我也不會把 production HS256 secret 貼進不受信任的網站或傳給前端程式。若要比較 HS256 與 RS256 的 trust model,可看 HS256 vs RS256。
RS256/ES256 沒有 private key 仍可驗證
非對稱演算法的 verifier 不需要 private key。issuer 可以保留 private key,只公開 public key/JWKS 讓 API 驗證。
我常用的流程:
trusted issuer
→ trusted JWKS
→ JWT kid
→ compatible JWK
→ signature verify
→ iss/aud/time checks
這正是 JWKS Validator 要解決的問題。
我不讓 token 自己選 trust source
JWT header 可能包含 jku 或 x5u。我不會看到 URL 就自動 fetch 並信任,因為這會讓 untrusted token 決定自己的 key source。
我會從 application configuration 的 trusted issuer 出發,再使用該 issuer 的 metadata/JWKS。
我不做的事
- payload 看起來合理就直接授權;
- 看到
alg就動態接受所有 algorithm; kidmatch 就當成 verified;- 自動追 token 內的
jku/x5u; - 為了除錯把 production access token 放進 URL/log;
- signature 出問題就關閉 verification。
什麼時候一定要從 decode 進入 verify
只要我要用 token 做 authentication 或 authorization,我就不會停在 decode。
我會問:
- 這個 claim 會影響使用者身分嗎?
- 會影響 API 權限嗎?
- 我需要證明 trusted issuer 真的簽了它嗎?
- 我需要確認 token 沒被修改嗎?
只要答案是「是」,就要用 JWT Signature Verifier 或 JWKS Validator 進行真正驗證。
我的最後檢查清單
- 先 decode header/payload。
- 把結果標示為 decoded only。
- 檢查
alg、kid、iss、aud、時間 claims。 - 從 configured trust policy 選擇 key source。
- 驗證 signature。
- 再驗證 issuer、audience、expiration、token type 與 permissions。
我在沒有 secret 時解碼 JWT,最重要的心態是:我只是讀到 token 的主張,還沒有相信它。 當這個界線清楚,JWT 除錯會安全很多。