要解碼一個精簡 (compact) 的 JWT,請以 '.' 字元分割字串,使用 java.util.Base64 對前兩個段落進行 Base64url 解碼,並將每個段落解析為 UTF-8 JSON。第三個段落是簽章,在沒有金鑰的情況下無法安全檢視,因此僅憑解碼並無法證明權杖是真實的。若想在不將 jjwt、java-jwt 或 Nimbus JOSE+JWT 加入專案的情況下進行一次性檢查,JWT 解碼器會在您的瀏覽器中本機執行相同的分割與解碼作業。Java 開發人員常在 OAuth 回呼除錯、測試固定資料審查,或跨服務健全性檢查時將權杖貼進去。此工具會呈現標頭 (header)、承載資料 (payload),以及它所辨識的 RFC 7519 註冊聲明 (registered claims),因此您可以在把權杖接入 Spring Security 篩選器或自訂驗證篩選器之前,先確認權杖所聲明的內容。解碼回答的是「這個權杖說了什麼」;驗證回答的是「我是否應該相信它所說的」。把這條界線劃清楚,才能讓一個有用的除錯輔助工具,變成一條安全的工作流程。

精簡 JWT 的結構:標頭、承載資料、簽章
RFC 7519 將精簡 JSON Web Token 描述為三個以單點連接的 Base64url 編碼段落:header.payload.signature。每個段落使用 RFC 4648 中定義的 URL 安全字母集:26 個大寫字母、26 個小寫字母、數字 0 到 9、連字號,以及底線。填充字元刻意省略,因為段落長度是由編碼後的位元組數固定下來的,所以帶填充的權杖在結構上就是無效的,嚴格的解碼器會將其拒絕,而不是悄悄接受另一種格式。
標頭帶有關於權杖的中繼資料:簽章或加密演算法 (alg 欄位)、選擇性的媒體類型 (通常為 typ: JWT),以及簽發者選擇加入的任何其他參數。承載資料帶有聲明,包括來自 RFC 7519 的註冊名稱、在別處註冊的公開名稱,以及您應用程式定義的私有名稱。第三個段落是簽章,若為未受保護的權杖則為空字串。僅解碼的工具只會檢查第三個段落是否符合精簡 Base64url 的形狀;其位元組永遠不會被解讀為已驗證的簽章。
Java 的 java.util.Base64 類別透過 Base64.getUrlDecoder() 公開一個 URL 安全的解碼器。由於精簡 JWT 會去掉結尾的 = 字元,您通常會將它與一個小型填充輔助函式搭配使用,或是在段落長度整齊的情況下呼叫 Base64.getMimeDecoder()。解碼後,這些位元組應被解讀為 UTF-8 JSON。這就是完整的解碼管線;圍繞在它之外的一切都屬於驗證。
Java 開發人員解碼 JWT 的兩種方式
大多數 Java 專案傾向使用第三方函式庫,而不是自己手寫解碼。常見的三個選擇是:
- jjwt (io.jsonwebtoken):串接式 (fluent) 的建構 API,對 Spring 友善,支援 JWS 與 JWE。
- java-jwt (com.auth0):介面小而精實,適合用於權杖簽發與解析。
- Nimbus JOSE+JWT:Spring Security OAuth 所使用的參考級品質函式庫。
每個函式庫都公開 parseSignedClaims(...) 或 decode(...) 等輔助方法,在內部進行分割、Base64url 解碼、解析 JSON,並在提供金鑰時驗證簽章。解碼步驟是廉價且無副作用的部分;昂貴且涉及安全性的是驗證,它需要金鑰與政策。
若只是為了偶爾檢查、除錯 OAuth 回呼、讀取測試固定資料,或比較兩個服務看到的內容,特地拉入一個相依套件就太殺雞用牛刀了。這正是本機瀏覽器解碼器填補的空缺:它能在不更動您的建置、不開啟 IDE、或將權杖送往遠端服務的情況下,顯示精簡權杖的標頭與承載資料。
在瀏覽器中本機解碼 JWT 權杖
JWT 解碼器是一個刻意設計得很精簡的工具,在您的瀏覽器分頁中執行與 java.util.Base64 相同的分割與 Base64url 處理作業。請依照下列步驟操作:
- 複製一份標準 header.payload.signature 格式的精簡權杖。請確認沒有夾帶多餘的空白、換行,或前後引號。
- 將其貼到 JWT 解碼器頁面上的輸入欄位中。
- 選擇 Decode JWT。頁面會以兩個點分割字串,驗證每個段落是否為未填充的 Base64url,將標頭與承載資料解碼為 UTF-8,並將其解析為 JSON。
- 閱讀所呈現的標頭物件、承載資料物件,以及頁面所辨識的任何 RFC 7519 註冊聲明。
- 將結果視為「未經驗證」的資訊。頁面會將每一次成功的解碼標示為未經驗證,以免一個方便的檢查步驟被誤認為是安全性檢查。
- 結束後,請清除輸入欄位與剪貼簿。權杖可能帶有您不希望殘留的個人識別資訊、租戶資料或範圍 (scope)。
若想採用更廣泛、完全不寫程式碼的瀏覽器工作流程,請參閱 在瀏覽器中無需撰寫程式碼即可解碼 JWT 權杖。
解碼後的標頭與承載資料包含什麼
標頭幾乎總是一個只有兩個常見欄位的小型 JSON 物件:alg (簽發者使用的演算法,例如 HS256、RS256 或 ES256) 與 typ (通常為 JWT)。承載資料則承載應用程式邏輯,它可以在同一個扁平物件中混合註冊聲明、公開聲明與私有聲明。
下表摘要列出 RFC 7519 所定義的註冊聲明。解碼器會在這些聲明存在時顯示,但它不會強制執行任何一項。
| Claim | 完整名稱 | 意義 |
|---|---|---|
| iss | Issuer | 簽發該 JWT 的主體。 |
| sub | Subject | 該 JWT 所描述的主體。 |
| aud | Audience | JWT 預期的接收者。 |
| exp | Expiration Time | JWT 不得再被接受的時間點。 |
| nbf | Not Before | JWT 不得在此時間之前被接受。 |
| iat | Issued At | JWT 簽發的時間。 |
| jti | JWT ID | 可用來防止重放 (replay) 的唯一識別碼。 |
針對 exp、nbf 與 iat,工具會同時顯示原始的 NumericDate 數值與 ISO 時間戳記。NumericDate 是以 Unix 秒數表示的慣例,並非該權杖目前可被接受的保證,因為時鐘偏移、接收者,以及簽發者的政策都會影響。對於 aud 聲明,它可能是單一字串或陣列;解碼器會原樣呈現 JSON 值,而不會判定它是否符合您的應用程式。自訂聲明會保留顯示在原始承載資料中,因為 JWT 允許私有聲明名稱,但頁面不會賦予它們任何特殊意義。
瀏覽器解碼器不會做的事
這個頁面是一個「僅供解碼」的工具。它不接受秘密金鑰或公開金鑰、不驗證 JWS 簽章、不檢查簽發者、不檢查接收者、不套用時鐘偏移、不解密 JWE,也不做出授權決策。它不會上傳權杖、不會將權杖送往 API、不會擷取簽章金鑰、不會儲存副本,也不會建立帳號。解碼完全在瀏覽器中進行。
一份可讀的承載資料仍然可能是偽造、過期、針對不同接收者,或使用您不信任的金鑰所簽署的。若您需要驗證權杖,請在負責安全性決策的服務中使用一套有維護的 JWT 函式庫,並於該處驗證演算法、金鑰、簽發者、接收者、效期,以及任何應用程式特定的要求。解碼器無法顯示加密 JWE 中的內容、無法修復毀損的權杖、無法找出簽章金鑰,也無法告訴您簽章是否正確。
Java 在信任權杖之前仍必須驗證的事項
在任何 JWT 函式庫中,解碼與驗證是兩種不同的操作。成功解碼之後,Java 端仍需確認:
- 標頭中的 alg 是應用程式所接受的演算法。拒絕 none,以及拒絕演算法混淆 (例如將 RS256 權杖拿 HMAC 金鑰驗證),是不可妥協的底線。
- 簽章與標頭和承載資料相符,使用的是預期的金鑰。該金鑰本身必須來自信任的金鑰存放區或 JWKS 端點,而不是從權杖中取得。
- iss 聲明與預期的簽發者識別碼相符。
- 當 aud 為必要時,aud 聲明包含您應用程式的識別碼。
- 目前時間晚於 nbf 且早於 exp,並允許您安全政策所允許的時鐘偏移。
- 若您的服務有追蹤重放,任何 jti 值在近期內未被使用過。
這些檢查位於您的驗證篩選器、資源伺服器組態,或負責信任決策的 Spring Security OAuth2ResourceServer 設定之中。瀏覽器解碼器是讀取權杖所「聲明」之內容的側通道;Java 的驗證路徑才是決定權杖是否可被接受的那一條。
Java 開發人員檢查權杖時的安全工作流程
即使 JWT 並非密碼,它們經常帶有個人識別資訊、租戶資料、範圍,以及其他應用程式特定的數值。請以您對待 session cookie 或 API 金鑰的同等謹慎來對待它們:
- 只在您有權檢查權杖的環境中取得權杖。測試固定資料與本機模擬 (mock) 沒問題;不小心擷取到的正式環境 bearer 權杖則不行。
- 將權杖貼到本機頁面,而不是貼到公開的線上解碼器。JWT 解碼器在您的瀏覽器中執行,絕不會將權杖傳送出去。
- 檢視 alg 欄位與註冊聲明,完成後清除輸入欄位與剪貼簿。
- 避免將正式環境的憑證貼到共用螢幕、問題追蹤系統、聊天訊息、螢幕擷圖,或第三方線上解碼器中。
- 若您需要獨立轉換 Unix 時間戳記,Unix 時間戳記轉換器可在不上傳數值的情況下,以 UTC、本地時間與 ISO 8601 格式呈現 NumericDate。
解碼步驟是例行的開發工作。讓解碼路徑維持在本機,並把驗證路徑留在 Java 服務內,才能將一個有用的除錯工具,轉化為可永續經營的安全性 posture。