WEB PROTOCOL

JWTの作り方(JSON Web Token)

認証トークンの作成から署名検証までの流れをインタラクティブに可視化します

INTERACTIVE VISUALIZATION
Header
Payload
Signature
JWTが作られるのは、ユーザーがIDとパスワードでログインに成功した直後です。サーバーは「この人は認証済み」という情報をトークンに詰めてブラウザに返します。以下のステップで、サーバーがJWTトークンを組み立てる過程を見ていきます。
シナリオ
一般ユーザー「田中太郎」がログインした場合の標準的なJWTです。role: "user" で通常権限が付与され、署名も有効期限も正常です。最後のステップで検証が成功します。
ステップ1 / 8
自動再生でJWTの構造と検証の流れを順番に確認できます
AlgorithmHS256
署名アルゴリズム
Token Length200
文字数
Signature
署名ステータス
Phase1 / 8
初期状態
JWTは、ユーザーがログインしたときにサーバーが発行する「認証済み証明書」のような文字列です。このトークンは3つのパートで構成されています。① Header(ヘッダー): 署名の方式を指定する設定情報② Payload(ペイロード): ユーザーIDや権限などの実際のデータ③ Signature(署名): ①と②が改ざんされていないことを保証する検証コードこの3つをドット(.)で繋いだ1本の文字列が、JWTトークンです。これからステップごとに、トークンの作成から検証までの流れを見ていきます。
TOKEN STRUCTURE
HEADER
{
  "alg": "HS256",
  "typ": "JWT"
}
PAYLOAD
{
  "sub": "user_1234",
  "name": "田中太郎",
  "role": "user",
  "iat": 1709280000,
  "exp": 1709366400
}
VERIFICATION
検証待ち...
解説

1
JWTとは

JWT(JSON Web Token)は、ウェブアプリケーションで「ログイン済みであること」を証明するためのトークンです。誰が作るのか? — サーバー(バックエンド)が作ります。ユーザーがIDとパスワードでログインに成功したとき、サーバーが「この人は認証済みです」という情報を詰め込んだJWTトークンを生成し、ブラウザに返します。いつ使うのか? — ログイン後のすべてのリクエストで使います。ブラウザはサーバーから受け取ったJWTを保存しておき、APIにアクセスするたびに「Authorization: Bearer eyJhbG...」というHTTPヘッダーに添えて送ります。サーバーはこのトークンを検証するだけで、誰からのリクエストかを判断できます。セッションIDと違い、サーバー側でログイン状態を記憶しておく必要がありません(ステートレス)。トークン自体にユーザー情報が含まれているため、データベースを参照せずに認証を確認できます。Auth0、Firebase Authentication、AWS Cognitoなどの認証サービスで広く使われています。

2
JWTの特徴

  • 📦ステートレス:サーバー側でセッション状態を保持しない。トークン自体に必要な情報が含まれる
  • 📋自己完結型:ユーザー情報(claims)がトークン内に含まれているため、毎回DBを参照する必要がない
  • 🛡改ざん検知:署名により内容の改ざんを即座に検知できる。上のツールで「改ざん検知」シナリオを試してみてください
  • 有効期限付き:expクレームにより自動的にトークンが無効化される。上のツールで「有効期限切れ」シナリオで確認できます
  • 暗号化ではない:ペイロードはBase64URLエンコードされるだけで暗号化されない。パスワード等の秘密情報は絶対に入れてはいけない

3
ユースケース

API認証
GitHub API、Stripe API等。Bearer tokenとしてリクエストヘッダーに含める
シングルサインオン(SSO)
Google Workspace等。1回のログインで複数サービスにアクセス
マイクロサービス間通信
サービス間の認証にJWTを使用。各サービスが独立してトークンを検証
モバイルアプリ認証
セッションCookieが使えないモバイル環境でのトークンベース認証

4
用語解説

