はじめに
Webアプリケーションの認証において、JWT(JSON Web Token) は今や欠かせない技術となっています。従来のセッションベース認証と比べて、ステートレスでスケーラブルな認証が実現できるため、APIやマイクロサービスアーキテクチャで広く採用されています。
この記事では、JWTの基本的な仕組みから、安全に実装するためのベストプラクティスまでを解説します。
この記事で学べること
- JWTの構造と仕組み
- 認証フローの全体像
- セキュリティのベストプラクティス
対象読者
- Web開発の基礎知識がある方
- 認証・認可の仕組みに興味がある方
- JWTを安全に実装したいエンジニア
JWTとは何か?
JWT(JSON Web Token) は、当事者間で情報を安全に伝達するためのオープン標準(RFC 7519)です。トークン自体に情報(クレーム)を含むため、サーバー側でセッション情報を保持する必要がありません。
従来のセッション認証との比較
| 項目 | セッション認証 | JWT認証 |
|---|---|---|
| サーバー側の状態 | セッション情報を保持(ステートフル) | 保持しない(ステートレス) |
| スケーラビリティ | サーバー間でセッション共有が必要 | 各サーバーで独立して検証可能 |
| 通信量 | セッションIDのみ(軽量) | トークン全体(やや大きい) |
| 無効化 | サーバー側で即座に可能 | 追加の仕組みが必要 |
JWTの構造を理解する
JWTは**ドット(.)**で区切られた3つの部分で構成されています。
xxxxx.yyyyy.zzzzz
↓ ↓ ↓
Header.Payload.Signature
1. Header(ヘッダー)
トークンのタイプと署名アルゴリズムを指定します。
{
"alg": "HS256",
"typ": "JWT"
}
-
alg: 署名アルゴリズム(HS256, RS256など) -
typ: トークンタイプ(通常は"JWT")
2. Payload(ペイロード)
実際のデータ(クレーム)を格納する部分です。
{
"sub": "1234567890",
"name": "田中太郎",
"iat": 1737705600,
"exp": 1737712800
}
標準クレーム(Registered Claims)
| クレーム | 説明 | 例 |
|---|---|---|
iss |
発行者(Issuer) | "https://example.com" |
sub |
主題(Subject)、通常はユーザーID | "user123" |
aud |
対象者(Audience) | "https://api.example.com" |
exp |
有効期限(Expiration Time) | 1737712800 |
nbf |
有効開始時刻(Not Before) | 1737705600 |
iat |
発行時刻(Issued At) | 1737705600 |
jti |
JWT ID(一意識別子) | "abc123" |
ペイロードはBase64エンコードされているだけで、暗号化されていません。誰でもデコードして内容を読めるため、パスワードや個人情報などの機密データは絶対に含めないでください。
3. Signature(署名)
トークンの改ざんを検出するための署名です。
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
署名により、トークンが改ざんされていないことを検証できます。
実際のトークン例
以下は実際のJWTトークンの例です:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IueUsOS4reeahOmDjiIsImlhdCI6MTczNzcwNTYwMH0.Kj8mQZvR3xPqYz5H7wLdN2fA9gC4yB6sT1eU0iM5hXo
これをデコードすると:
// Header
{ "alg": "HS256", "typ": "JWT" }
// Payload
{ "sub": "1234567890", "name": "田中太郎", "iat": 1737705600 }
JWTの認証フロー
基本的な認証フロー
Access Token と Refresh Token
セキュリティと利便性のバランスを取るため、2種類のトークンを使い分けます。
| トークン | 有効期限 | 用途 |
|---|---|---|
| Access Token | 短い(15分〜1時間) | APIへのアクセス認証 |
| Refresh Token | 長い(7日〜30日) | Access Tokenの再発行 |
Refresh Token Rotation(ローテーション) を実装すると、Refresh Token使用のたびに新しいものを発行することで、トークン漏洩時のリスクを軽減できます。
セキュリティのベストプラクティス
1. 署名アルゴリズムの選択
| アルゴリズム | 種類 | 用途 |
|---|---|---|
| HS256 | 対称鍵(共通鍵) | 単一サービス向け |
| RS256 | 非対称鍵(公開鍵/秘密鍵) | マイクロサービス・複数サービス向け |
alg: "none" は絶対に許可しない!
サーバー側で許可するアルゴリズムをホワイトリストで明示的に指定してください。攻撃者がヘッダーを "alg": "none" に書き換えて署名検証をバイパスする攻撃が存在します。
2. トークンの有効期限設定
// ❌ 悪い例:有効期限が長すぎる
const token = jwt.sign(payload, secret, { expiresIn: '365d' });
// ✅ 良い例:短い有効期限
const accessToken = jwt.sign(payload, secret, { expiresIn: '15m' });
const refreshToken = jwt.sign(payload, refreshSecret, { expiresIn: '7d' });
3. クレームの検証
トークン検証時は、署名だけでなく以下のクレームも必ず検証しましょう:
-
exp: 有効期限が切れていないか -
iss: 信頼できる発行者か -
aud: 正しい対象者か
まとめ
要点の振り返り
JWTは、ステートレスな認証を実現する強力なツールです。以下のポイントを押さえて安全に実装しましょう:
- 構造を理解する: Header, Payload, Signatureの3部構成
- 短い有効期限: Access Tokenは15分〜1時間程度に設定
- Refresh Tokenを活用: 利便性とセキュリティのバランスを取る
-
アルゴリズムをホワイトリスト指定:
noneアルゴリズム攻撃を防ぐ - 機密情報は含めない: ペイロードは暗号化されていない
- HttpOnly Cookieに保存: XSS攻撃からトークンを保護
参考リンク
この記事は2026年1月時点の情報に基づいています。各ライブラリのバージョンや推奨設定は変更される可能性があるため、公式ドキュメントも併せてご確認ください。
