本文へ移動
ZEKILO Dev
エンコード

JWTのデコードと署名検証の違い|exp・iatの読み方

2026.10.03 更新 · 4分で読めます

JWTのデコードはBase64URLを読むだけで、署名の検証ではありません。ヘッダーとペイロードの構造、exp・iat・nbfの時刻の読み方、alg: noneのトークンを受け入れてはいけない理由をRFC 7519をもとにまとめました。

JWTデコーダーをすぐに使う

デコードは署名の検証ではありません。JWTの内容は誰でも読めるため、秘密情報を入れないでください。JWTデコーダーにトークンを貼り付けると、ヘッダーとペイロード、有効期限を確認できますが、それは読んでいるだけです。そのトークンを信頼してよいかどうかは、受け取ったサーバーが鍵で署名を検証し、expやaudなどのクレームを確認して初めて決まります。

JWTは3つの部分でできている

署名付きのJWTはヘッダー.ペイロード.署名という形で、3つの部分はそれぞれパディングなしのBase64URLで書かれています(RFC 7515)。例として、HS256アルゴリズムと例示用の秘密鍵zekilo-secretで署名したトークンを見てみます。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlpFS0lMTyIsImlhdCI6MTc2NzIyNTYwMCwiZXhwIjoxNzY3MjI5MjAwfQ.218DR4r7DRNkKO3XJcQYXE0ztwbqxYMeQpkIp9S18oE
部分 デコードした内容
ヘッダー {"alg":"HS256","typ":"JWT"}
ペイロード {"sub":"1234567890","name":"ZEKILO","iat":1767225600,"exp":1767229200}
署名 32バイトのHMAC-SHA256の値(Base64URLで43文字)

ヘッダーとペイロードは暗号化されていません。Base64URLで書かれたJSONなので、鍵がなくても読めます。内容まで暗号化したJWTはJWEという別の形式で、ドットで区切った部分が5つあります。

デコードと検証の違い

項目 デコード 署名検証
行うこと Base64URLを戻してJSONを読む 鍵を使って署名を確かめる
必要なもの なし 秘密鍵(HS256)または公開鍵(RS256・ES256)
わかること トークンに書かれている内容 内容が、鍵を持つ側が署名したままであること
できる人 誰でも 鍵を持つ側

署名の対象は、BASE64URL(ヘッダー)、ドット、BASE64URL(ペイロード)をつなげた文字列です(RFC 7515)。上のトークンの前半2つの部分についてzekilo-secretでHMAC-SHA256を計算すると、3つ目の部分と同じ値になります。ペイロードが1文字でも違えば計算結果も変わるため、検証する側は内容が変えられたことに気づけます。

検証は署名の確認だけでは終わりません。受け取る側は、有効期限(exp)、発行者(iss)、対象(aud)も確認する必要があります。RFC 7519は、audクレームがあるのにその値に自分が含まれていない場合、トークンを拒否しなければならないと定めています。

exp・iat・nbfの読み方

この3つのクレームの値はNumericDate、つまり1970-01-01T00:00:00Zからの秒数です(RFC 7519 2節)。ミリ秒ではありません。JavaScriptのDate.now()はミリ秒を返すので、1000で割ってから比較します。

クレーム 意味 例のトークンの値 日時
iat 発行した時刻 1767225600 2026-01-01 00:00:00 UTC(JST 09:00)
exp この時刻以降は受け入れてはならない 1767229200 2026-01-01 01:00:00 UTC(JST 10:00)
nbf この時刻より前は受け入れてはならない なし —

expからiatを引くと3,600秒なので、このトークンの有効期間は発行から1時間です。RFC 7519は、サーバー間の時計のずれを考慮して、通常は数分以内の猶予を設けてもよいとしています。登録済みクレームはどれも任意なので、トークンに入っていないこともあります。

数値を日時に直すときは、UNIX時間変換に1767225600を入力すると、2026-01-01T00:00:00Z、日本時間では2026-01-01 09:00:00と表示されます。JWTデコーダーもexp・nbf・iatの横に日時を表示し、expを過ぎていれば期限切れの警告を出します。この表示はブラウザの時計と比べた参考情報で、検証の代わりにはなりません。

alg: noneとアルゴリズムの確認

RFC 7519 6節は、署名のないJWT(Unsecured JWT)を定義しています。ヘッダーのalgがnoneで、署名の部分が空になっています。別の手段で保護されている場合のための形式であり、通常の認証トークンとして受け入れるものではありません。

  • RFC 7518 3.6節:実装は、署名のないトークンを既定で受け入れてはなりません。
  • RFC 8725 3.1節:ライブラリは、呼び出し側が許可するアルゴリズムの一覧を指定できるようにし、それ以外のアルゴリズムを使ってはなりません。

したがってサーバーは、受け入れるアルゴリズムを自分のコードで決めておき、トークンのヘッダーに書かれたalgにそのまま従わないようにします。JWTデコーダーは、algがnoneのトークンに署名がないという警告を表示します。

実務で守ること

  • ペイロードにパスワード、マイナンバー、カード番号などの情報を入れません。
  • トークンは、持っている人が使える通行証です。本番環境のトークンをチャット、課題管理ツール、ログに貼り付けません。
  • 検証は、サーバー側で実績のあるライブラリを使って行います。アルゴリズムを決めておき、署名とexp・nbf・iss・audを確認します。
  • クライアントでデコードした値は、画面表示だけに使います。権限の判断は、サーバーが検証した結果で行います。

この記事に関連するツール

出典と基準

ほかのガイド