ヘッダー(Header)
= トークンのメタ情報
アルゴリズム(alg)とトークンタイプ(typ)を格納します。受信側はこの情報を見て、どのアルゴリズムで署名を検証すべきかを判断します。
HEADERalg: HS256
ペイロード(Payload)
= 送りたいデータ本体
クレーム(claims)を格納します。sub(主体)、name、role等のユーザー情報と、iat(発行時刻)、exp(有効期限)等のメタデータを含みます。
PAYLOADsub, name, role
署名(Signature)
= 改ざん防止の証明
秘密鍵で生成されるハッシュ値です。ヘッダーとペイロードの内容が1文字でも変更されると署名が変わるため、改ざんを検知できます。
SIGNATUREHMAC
クレーム(Claims)
= トークンに含まれる主張
sub(主体)、iat(発行時刻)、exp(有効期限)等の予約済みクレームと、name、role等のカスタムクレームがあります。
subexpnamerole
Base64URL
= URL安全なエンコード
JSONを文字列に変換する方式です。暗号化ではないため誰でもデコードできます。通常のBase64から + を - に、/ を _ に置換し、= パディングを省略します。
JSONBase64URLencode / decode
秘密鍵(Secret Key)
= 署名の鍵
サーバーのみが保持する秘密の文字列です。これを知らないと正しい署名を生成できません。攻撃者がペイロードを改ざんしても、秘密鍵なしでは正しい署名を作れません。
SECRET KEYserver only

🔏
JWS(JSON Web Signature)とは

JWT は実は「フォーマットの名前」で、実際のトークンの実装方式として JWS(署名付き)JWE(暗号化)の2種類があります。一般的に「JWT」と言ったときはほぼ JWS のことを指します。

JWS は「中身は誰でも読めるが、改ざんされていないことを署名で保証する」という仕組みです。暗号化ではないので、ペイロードを Base64URL デコードすれば誰でも読めます。

Header{"alg":"HS256"}{"typ":"JWT"}↓ Base64URL.Payload{"sub":"user_123"}{"role":"admin"}↓ Base64URL.SignatureHMAC-SHA256(header + payload,secret_key)署名の計算フローbase64url(header)+base64url(payload)secret_key 🔑HMAC-SHA256 → SignatureHeader か Payload を 1 文字でも変えると Signature が変わる → 改ざん検知
JWS でできること
✓ トークンが改ざんされていないことを検証できる
✓ トークンの発行者が正しいことを検証できる(秘密鍵を持つサーバーだけが署名を作れる)
✓ サーバー側にストアなしで検証できる(秘密鍵だけあればOK)
JWS でできないこと
✕ ペイロードの暗号化(中身は誰でも読める)
✕ パスワードやクレジットカード番号などの秘密情報の保護
JWS vs JWE
JWS(署名)JWE(暗号化)
目的改ざんの検知中身を隠す(暗号化)
中身誰でも読める(Base64URL)復号しないと読めない
構成3パート(Header.Payload.Sig)5パート
使用頻度ほぼこちら(一般的な JWT)まれ(特殊な要件時のみ)
パフォーマンス高速(ハッシュ計算のみ)低速(暗号化+復号)
実務では: 認証トークンとして使う JWT はほぼ 100% JWS です。ペイロードにはユーザー ID や権限など「読まれても問題ないが改ざんされたら困る」情報を入れます。パスワードなどの秘密情報はそもそもトークンに入れません。

5
JWTの構造

JWTトークンは、3つのパートをドット(.)で繋いだ1本の文字列です。見た目は意味不明な英数字の羅列ですが、ドットで区切ると役割がはっきり分かれています。

