⌘K でツールを切替
SECURITY

JWTトークンデコーダー

JSON Web Tokenをデコードして内容を確認します。

local
jwt-decoder

Decoding only — the signature is not verified. Nothing is sent anywhere.

§01 このツールについて

概要

JWT はドットで区切られた base64url の 3 つの部分です。署名方法を記したヘッダ、 クレームのペイロード、そして前 2 つに対する署名です。このエンコードは暗号化では ありません。トークンを持っている者は誰でも中のすべてのクレームを読めます。 ペイロードに何かを入れる前に、この点を頭に入れておく価値があります。

このツールは最初の 2 つの部分をデコードして整形し、3 つの時刻クレームを取り出して Unix 秒から読める日時に変換します。署名は検証しません。それが機能の欠落では なく正しい判断である理由は下記のとおりです。

使い方

  1. トークンを貼ります。Bearer より後ろの部分です(スキーム自体は JWT の 一部ではありません)。
  2. header でアルゴリズムと、あれば鍵 ID を確認します。
  3. payload でクレームを読みます。
  4. iatnbfexp と失効判定の表を確認します。

登録済みクレーム

クレーム名称補足
iss発行者誰が発行したか。サーバー側で許可リストと照合すべき値
sub主体誰についてのトークンか。通常はメールではなく安定した利用者 ID
aud受け手向けのトークンか。別の受け手向けのトークンは拒否しなければならない
exp失効時刻Unix 秒。これを過ぎたら拒否
nbf有効開始Unix 秒。これより前は拒否
iat発行時刻Unix 秒。「N 時間より古ければ再認証」に使える
jtiJWT ID一意な ID。失効管理やリプレイ検査に使う

7 つすべて仕様上は任意です。exp を持たないトークンは自力では失効しません。 そういうトークンを見たときに気づく価値のある設計判断です。

署名検証を提供しない理由

署名の検証には鍵が必要です。HS256 なら共有秘密、RS256ES256 なら公開鍵です。 対称鍵の場合、検証する鍵は署名する鍵と同一です。つまり検証機能を提供する ページは、「あなたのシステム向けのトークンを誰でも発行できてしまう資格情報」を 貼るよう求めることになります。これを安全に作る方法は存在しません。

それでもデコードには価値があります。JWT のデバッグの大半は「このトークンは 実際に何と言っているのか」です。受け手が違う、スコープが無い、exp が 5 分前、 sub がコードの想定する UUID ではなくメールアドレス。これらはすべて鍵なしで 見えます。

デコードで分からないのは、そのトークンが本物かどうかです。受け取った JWT は、 サーバーが信頼する鍵で署名を検証するまでは、事実ではなく主張です。

alg は検証側が委ねてよい判断ではない

ヘッダの alg送信側が使ったものを記述しています。alg を読んでそれに 応じてアルゴリズムを選ぶ検証実装は、攻撃者が制御する入力を信用していることに なり、古典的な破り方が 2 つ生まれます。

  • alg: none。unsecured JWT は仕様上正当です。これを尊重する検証実装は、 空の署名を付けた任意のペイロードを受け入れます。
  • RS256HS256 に差し替える。ライブラリが公開鍵を HMAC の秘密鍵として 使ってしまう場合、公開鍵を知る攻撃者(公開されています)は、こちらが受け入れる トークンを署名できます。

どちらも暗号の問題ではなく設定の問題です。期待するアルゴリズムを検証側で固定し、 それ以外を拒否してください。トークンから読み取ってはいけません。

ブラウザでトークンをどこに置くか

トークンをデコードして中身が読めることに気づいた人が、必ず次に尋ねる点です。 短く言えば、JWT はベアラ資格情報なので、それを読めるものはそれを使えます。

localStorage は同一オリジンの任意のスクリプトから読めるので、XSS が起きれば トークンも持っていかれます。一方で自動送信はされないので、それ経由で CSRF される ことはありません。ある種類の不具合を別の種類と交換しているだけです。

HttpOnly な Cookie はスクリプトから一切読めないので、XSS では盗めません。 ただし自動送信されるのでSameSite=Lax または StrictSecure が必要で、 状態を変えるエンドポイントには独自の CSRF 対策が必要です。

ブラウザアプリでの通例の結論は、寿命の短いアクセストークンをメモリだけに保持し、 HttpOnly / Secure / SameSite なリフレッシュトークン Cookie から更新する形です。 これなら XSS が取れるのは数分の寿命のトークンで、長寿命の秘密は JavaScript から 到達できません。

どれを選んでも、実際に効いているのは exp です。失効リストを持たない 1 時間の トークンは、盗まれてから 1 時間有効で、クライアント側の工夫で変わるものは 何もありません。

使用例

  • 説明できない 401 — デコードして aud を確認します。ある API 向けに発行した トークンを別の API に提示するのが最も一般的な原因で、エラーメッセージが そう言うことはまずありません。
  • 断続的な 401expiat を比べます。短い寿命とトークンをキャッシュする クライアントの組み合わせは、構造上断続的になります。
  • 通るはずの権限が通らない — ペイロードの scoperoles を見ます。 クレームが無ければ、問題は認可コードではなく発行側にあります。
  • トークンに何を入れているかの棚卸し — 自社のトークンをデコードします。 メールアドレス・内部 ID・機能フラグなど、そこにあるものはすべて、 トークンを持つ者(保存先のブラウザを含む)から読めます。

注意事項

デコード前にパディングを補います。base64url は通常パディングを省くためです。 ログからコピーしたトークンはパディングが付いていることもあり、どちらの形でも 動きます。

失効判定はローカルの時計を使うので、権威ではなく便宜です。特定の時点と 比較したい場合は、生の exp の値を Unix タイムスタンプ変換 にかけてください。

ペイロードは原理上は常に JSON とは限りません(仕様は任意のコンテンツタイプを 許します)が、実際の JWT はすべて JSON オブジェクトを運んでおり、JSON として 解析できないペイロードは隠さずに生のテキストとして表示します。

FAQ
署名を検証してくれますか?
いいえ。これは意図的です。検証には署名鍵が必要で、署名鍵を Web ページに貼ることは、このツールが決して促してはならない行為です。デコードはトークンが何を主張しているかを教えますが、その主張が正しいかを判定できるのは自分のサーバーだけです。
トークンはどこかに送信されますか?
いいえ。ドットで分割し、ページ内で base64url デコードします。ネットワーク通信は発生しません。それでも、どこかに貼ったトークンは使用済みとして扱ってください。クリップボード履歴やブラウザのセッションに残ったベアラトークンは、もう完全には管理できていない資格情報です。
API はまだ受け付けるのに EXPIRED と出るのはなぜですか?
判定は exp を自分の PC の時計と比べています。時計がずれている場合や、発行側がクロックスキュー(数分は一般的です)を許容している場合、両者の判断は食い違い得ます。権威ある数値はトークン自身の exp の値で、ラベルは便宜的なものです。
2 つの部分しかないトークンもデコードできますか?
できます。2 部分は有効な unsecured JWT(alg: none)か、署名を付けずに貼ったトークンです。必要なのはヘッダとペイロードで、署名は使いません。
ペイロードが意味不明です。何が起きていますか?
多いのは、署名ではなく暗号化されたトークン(JWE。5 部分になります)であるか、何かが再エンコードした場合です。行を折り返す端末からのコピーや、エスケープされた JSON 文字列からのコピーが典型です。JWS のペイロードは素の base64url で、常に JSON にデコードできます。