JWT(JSON Web Token)は、JSON で表した情報(クレーム)を、改ざんを検知できる形でやり取りするためのトークン形式です。header.payload.signature の3部構成で、それぞれを base64url でエンコードしてピリオド(.)でつなぎます。サーバ側にセッションを持たないステートレス認証や API の認可で広く使われます。本記事では JWT の構造・各部の中身・署名・「ペイロードは暗号化ではない」という重要な注意点・使いどころ・セキュリティ上の落とし穴を正確に整理します。
1. JWT とは — 3部構成と base64url
JWT は、JSON で表したクレーム(claim、主張・情報)を、安全にやり取りするためのコンパクトなトークン形式です。最もよく使われるのは署名付きの形(JWS)で、次の 3 つの部分から成ります。
- header(ヘッダ):トークンの種類と署名アルゴリズムを表すメタ情報。
- payload(ペイロード):実際に伝えたいクレーム(誰が・いつまで有効か など)。
- signature(署名):ヘッダとペイロードに対する署名で、改ざんを検知する。
この 3 部はそれぞれ base64url(URL で安全に扱える Base64 の変種)でエンコードされ、ピリオド(.)で連結されます。つまり全体は次の形です。
base64url(header).base64url(payload).base64url(signature)
実際のトークンは、たとえば次のような 3 つのパートに分かれた文字列になります。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0Iiwicm9sZSI6ImFkbWluIn0.abc123signature
+ を -、/ を _ に変え、末尾の = パディングを省きます。URL やヘッダにそのまま埋め込めるようにするための工夫です。base64url については Base64 の解説記事もあわせてご覧ください。
2. 各部の中身 — ヘッダのクレームと登録クレーム
ヘッダとペイロードは、デコードするとどちらもただの JSON オブジェクトです。中身を順に見ていきます。
ヘッダ(header)
ヘッダは主に 2 つのフィールドを持ちます。
alg:署名に使うアルゴリズム(例:HS256、RS256、ES256)。typ:トークンの型。通常はJWT。
例:{ "alg": "HS256", "typ": "JWT" }
ペイロード(payload)と登録クレーム
ペイロードには任意のクレームを入れられますが、仕様で意味が定められた登録クレーム(Registered Claims)がいくつかあります。相互運用のため、これらは名前と意味を守って使います。
| クレーム | 意味 | 備考 |
|---|---|---|
iss | 発行者(issuer) | トークンを発行した主体 |
sub | 主体(subject) | トークンが表す対象(例:ユーザーID) |
aud | 受信者(audience) | このトークンを受け取るべき相手 |
exp | 有効期限(expiration) | この時刻以降は無効。UNIX 秒 |
nbf | 有効開始(not before) | この時刻より前は無効。UNIX 秒 |
iat | 発行時刻(issued at) | トークンを発行した時刻。UNIX 秒 |
例:{ "sub": "1234", "role": "admin", "iss": "https://auth.example.com", "exp": 1924905600 }
このように、ペイロードには「誰が(sub)」「どんな権限を持ち(role などの独自クレーム)」「いつまで有効か(exp)」といった、認可に必要な情報を載せます。
3. 署名 — HMAC(共有鍵)と RSA・ECDSA(公開鍵)
署名は JWT の心臓部です。ヘッダとペイロードを base64url でつないだ文字列に対して署名を計算し、3 番目のパートとして付けます。署名方式は大きく 2 系統あります。
HMAC(HS256 など)— 共有鍵
HMAC は、発行者と検証者が同じ秘密鍵(共有鍵)を持つ方式です。HS256 は SHA-256 を用いた HMAC を指します。署名する側も検証する側も同じ鍵を知っている必要があるため、発行と検証を同じ信頼境界(同一サービス)で行う場合に向きます。
RSA・ECDSA(RS256・ES256 など)— 公開鍵
RSA や ECDSA は公開鍵暗号を使う方式です。発行者は秘密鍵で署名し、検証者は対応する公開鍵で検証します。検証側に秘密鍵を渡さなくてよいため、発行者と検証者が別のとき(例:認証サーバが発行し、複数の API が公開鍵で検証する)に適しています。
| 観点 | HMAC(HS256) | RSA / ECDSA(RS256・ES256) |
|---|---|---|
| 鍵の種類 | 共有鍵(1 つの秘密鍵) | 秘密鍵 + 公開鍵のペア |
| 署名する人 | 共有鍵を持つ者 | 秘密鍵を持つ発行者 |
| 検証する人 | 同じ共有鍵を持つ者 | 公開鍵を持つ誰でも |
| 向いている構成 | 発行と検証が同一サービス | 発行者と検証者が分かれる |
4. ペイロードは暗号化ではない — 機密を入れない
JWT で最も誤解されやすい点です。標準的な JWT(JWS)のペイロードは暗号化されていません。base64url は単なるエンコードであり、鍵がなくても誰でもデコードして中身を読めます。
したがって、次のような機密情報をペイロードに入れてはいけません。
- パスワードやその断片。
- クレジットカード番号などの決済情報。
- 外部に漏れて困る個人情報・内部情報。
もし内容そのものを隠したい場合は、署名だけの JWS ではなく、ペイロードを暗号化する JWE(JSON Web Encryption)を使う必要があります。多くの場面で使われている「JWT」は JWS であり、暗号化はされていない点を必ず押さえてください。
5. 用途 — ステートレス認証と API 認可
JWT の最大の利点は、必要な情報をトークン自身が運ぶ(自己完結している)ことです。これにより、サーバ側でセッションを保持しなくても認証・認可が成立します。
- ステートレス認証:ログイン後にサーバが JWT を発行し、クライアントは以後のリクエストでそれを送ります。サーバは署名を検証するだけで利用者を識別でき、セッションストアを参照する必要がありません。
- API 認可:トークンに権限(
roleやスコープ)を載せ、API はそれを見てアクセス可否を判断します。マイクロサービス間でも公開鍵で検証すれば、各サービスが独立に認可できます。 - サービス間・第三者連携:OAuth 2.0 / OpenID Connect ではアクセストークンや ID トークンの表現に JWT がよく使われ、発行者が署名・受信者が公開鍵で検証する形で安全に情報を受け渡せます。
exp)と、別途用意するリフレッシュトークンや失効リストの仕組みで補うのが一般的です。
6. セキュリティ注意 — alg=none・有効期限・保管場所
JWT は正しく使えば強力ですが、実装を誤ると認証を丸ごと破られます。代表的な注意点を挙げます。
alg=none攻撃:ヘッダのalgをnoneに書き換え、署名を空にしたトークンを「署名検証不要」として受理させる古典的な攻撃です。検証側で許可するアルゴリズムを固定し、noneや想定外のalgを必ず拒否してください。攻撃者がヘッダのalgを切り替えて検証ロジックを混乱させる(例:RS256 を HS256 と誤認させ、公開鍵を共有鍵として扱わせる)手口にも注意が必要です。- 有効期限を必ず検証する:
exp(および必要ならnbf・iat)を検証側で確認し、期限切れトークンを拒否します。有効期限は短く設定し、漏えい時の被害を最小化します。 - 保管場所:ブラウザでトークンを保持する場合、
localStorageは XSS で読み取られる危険があります。用途に応じてHttpOnly属性付きの Cookie などを検討し、あわせて CSRF 対策も行います。いずれにせよ通信は HTTPS 必須です。 - 署名は必ず検証する:当然ですが、署名検証を省略したり、検証エラーを握りつぶしたりしてはいけません。
aud・issも検証し、自分宛て・信頼できる発行者のトークンだけを受理します。
よくある質問(FAQ)
JWTとは何ですか?
JWT(JSON Web Token)は、JSON で表したクレーム(情報)を、改ざんを検知できる形でやり取りするためのトークン形式です。header(ヘッダ)・payload(ペイロード)・signature(署名)の3部構成で、それぞれを base64url でエンコードし、ピリオド(.)で連結した文字列になります。サーバ側にセッションを保持しないステートレスな認証や、API の認可情報の受け渡しに広く使われます。
JWT のペイロードは暗号化されていますか?
いいえ。標準的な JWT(JWS)のペイロードは暗号化ではなく base64url でエンコードされているだけです。鍵がなくても誰でもデコードして中身を読めます。署名は改ざんを検知するためのもので、内容を秘匿するものではありません。したがってパスワードやクレジットカード番号などの機密情報をペイロードに入れてはいけません。内容自体を隠したい場合は、暗号化を行う JWE を使う必要があります。
JWT の署名の役割は何ですか?
署名は、トークンが正規の発行者によって作られ、途中で改ざんされていないことを検証するためのものです。HMAC(HS256 など)では発行者と検証者が同じ共有鍵を持ち、RSA や ECDSA(RS256・ES256 など)では発行者が秘密鍵で署名し、検証者は対応する公開鍵で検証します。署名が一致しないトークンは無効として拒否します。署名は完全性と真正性を保証しますが、ペイロードの内容を暗号化して隠すわけではありません。