実際のJWTトークン(色分け)
eyJhbGci....eyJzdWIi....SflKxwRJ...
① HEADER(ヘッダー)
「このトークンをどうやって検証するか」の設定情報です。封筒の表書きのようなもので、中身のデータではなく、処理方法を指定します。
alg: 署名に使うアルゴリズム(HS256 = HMAC-SHA256)typ: トークンの種類(常に "JWT")
{
  "alg": "HS256",
  "typ": "JWT"
}
② PAYLOAD(ペイロード)
トークンの本体。「誰が」「何の権限で」「いつまで有効か」という実際のデータを格納します。これらの項目を「クレーム(claim)」と呼びます。
sub: ユーザーID(誰のトークンか)role: 権限(user / admin 等)iat: 発行日時   exp: 有効期限
⚠ ペイロードは暗号化されません。Base64URLデコードすれば誰でも中身を読めるため、パスワードなどの秘密情報は絶対に入れてはいけません。
{
  "sub": "user_1234",
  "name": "田中太郎",
  "role": "user",
  "iat": 1709280000,
  "exp": 1709366400
}
③ SIGNATURE(署名)
「①と②の内容が改ざんされていない」ことを保証する検証コードです。サーバーだけが持つ秘密鍵を使って生成されるため、攻撃者がペイロードを書き換えても正しい署名を作れません。
署名の計算式: ヘッダーとペイロードをBase64URLエンコードしてドットで繋ぎ、それを秘密鍵でハッシュ化します。上のツールで「改ざん検知」シナリオを試すと、ペイロードを1文字変えただけで署名が不一致になることを確認できます。
HMAC-SHA256(
  base64url(header)
  + "." +
  base64url(payload),
  secret_key
)

6
登録済みクレーム一覧

sub
Subject - トークンの主体(ユーザーID等)
iat
Issued At - トークン発行時刻(Unix timestamp)
exp
Expiration - 有効期限(Unix timestamp)
nbf
Not Before - この時刻より前は無効
iss
Issuer - 発行者
aud
Audience - 対象者
jti
JWT ID - トークンの一意識別子

7
JWT検証の手順

1
トークンを受信
HTTPヘッダーから Authorization: Bearer <token> としてBearerトークンを取得します。
Authorization:Bearer eyJhbG...
2
3パートに分割
ドット(.)で区切ってheader, payload, signatureの3パートに分割します。
header.payload.sig
3
署名を再計算
header + "." + payload を秘密鍵で再署名します。サーバーは秘密鍵を保持しているため、正しい署名を再計算できます。
header.payload+secretnew signature
4
署名を比較
再計算した署名とトークンに含まれる署名を比較します。一致すればトークンは改ざんされていないことが証明されます。
original===recomputed
5
クレームを検証
exp(有効期限)、nbf(開始時刻)、iss(発行者)等をチェックします。署名が有効でも、有効期限切れなどの場合はトークンを拒否します。
exp: 1709366400iss: "api.example"

8
セキュリティの注意点

やってはいけないこと
  • パスワード等の秘密情報をペイロードに含める
  • 秘密鍵をフロントエンドのコードに含める
  • algクレームを"none"で受け入れる
  • 有効期限を設定しない
ベストプラクティス
  • HTTPS通信でのみJWTを送信する
  • 短い有効期限+リフレッシュトークンを使う
  • 十分に長い秘密鍵を使う(256bit以上)
  • RS256(非対称鍵)を検討する

関連コンテンツ

HTTP通信

HTTP通信

ブラウザとサーバー間のHTTPリクエスト/レスポンスの仕組みを可視化

HTTP/1.1 vs HTTP/2

HTTP/1.1 vs HTTP/2

直列リクエストと多重化の違いをウォーターフォールチャートで比較

TLSハンドシェイク

TLSハンドシェイク

HTTPSで安全に通信するためのTLSハンドシェイクの仕組みを可視化

SSE(Server-Sent Events)

SSE(Server-Sent Events)

サーバーからクライアントへの一方向リアルタイムストリーミング通信

QUIC(HTTP/3基盤)

QUIC(HTTP/3基盤)

UDPベースの次世代トランスポートプロトコル。0-RTT接続、ストリーム多重化、接続マイグレーションを可視化

MQTT(Pub/Subモデル)

MQTT(Pub/Subモデル)

MQTTブローカーを経由したPublish/Subscribeモデルの通信フローを可視化します