記事一覧へ戻る
操作ハウツー

JWT トークンをデコードして中身を確認する方法

JWT を貼り付けて header / payload を読み取る手順。Base64URL の構造、exp / iat の意味、デコードと署名検証の違いを順に解説します。

デコードは「中身を読む」だけで、署名の真偽は別

最初に明確にしておきたいのは、JWT のデコードと署名検証は別の操作だということです。デコードは header.payload.signature というドット区切り文字列のうち最初の 2 つ (header と payload) を Base64URL から復号して JSON として読むだけで、「これが正規発行者から出たトークンかどうか」は一切判定しません。逆に署名検証は、signature 部分を発行者の公開鍵 / 共通鍵で検証して「改ざんされていないか」を確認します。中身を読みたいだけなら jwt-decode で十分で、認可判定として使うなら jwt-verify が必要、というのが正しい使い分けです。

実務でデコードが必要になる場面は多岐にわたります。API レスポンスに含まれる JWT の中身を確認したい、フロントエンドの認証ロジックをデバッグしていて exp (有効期限) や iat (発行時刻) が想定通りか調べたい、ログに残ったトークンから user ID や scope を読みたい、テスト環境で発行した JWT に意図した claim が乗っているか確認したい。いずれも「中身を読むだけ」で済む作業で、署名鍵を持ち出す必要はありません。

ブラウザだけでトークンを分解する

jwt-decode を開いて、JWT を入力欄に貼り付けます。eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIi... のようなドット区切り文字列で、3 つのパートに分かれているのが分かるはずです。貼り付けた瞬間にツールが自動でデコードし、Header / Payload / Signature の 3 つのパネルが表示されます。

Header には署名アルゴリズム (alg: "HS256" / "RS256" / "ES256" など) と種別 (typ: "JWT") が入っています。Payload には iss (発行者) / sub (主体) / aud (対象) / exp (有効期限) / iat (発行時刻) / nbf (この時刻以降に有効) / jti (トークン ID) などの標準 claim と、サービスごとの独自 claim (role, email, scope など) が並びます。jwt-decode は exp / iat / nbf のような Unix 秒タイムスタンプを自動的に「2026-06-13 14:30 (3 時間後に期限切れ)」のような人間可読な日時として併記して表示します。Signature は復号せず、原文の Base64URL 文字列としてそのまま表示します (検証に使うには jwt-verify 側に貼り直してください)。

入力した瞬間に DevTools の Network タブを見ても通信は発生しません。デコード処理はすべてその場のメモリで完結します。

Base64URL と JSON パースの内部仕様

JWT は 3 つの Base64URL 文字列をピリオドで連結したものです。通常の Base64 と異なり、URL に安全に乗るよう +-/_ に置換し、末尾の = パディングを省略する規格です。ブラウザの atob() はこの URL-safe 表記をそのままでは食わないので、jwt-decode は内部で -+_/ に戻し、長さが 4 の倍数になるよう = を付け足してから atob に渡しています。デコード後の binary 文字列は Uint8Array 経由で TextDecoder("utf-8") に渡して、UTF-8 として正しい JSON 文字列に戻ります (これを怠ると日本語を含む claim が文字化けします)。

復号した JSON は JSON.parse で構造化し、UI 側で claim ごとに色分けして表示します。失敗したときの扱いも分かれていて、Base64URL のパディング不整合や 3 セグメント未満の入力は「形式が JWT ではない」とエラー、JSON パースが失敗した場合は「Base64URL は通ったが中身が JSON ではない」と区別してエラーを返します。これは「壊れたトークン」と「JWT 風の別形式 (Branca、PASETO など)」をユーザーが見分けやすくするためです。発行側を作りたい場合は jwt-encodeheader.payload.signature 形式を組み立てられ、こちらは WebCrypto の SubtleCrypto.sign で署名まで一気に作れます。

アップロード型 JWT デコーダのリスク

「JWT decoder」「JWT debugger」で検索すると、ブラウザに貼ったトークンを裏で外部サービスへ送る Web ツールが少なからずあります。デコードだけならサーバー側でも同じ計算ができるので、技術的にはサーバーに送る必要はゼロです。にもかかわらず送るタイプのサービスを使うと、貼ったトークンがそのまま外部の運営者に渡るリスクが生まれます。

これは普通のテキストとは違う性質のリスクで、JWT は本質的に 認証情報そのもの です。アクセストークンが漏れた瞬間、そのトークンが有効期限内なら攻撃者は API に対して正規ユーザーとしてリクエストできます。多くの認証システムは漏洩したトークンを失効させる手段を持っていますが、それは「漏れたと気付いてから」の話で、デバッグのつもりで貼ったトークンが運営者のログに残っているとは普通気付きません。だからこそ、デバッグ目的のデコードこそブラウザ内で完結させる価値があります。

jwt-decode はトークンも結果もタブの外に出しません。Base64URL のデコードは atob + TextDecoder、JSON パースは JSON.parse、いずれもブラウザ標準の同期 API で、ネットワーク I/O は介在しません。ソースは GitHub で公開しており、DevTools の Network タブで通信ゼロを確認できます。「トークンを貼った瞬間にどこにも送られていない」が自分の目で確認できる状態は、認証情報を扱うデバッグ作業のデフォルトとして妥当な選択肢です。