JWT デコーダー
JWT(JSON Web Token)をブラウザ上でデコードし、ヘッダー・ペイロード・署名を可視化します。iat / exp / nbf は日時に自動変換されます。
Header
Payload
Signature
※ 署名検証には秘密鍵・公開鍵が必要なため、当ツールではデコードのみ行います。
JWT の構造について
JWT は header.payload.signature の3つのパートをドット(.)で連結した文字列です。ヘッダー・ペイロードは Base64URL エンコードされた JSON、署名はヘッダーで指定したアルゴリズム(HS256 / RS256 など)で生成されています。
主要なクレーム: iss(発行者)、sub(主題)、aud(受信者)、exp(有効期限)、nbf(有効開始日時)、iat(発行日時)、jti(JWT ID)
📖 つまずきやすいポイント
JWT のヘッダー・ペイロード・署名を分解して表示し、exp や iat のような時刻のクレームを日時に変換します。処理はブラウザ内で完結し、署名の検証は行いません (鍵が必要なため)。ここで押さえておくべきなのは、「デコードできる」ということは「中身が誰にでも読める」ということだという点です — JWT のペイロードは暗号化されておらず、単に Base64URL で符号化されているだけです。
| ケース | 何が起きるか | どうする |
|---|---|---|
| ペイロードに機密を入れてしまう | Base64URL は符号化であって暗号化ではありません — このページがそうしているように、鍵を持たない誰でも中身を読めます。それでも「署名されているから安全」という誤解は根強く、ペイロードに個人情報・内部の権限構造・社内 ID・ときにはメールアドレスと生年月日をまとめて入れてしまう設計が見られます。JWT はブラウザの localStorage や Cookie に保存され、ログにも残り、URL に載ることもあります — 中身は「公開情報として扱われる」と考えるのが正確です。 |
ペイロードには「識別子」だけを入れ、中身はサーバーで引いてください — ユーザー ID とロール名程度に留め、氏名・メールアドレス・住所は入れません。暗号化が必要なら JWE (JSON Web Encryption) という別の仕様がありますが、その前に「そもそも JWT に入れる必要があるか」を問い直してください — 多くの場合、必要なのは「誰であるか」だけで、「何者であるか」はサーバーが知っていれば十分です。判断の基準は単純で、「その値がアクセスログに平文で出ても構わないか」です — 構わないなら入れてよく、困るなら入れてはいけません。 |
| デコードしただけで中身を信じてしまう | 署名を検証しなければ、JWT は「ユーザーが自由に書き換えられる文字列」にすぎません。デコードして role: "admin" を読み、そのまま権限判定に使うコードは、攻撃者が自分でその値を書いたトークンをそのまま受け入れます。歴史的に有名な失敗が 2 つあり、1 つは alg: "none" 攻撃 — ヘッダーのアルゴリズムを none に書き換え、署名を空にすると、それを素直に受け入れる実装があったためです。もう 1 つは HS256 と RS256 の取り違えで、公開鍵を HMAC の共有鍵として使わせることで、公開情報だけで有効な署名を作れてしまいます。 |
検証は必ずライブラリの検証関数で行い、許可するアルゴリズムを明示的に固定してください — jwt.verify(token, key, { algorithms: ["RS256"] }) のように書きます。この引数を省略すると、ヘッダーの alg を信じる実装があります — 攻撃者が書き換えられる値を、検証の方式の決定に使ってはいけません。デコードだけを行う関数 (jwt.decode のような名前のもの) を認可の判断に使わないでください — 名前が似ているので混同されますが、これは検証を行いません。用途はデバッグ表示だけです。実装を書く前に、そのライブラリの「検証する関数」と「デコードするだけの関数」を必ず確認してください。 |
| ログアウトしたのにトークンが使える | JWT はステートレスであることが設計上の利点であり、同時に最大の制約です。サーバーはトークンを保存していないので、発行したトークンを個別に無効化する手段がありません — ログアウトとは実際には「クライアント側でトークンを捨てる」ことにすぎず、そのトークンをコピーして持っていた者は、有効期限まで使い続けられます。同じ理由で、権限を剥奪しても、既に発行済みのトークンには古い権限が書かれたままです。「退職者のアクセスを止めたはずなのに 1 時間使えた」というのはこれです。 | 有効期限を短くし、リフレッシュトークンと組み合わせてください — アクセストークンは 15 分程度にし、更新にはサーバー側で管理するリフレッシュトークンを使います。この構成なら、リフレッシュトークンを無効化することで最大 15 分で権限が切れます。即時の失効が要件なら、ブロックリスト (失効させたトークンの ID を保存し、検証時に照合) が必要です — ただしこれはステートを持つということなので、JWT を使う利点の一部を手放すことになります。判断はここが分岐点で — 即時失効が本当に要るなら、素直にセッション ID とサーバーサイドセッションを使うほうが単純で確実です。JWT が向くのは、複数のサービスをまたぐ認証や、検証だけを分散させたい場合です。 |
時刻のクレームは「秒」です。exp・iat・nbf はいずれも Unix 秒で、ミリ秒を入れると有効期限が 5 万年後になり、実質的に無期限のトークンができあがります — JavaScript の Date.now() がミリ秒を返すため、Date.now() + 3600000 のように書いてそのまま exp に入れる間違いは非常によく起きます (正しくは Math.floor(Date.now() / 1000) + 3600)。デコード結果の日時が遠い未来になっていたら、この間違いを疑ってください — このページが時刻を日時に変換して表示しているのは、まさにそれを目で確認するためです。もう 1 点、サーバー間の時計のずれに備えて、nbf と exp の検証には数十秒の許容 (leeway) を設けてください — 主要なライブラリにはそのオプションがあります。最後に運用上の注意として、有効期限内の本番トークンを、外部のオンライン JWT デコーダーに貼らないでください — それは認証情報そのものであり、貼った先のサーバーのログに残れば、そのまま他人がなりすませます。このページはブラウザ内で完結しますが、その保証は開発者ツールの Network タブで確認する習慣を持ってください。
📖 使い方
-
1
JWT をコピーAPI のレスポンスや Authorization ヘッダから JWT 文字列を取得します。
-
2
入力欄に貼り付けページ上部のテキストエリアに JWT をペーストすると、自動的にデコードが実行されます。
-
3
ヘッダー・ペイロードを確認アルゴリズム (alg)・発行者 (iss)・有効期限 (exp) などのクレームを可視化して確認できます。
❓ よくある質問
JWT とは何ですか?
署名検証はできますか?
入力した JWT はサーバーに送信されますか?
exp が期限切れの場合どう対処すれば?
🐛 このツールで問題が発生しましたか?
完全無料・登録不要。再現手順だけでも結構です。届いたご報告は運営者に直接届き、修正の参考にします。
ご報告ありがとうございます!
運営者に届きました。改善の参考にさせていただきます。