什麼時候會需要拆開一個 token
- API 一直回 401,要確認是 token 過期了,還是根本沒帶到你以為的那個權限。
- 使用者回報「莫名其妙被登出」,要看這張 token 的有效期到底設了多久。
- 串接第三方登入,想確認對方回傳的 payload 裡到底有哪些欄位可以用。
- 前後端對不上時區,要把 exp 那串秒數換算成看得懂的當地時間。
- 做安全檢查,想確認自家簽出去的 token 有沒有把不該放的個人資料寫進 payload。
JWT 的三段結構
一個 JWT 就是三段 Base64URL 用點號接起來的字串,形如xxxxx.yyyyy.zzzzz。工具的結果區把這三段染成三個顏色, 對照下面這張表就知道每一段在做什麼。
| 段落 | 內容 | 能不能被讀懂 |
|---|---|---|
| Header | 一個 JSON 物件,說明用哪種演算法簽的(alg)、這是什麼型別的 token(typ),有時還有金鑰編號(kid)。 | 可以,任何人都讀得到。 |
| Payload | 一個 JSON 物件,裝的是這個 token 想主張的事情,每一個欄位叫一個 claim,例如使用者是誰、有什麼權限、什麼時候過期。 | 可以,任何人都讀得到。 |
| Signature | 前兩段加上密鑰算出來的雜湊值。它不含任何資訊,唯一的用途是證明前兩段 沒有被改過。 | 不行,它本來就不是拿來讀的。 |
七個註冊 claim 各代表什麼
RFC 7519 定義了七個標準 claim,名字都很短,第一次看不容易猜。工具的 claim 對照表會把說明直接列在欄位旁邊,這裡是完整版。
| Claim | 全名 | 意思 |
|---|---|---|
iss | Issuer | 誰簽發了這個 token,通常是你的認證服務網址。 |
sub | Subject | 這個 token 在描述誰,多半是使用者 ID。 |
aud | Audience | 這個 token 是給哪個服務用的。收到不是給自己的 token 應該拒絕。 |
exp | Expiration Time | 到期時間。到了這個時間點之後,驗證方就該拒絕它。 |
nbf | Not Before | 生效時間。在這之前這個 token 不該被接受。 |
iat | Issued At | 簽發時間。拿它跟 exp 相減,就是這個 token 打算活多久。 |
jti | JWT ID | 這一張 token 的唯一識別碼,用來做撤銷清單或防止重放。 |
時間為什麼要換算,怎麼換算
- 這三個時間 claim 的值是 NumericDate,也就是自 1970 年 1 月 1 日 UTC 起算的秒數,不是毫秒。JavaScript 的
Date.now()給的是毫秒,兩者差 1000 倍,是最常見的錯誤來源。 - 秒數本身不帶時區。工具會同時顯示你這台電腦當地時區的時間與 ISO 8601 的 UTC 時間,前後端記錄對不上時,看這兩行就知道差了幾個小時。
- 有效狀態分成四種:目前有效、已過期、尚未生效(
nbf還沒到), 以及沒有設定到期時間。最後一種本身就值得警覺,一張永不過期的 token 一旦外流就收不回來。 - 剛簽出來就顯示「尚未生效」通常是伺服器之間的時鐘差異,多數函式庫允許幾十秒的 容許誤差,這個工具照字面判斷、不自己加容許值。
為什麼不要把敏感資料放進 payload
這是使用 JWT 最常見的誤解:Base64URL 是編碼,不是加密。 它沒有密鑰、不需要破解,任何拿到 token 的人都能像這個工具一樣把 payload 還原成 明文 JSON。簽章保護的是「內容有沒有被改過」,不是「內容能不能被看到」。
- 不要放身分證字號、完整生日、住址、電話這類個資。
- 不要放密碼、其他系統的 API key,或任何一組還能用的憑證。
- email 與姓名要放之前先想清楚:token 常常被寫進伺服器日誌、錯誤回報系統與瀏覽器的 儲存空間,等於這些欄位也跟著被複製到那些地方。
- 真的需要藏起來的內容要用 JWE,那是加密過的另一種格式,不是這裡處理的 JWS。
- payload 只放識別碼,真正的資料讓後端自己去查,是比較安全的做法。
這裡驗得了哪些簽章
填入 HMAC 密鑰之後,可以離線驗證 HS256、HS384 與HS512,用的是瀏覽器內建的 Web Crypto,密鑰不會離開這個分頁。
- 驗證成功代表這個 token 確實是用該密鑰簽的,而且前兩段一個字都沒被改過。
- 驗證失敗只有兩種可能:密鑰打錯,或這張 token 被動過手腳。
- 有些服務後台給的密鑰是 Base64 編碼過的位元組,直接當文字算會得到不同的簽章, 這時勾選「密鑰是 Base64 編碼」。
RS256這類非對稱演算法需要公鑰,抓公鑰要發跨網域請求而通常被 CORS 擋, 所以這裡不支援,也不會為此加轉送伺服器。
你貼上的 token 會不會離開瀏覽器
不會。解碼、時間換算與 HMAC 驗證都在你的瀏覽器裡完成,沒有任何請求會把 token 或密鑰 送出去,也不寫進瀏覽器的儲存空間,關掉分頁就沒了。匯出的解析報告刻意不含完整的 token,因為報告是拿去貼給別人看的,而 token 本身就是一組還能用的憑證。 細節見隱私權政策。
常見問題
- 我貼進去的 token 會不會被送到伺服器?
- 不會。這個站沒有後端,解碼、時間換算與簽章驗證都是在你這個分頁的 JavaScript 裡跑完的。想自己確認的話按 F12 打開開發者工具的網路分頁,貼一次 token,你會看到沒有任何請求被發出去。
- 解碼跟驗證簽章差在哪裡?
- 解碼只是把 Base64URL 還原成 JSON,任何拿到 token 的人都做得到,它證明不了內容沒被改過。驗證簽章是拿密鑰重算一次雜湊再比對,那才能證明這個 token 確實出自持有該密鑰的一方,而且一個字都沒被動過。
- 為什麼 RS256 這類演算法在這裡驗不了?
- RS、ES、PS 系列用的是非對稱金鑰,驗證需要簽發方的公鑰,而公鑰通常掛在對方的 JWKS 網址上。要抓那個網址就得從瀏覽器發跨網域請求,多半會被 CORS 擋掉。與其做一個時靈時不靈的功能,這裡選擇只支援 HMAC,也不會為此加轉送伺服器。
- exp 顯示的時間跟我後端記的差了好幾個小時?
- 那是時區,不是算錯。JWT 的時間是自 1970 年起算的 UTC 秒數,本身不帶時區。這個工具同時顯示你電腦當地時區的時間與 ISO 8601 的 UTC 時間,兩個對照就看得出差幾個小時。另外注意單位是秒不是毫秒,用毫秒去算會差 1000 倍。
- 可以在這裡修改 payload 再簽一次嗎?
- 不行,這個工具只讀不寫。改過 payload 的 token 一定要用原本的密鑰重新簽章才會被接受,而那組密鑰應該只存在你的伺服器上,不該貼到任何網頁裡。