JWTデコード
JWTデコーダーは、JSON Web Tokenのヘッダとペイロードをブラウザ内で読み取り、見つかった内容を解説します。署名アルゴリズム、すべてのクレームとその意味、実在の日付にデコードされた有効期限です。署名の検証は決して行いません。検証するには、トークンを鍵の持ち主に送らなければならないからです。
JWTデコードはどう動きますか?
JSON Web Tokenは、ドットでつながった3つのbase64urlエンコード済みセグメントです:header.payload.signature。最初の2つはJSONオブジェクトで、暗号化されていません——base64urlはエンコードであって暗号ではありません。トークンを手にした人は、中のすべてのクレームを読めます。だからこそ、JWTのペイロードにパスワード、カード番号、内部データベースIDを入れるのは、定期的に行われ、発見が遅れるミスなのです。
したがってデコード自体は単純です。ドットで分割し、最初の2セグメントをbase64urlデコードし、それぞれをJSONとしてパースします。手間がかかるのは、素朴なデコーダーを壊す細部です。JWTのセグメントはパディングなしのbase64url(RFC 7515 §2)なので、=パディングを要求するデコーダーは、実際のトークンの大半を拒否してしまいます。アルファベットは+と/の代わりに-と_を使うため、標準のBase64デコーダーは、ランダムなバイトがたまたま何を符号化したか次第で、全トークンの半分ほどで失敗します。
このツールがデコードに加えて提供するのは、解釈です。RFC 7519の登録済みクレームには、それぞれの意味を示す注釈が付きます。exp、nbf、iatはNumericDate——Unixエポックからの秒数——なので、実在のタイムスタンプと相対時間として表示されます。“1757546000”は対応のしようがないのですが、“4時間前に期限切れ”なら対応できます。
さらに、インシデントにつながる具体的な問題を探します。algがnone、空の署名セグメント、expを持たないトークン、発行者の時計が進んでいるためにまだ有効になっていないトークン、audが欠けていて、同じ発行者を信頼する別のサービスに対してトークンをリプレイできてしまう、といったものです。
そして意図的に、検証の手前で止まっています。署名の確認には発行者の秘密鍵か公開鍵が必要で、Webページがそれを手に入れる唯一の方法は、トークンをどこかに送ることです。それを提供すれば、生のクレデンシャルをこのページに貼っても安全だとできる唯一の性質が失われます。
トークンセグメント
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 .eyJzdWIiOiJ1c3JfOGYyYTFiIiwiZXhwIjoxNzU3NTQ2MDAwfQ .3Zc0Kz1qHhVQ9oFmR2sT7xYbN4dJwEuLpAiCgXvKmO8
デコード結果
header { "alg": "HS256", "typ": "JWT" }
payload { "sub": "usr_8f2a1b", "exp": 1757546000 }
exp 2026-09-10 21:53:20 UTC (expired)
sub Subject — who the token is aboutJWTデコードが対応するオプションとエッジケースは?
| パラメータ | 型 | デフォルト | 動作とエッジケース |
|---|---|---|---|
| alg | 文字列 | 必須 | 署名アルゴリズム(ヘッダー内)。HS*は共有シークレットを使ったHMAC、RS*/PS*はRSA、ES*はECDSA、EdDSAはEd25519です。"none"という値はエラーとしてフラグされます。トークン自体からのalgを信頼するライブラリは、誰でもトークンを偽造できる可能性があります。 |
| typ / kid | 文字列 | 任意 | typは慣例的に"JWT"です。kidはどのキーがトークンに署名したかを特定し、発行者がキーをローテーションしても一度にすべてを無効にせずに済むようにします。 |
| exp | NumericDate | 任意 | Unixエポックからの秒数(ミリ秒ではなく、ISO文字列でもありません)。ここではUTCタイムスタンプと相対時間にデコードされます。expがないトークンは自体では期限切れにならず、失効によってのみ停止できます。 |
| nbf | NumericDate | 任意 | Not-before(有効開始時刻)。まだ有効でないトークンは、発行サーバーと読み取りマシン間のクロックスキューが原因であることがほとんどで、意図的な遅延ではありません。 |
| aud | 文字列 | 文字列[] | 任意 | 意図された受信者。サービスは、対象が自分自身ではないトークンを拒否しなければなりません。audがないと、あるサービス用に発行されたトークンを、同じ発行者を信頼する別サービスで再利用されてしまう可能性があります。 |
| セグメントエンコーディング | base64url | パディングなし | RFC 7515 §2では、パディングを削除したURLセーフアルファベット(-と_)が使用されます。標準のBase64デコーダーは、バイトが+または/を生成するトークンでは失敗します。これが、あるツールではデコードできるのに別のツールではできない理由です。 |
| 署名 | base64url | 検証しない | 表示されますが、チェックはされません。検証には発行者のキーが必要です。キーを取得するということは、トークンを送信することを意味します。空の署名セグメントはフラグされます。なぜなら、完全に整合性保護がないことを意味するからです。 |
| 入力サイズ | bytes | 8 MB | サイト全体で共有されるメインスレッドの上限です。実際のトークンは数キロバイト程度です。この制限があるので、間違ったものを貼り付けた場合にタブがロックされることはありません。 |
よくある質問
本物のJWTをこのページに貼り付けても安全ですか?
デコードは完全にブラウザ内で行われ、トークンが送信されることはありません。DevToolsを開き、Networkパネルに切り替えてトークンを貼り付けてみてください。それを運ぶリクエストは何も表示されないはずです。このページは、サーバーに送信するタイプのデコーダーよりも明確に安全です。そのようなサーバーでは、トークンがアクセスログに残ってしまいます。残る注意点はこのサイトの話ではありません。管理下にないマシンのブラウザに貼り付けたクレデンシャルは、後でローテーションすべきというものです。
署名を検証できないのはなぜですか?
検証には鍵が必要だからです。HS256なら共有シークレット、RS256なら発行者の公開鍵で、通常はJWKSエンドポイントから取得します。ブラウザのページがそのどちらかを行うには、トークンかシークレットをどこかに送るしかなく、それではこのページを安全に使える性質が壊れてしまいます。検証は、鍵がすでにあるあなたのサービスの中で行うべきものです。
トークンはここではデコードできるのに、自分のライブラリには拒否されます。なぜですか?
デコードできることと受け入れられることは、別の問題です。最も多い原因は次のとおりです。トークンの有効期限が切れている(expの行を確認してください——このツールは実在の日付で表示します)。オーディエンスがサービスの期待と一致していない。発行サーバーの時計が進んでいて、nbfが未来になっている。あるいは、サービスに設定された鍵に対して署名が検証できない。多くの場合これは、発行者が鍵をローテーションし、kidがキャッシュがまだ取り込んでいない鍵を指しているせいです。
alg: noneとは何で、なぜエラーとしてフラグが立つのですか?
トークンが未署名だという意味です。危険なのは値そのものではなく、検証器がそれをどう扱うかです。歴史的に、一部のJWTライブラリはトークンからalgを読み、それに応じて検証方式を選んでいました。そのため攻撃者は、有効なトークンを取り、アルゴリズムをnoneに変え、署名を剥がして、受け入れさせることができました。正しい検証器は、期待するアルゴリズムを自分自身の設定から決め、トークンの主張を無視します。
JWTは暗号化されていますか?
いいえ。標準のJWT(JWS)は署名であって、暗号化ではありません——署名はペイロードが改ざんされていないことを証明するだけで、内容を隠す働きはありません。すべてのクレームは、トークンを手にした人なら読めます。それをまさにこのページが実演しています。内容を隠す必要があるなら、必要なのはJWEです。JWEはセグメントが3つではなく5つで、復号鍵なしでは読めません。
有効期限が切れたトークンもデコードできますか?
はい。有効期限はペイロード内のクレームであって、エンコードの性質ではないので、期限切れのトークンも有効なトークンとまったく同じようにデコードできます。このツールはそれを読み、いつ期限切れになったか、どれほど前に切れたかを教えてくれます。断続的な401が権限の問題ではなくトークンの寿命の問題だと確認する最短の方法になることが、たいていです。