JWT認証:開発者ガイド
JSON Web Tokenでセキュアな認証を実装。JWT構造、セキュリティ考慮事項、ベストプラクティスを学習。
JWTとは?
JSON Web Token(JWT)は、パーティ間でJSONオブジェクトとして情報を安全に伝送するための コンパクトで自己完結型の方法を定義するオープンスタンダード(RFC 7519)です。 JWTはWebアプリケーションでの認証と情報交換に一般的に使用されます。
JWTの主要な利点
- ステートレス: サーバーにセッションデータを保存する必要がない
- コンパクト: 軽量で伝送効率が高い
- 自己完結型: 必要な情報をすべて含んでいる
- セキュア: デジタル署名で改ざんを防止
- クロスドメイン: 異なるドメインやサービスで動作
JWT構造
JWTはドット(.)で区切られた3つの部分から構成されます:ヘッダー、ペイロード、署名。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
ヘッダー
アルゴリズムとトークンタイプを指定
1{
2 "alg": "HS256",
3 "typ": "JWT"
4}
ペイロード
クレーム(エンティティに関するステートメント)を含む
1{
2 "sub": "1234567890",
3 "name": "John Doe",
4 "iat": 1516239022,
5 "exp": 1516242622,
6 "role": "admin"
7}
署名
トークンが改ざんされていないことを検証
1HMACSHA256(
2 base64UrlEncode(header) + "." +
3 base64UrlEncode(payload),
4 secret
5)
JWT認証の動作原理
JWT認証フローは、クライアント、サーバー、保護されたリソース間のいくつかのステップを含みます。
ユーザーログイン
クライアントが認証サーバーに認証情報を送信
トークン生成
サーバーが認証情報を検証しJWTを作成
トークン返却
サーバーがJWTをクライアントに送信
後続リクエスト
クライアントがAuthorizationヘッダーにJWTを含める
トークン検証
サーバーがJWTを検証しリクエストを処理
実装例
ExpressでのNode.js(サーバーサイド)
1const jwt = require('jsonwebtoken');
2const bcrypt = require('bcrypt');
3
4// Login endpoint
5app.post('/login', async (req, res) => {
6 const { email, password } = req.body;
7
8 try {
9 // Find user in database
10 const user = await User.findOne({ email });
11 if (!user) {
12 return res.status(401).json({ error: 'Invalid credentials' });
13 }
14
15 // Verify password
16 const isValidPassword = await bcrypt.compare(password, user.passwordHash);
17 if (!isValidPassword) {
18 return res.status(401).json({ error: 'Invalid credentials' });
19 }
20
21 // Create JWT
22 const token = jwt.sign(
23 {
24 userId: user.id,
25 email: user.email,
26 role: user.role
27 },
28 process.env.JWT_SECRET,
29 { expiresIn: '1h' }
30 );
31
32 res.json({ token, user: { id: user.id, email: user.email } });
33 } catch (error) {
34 res.status(500).json({ error: 'Server error' });
35 }
36});
Frontend JavaScript (Client-side)
1class AuthService {
2 constructor() {
3 this.token = localStorage.getItem('token');
4 }
5
6 async login(email, password) {
7 try {
8 const response = await fetch('/api/login', {
9 method: 'POST',
10 headers: {
11 'Content-Type': 'application/json'
12 },
13 body: JSON.stringify({ email, password })
14 });
15
16 if (!response.ok) {
17 throw new Error('Login failed');
18 }
19
20 const data = await response.json();
21 this.token = data.token;
22 localStorage.setItem('token', this.token);
23
24 return data;
25 } catch (error) {
26 console.error('Login error:', error);
27 throw error;
28 }
29 }
30}
セキュリティ考慮事項
トークンの保存
- 機密トークンでのlocalStorageの使用を避ける(XSS脆弱性)
- 自動的な含有のためにhttpOnlyクッキーを使用
- secure、sameSiteクッキー属性を検討
- クッキーと適切なCSRF保護を実装
秘密鍵管理
- 強力でランダムに生成された秘密鍵を使用
- 秘密鍵を安全に保存(環境変数、キーボルト)
- 定期的に秘密鍵をローテーション
- マイクロサービス向けに非対称アルゴリズム(RS256)を検討
ベストプラクティス
常にHTTPSを使用
暗号化されていない接続でJWTを送信しない
すべてのクレームを検証
有効期限、発行者、対象者、その他の関連クレームを確認
ペイロードサイズを最小化
JWTペイロードには必要な情報のみを含める
トークン更新を実装
リフレッシュトークン機構と短期間のアクセストークンを使用
トークン有効期限を適切に処理
自動トークン更新と有効期限切れ時のログアウトを実装
JWT vs 代替案
セッションベース認証
利点: サーバーサイド制御、簡単な取り消し、小さなクライアントストレージ
欠点: サーバーサイドストレージが必要、水平スケールが困難
OAuth 2.0 / OpenID Connect
利点: 業界標準、委任、包括的なフロー
欠点: より複雑な実装、追加のインフラが必要
APIキー
利点: シンプルな実装、サービス間認証に適している
欠点: 有効期限なし、スコープ制御の制限、セキュリティ上の懸念
一般的なJWTクレーム
クレーム | 説明 | 例 |
---|---|---|
iss | 発行者 | "https://auth.example.com" |
sub | 対象者(ユーザーID) | "user123" |
aud | 観客(対象) | "api.example.com" |
exp | 有効期限 | 1516242622 |
iat | 発行時刻 | 1516239022 |
jti | JWT ID | "abc123" |
まとめ
JWTは、現代のWebアプリケーションにおけるステートレス認証の堅牢なソリューションを提供します。 強力である一方、セキュリティのベストプラクティスに注意を払った慎重な実装が必要です。 代替認証方法よりもJWTを選択する際は、特定のユースケース、セキュリティ要件、 インフラの制約を考慮してください。