Updated: 10/18/2025, 5:40:23 PM
10/18/2025, 5:40:23 PM
この記事では、JWT(JSON Web Token)を使った認証システムの実装について、実際にプロダクションで動くシステムを構築した経験をもとに解説します。
単なるチュートリアルではなく、以下のような「現場で必要になる知識」を重点的に扱います:
以下のような方を想定しています:
以下の知識があるとスムーズに読めます(必須ではありません):
言語非依存の内容なので、特定のフレームワークに縛られず応用できます。
まず最初に重要な認識を正しましょう。
JWTは認証システムそのものではありません。
よくある誤解:
❌ 「JWT認証を使えば認証システムが作れる」
❌ 「JWTはセッション管理の仕組み」
❌ 「JWTがあれば安全な認証ができる」
正しい理解:
✅ JWTは「署名付き自己完結型トークン」のフォーマット仕様
✅ 認証システムの「部品」として使うもの
✅ JWTだけでは認証システムは完成しない
例えるなら:JWTは「南京錠」のようなもの。鍵をかけて本人確認はできるけど、「誰に鍵を渡すか」「鍵をどう管理するか」は別途設計が必要です。
JWTの本質は 「改ざんできない情報の入れ物」 です。
通常のJSONデータとの違い:
json
// JWT(署名付きなので改ざん検知可能)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJ1c2VyX2lkIjoxMjMsImVtYWlsIjoidXNlckBleGFtcGxlLmNvbSJ9.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
この 「改ざんできない」 特性が、JWTの最大の価値です。
JWTは3つの部分から構成されます:
[Header].[Payload].[Signature]
1. Header(ヘッダー)
json
→ Base64エンコード → eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
2. Payload(ペイロード)
json
→ Base64エンコード → eyJ1c2VyX2lkIjoxMjMsIm...
3. Signature(署名)
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret_key
)
→ 署名結果 → SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
重要なポイント:
つまり、JWTは 「秘密にする」ためではなく「改ざんを防ぐ」ためのもの です。
JWT認証システムの本質は、驚くほどシンプルです:
1. アクセストークン(JWT)で本人確認する
2. 期限切れになったらリフレッシュトークンで更新する
以上。
それだけ? はい、本当にそれだけです。
複雑に見えるのは、この2つのトークンを 「どう発行するか」「どう保存するか」「どう無効化するか」 という周辺設計の話です。
Q: アクセストークンだけじゃダメなの?
ダメです。理由は2つあります:
理由1: セキュリティ vs 利便性のトレードオフ
理由2: 即座にログアウトできない問題
JWTは自己完結型なので、サーバー側で「無効化」できません:
ユーザー: 「ログアウトしたい」
サーバー: 「了解!」
でも実際は...
→ アクセストークンはまだ有効(最大30日間使える)
→ 本当の意味でのログアウトができていない
解決策:2トークン方式
アクセストークン(短命・15分)
↓
盗まれても被害は15分間だけ
ログアウト時は放置してOK(15分で自然消滅)
リフレッシュトークン(長命・30日)
↓
Redis等で管理(削除可能)
ログアウト時に削除すれば即座に無効化
これにより 「セキュリティと利便性を両立」 できます。
JWT認証の特徴を理解するには、この2つの概念が重要です:
ステートレス(Stateless)
サーバー側で状態を保持しない方式
例:アクセストークン(JWT)
- サーバーは「この人がログインしてる」を記録しない
- トークンの署名を検証するだけ
- 超高速(データベース・Redis不要)
- スケールしやすい(どのサーバーでも検証可能)
問題点:
- 即座に無効化できない
- 発行したら取り消せない
ステートフル(Stateful)
サーバー側で状態を保持する方式
例:リフレッシュトークン(UUID)
- Redisに「このトークンは有効」と記録
- リクエストごとにRedisをチェック
- 削除すれば即座に無効化
問題点:
- Redisアクセスが必要(わずかに遅い)
- Redisが落ちると認証不可
ハイブリッド戦略:両方のいいとこ取り
通常のAPIリクエスト
→ アクセストークン(JWT)で超高速認証
トークン更新・ログアウト
→ リフレッシュトークン(Redis)で確実に制御
この組み合わせが、モダンなJWT認証システムの定石です。
JWT認証は万能ではありません。他の認証方式と比較して、適切な選択をしましょう。
セッションベース認証(従来型)
1. ログイン
↓
2. サーバーがセッションIDを発行
↓
3. セッションIDをCookieに保存
↓
4. リクエストごとにセッションIDで照合
仕組み:
クライアント: 「セッションID: abc123」
サーバー: 「データベース見るか... OK、user_id=123だな」
比較表:
使い分けの目安:
セッションベースを選ぶべき場合:
✅ Webアプリのみ(モバイル不要)
✅ シンプルな実装を優先
✅ 即座のログアウトが重要
✅ 小規模サービス(スケール不要)
JWT認証を選ぶべき場合:
✅ モバイルアプリ対応が必要
✅ マイクロサービス構成
✅ 高トラフィック・高スケーラビリティ
✅ API提供がメイン
よくある誤解:
❌ 「JWTとOAuthは別物」
❌ 「OAuthを使えばJWTは不要」
正しい理解:
✅ OAuth 2.0は「認可フレームワーク」
✅ JWTはOAuth 2.0の「アクセストークン形式」として使われることが多い
✅ 両者は補完関係
関係性の図:
OAuth 2.0(認可フレームワーク)
├─ Authorization Code Flow(認可フロー)
├─ Refresh Token(更新トークン)
└─ Access Token(アクセストークン)← ここでJWTを使う
例:Google OAuth
1. 「Googleでログイン」ボタンをクリック
↓(OAuth 2.0の認可フロー)
2. Googleが認証してauthorization_codeを返す
↓
3. あなたのサーバーがaccess_tokenを取得
↓(ここでJWT形式のトークンを自分で発行)
4. 以降はJWT認証で本人確認
API Key(永続的なトークン)
例: api_key_1234567890abcdefghijklmnop
特徴:
- 有効期限なし(手動で削除するまで有効)
- マシン to マシン通信向け
- ユーザーごとではなくアプリケーションごと
JWT(一時的なトークン)
例: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
特徴:
- 有効期限あり(15分〜30分)
- ユーザー to サーバー通信向け
- ユーザーごとに異なる
使い分け:
JWTは認証フレームワークではなく「署名付きトークン」
JWT認証の核心は単純
ステートレス + ステートフル のハイブリッド戦略
他の認証方式との使い分けが重要
次回は 「シーケンス図で理解する認証フロー」 です。