JWTはヘッダー・ペイロード・署名の3部構成の自己完結型トークンです。ステートレスな認証に広く使われますが、使い方を誤るとセキュリティリスクになります。仕組みと注意点を正しく理解しましょう。
JWTはxxxxx.yyyyy.zzzzzの形式で、ピリオドで3つのBase64URLエンコードされた部分に分かれています。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMyIsIm5hbWUiOiLlsI_tnoYiLCJpYXQiOjE3MTYwMDAwMDB9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Header(赤)
アルゴリズム種別(HS256等)とトークンタイプを示す。
Payload(青)
ユーザーID・有効期限(exp)等のクレーム情報。
Signature(緑)
Header+Payloadを秘密鍵でHMACして改ざん防止。
PayloadはBase64URLデコードすれば誰でも読めます。パスワード・クレジットカード番号などの機密情報をPayloadに入れないでください。「署名がある=暗号化されている」ではありません。暗号化が必要な場合はJWE(JSON Web Encryption)を使用してください。
const jwt = require('jsonwebtoken'); // JWTを発行(ログイン時) const token = jwt.sign( {{ userId: 'user_123', role: 'admin' }}, process.env.JWT_SECRET, {{ expiresIn: '1h' }} ); // JWTを検証(APIリクエスト時) try {{ const decoded = jwt.verify(token, process.env.JWT_SECRET); console.log(decoded.userId); // 'user_123' }} catch (err) {{ // 署名不正・期限切れはここでキャッチ console.error('Invalid token', err.message); }}
セッション(サーバー側でセッションIDを管理)はサーバーが状態を持つため、ログアウトやセッション無効化が簡単です。JWTはステートレスでスケールしやすく、マイクロサービス間の認証に向きます。単一サービスの小〜中規模アプリにはセッションが実装しやすく、複数サービス間をまたぐ認証にはJWTが向いています。
JWTはステートレスのため、本来サーバー側で無効化できません。ブラックリスト(Redisで失効トークンを管理)を実装すれば強制ログアウトは可能ですが、スケールのメリットが薄れます。有効期限を短くして定期的に再発行(リフレッシュトークン)する設計が現実的な妥協点です。
JWTはトークンの「フォーマット・形式」、OAuthは認可の「プロトコル・フロー」です。OAuth 2.0ではアクセストークンの形式としてJWTを使うことが多いですが、必須ではありません。「JWTで認証」「OAuthで認証」と言われますが、正確にはOAuthは認証ではなく認可(アクセス権限の委譲)を扱うプロトコルです。