JWTによるAPI認証
Bearerトークン、ミドルウェア検証、スコープベース認可、エラーハンドリングのベストプラクティスを含むJWTベースのAPI認証実装方法を解説します。
詳細な説明
JWTは、REST API、GraphQL API、マイクロサービスの認証メカニズムとして主流となっています。Bearerトークンパターンは、サーバーサイドのセッション保存なしにAPIリクエストを認証・認可するためのステートレスでスケーラブルな方法を提供します。
Bearerトークンパターン:
GET /api/users/me HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyMTIzIn0.signature
クライアントは「Bearer」スキーム(RFC 6750で定義)とともにJWTをAuthorizationヘッダーに含めます。APIサーバーはトークンを抽出し、検証し、埋め込まれたクレームを認証と認可に使用します。
サーバーサイドの検証ミドルウェア:
ミドルウェアでの一般的な検証フロー: (1) Authorizationヘッダーからトークンを抽出、(2) ヘッダーをデコードしてアルゴリズムを決定、(3) 適切な鍵で署名を検証、(4) expをチェックしてトークンが期限切れでないことを確認、(5) issが期待される発行者と一致することを検証、(6) audにこのAPIの識別子が含まれることを検証、(7) ダウンストリーム処理のためにユーザーアイデンティティとクレームを抽出。
// Express.js middleware example
function authenticateJWT(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith('Bearer ')) {
return res.status(401).json({ error: 'Missing token' });
}
const token = authHeader.split(' ')[1];
try {
const payload = jwt.verify(token, publicKey, {
algorithms: ['RS256'],
issuer: 'https://auth.example.com',
audience: 'https://api.example.com'
});
req.user = payload;
next();
} catch (err) {
return res.status(401).json({ error: 'Invalid token' });
}
}
スコープベースの認可:
認証(誰がリクエストしているか)に加えて、JWTは細粒度の認可(何ができるか)を可能にします。scopeクレームにはトークンに付与されたパーミッションがリストされます(例: read:users write:posts)。APIエンドポイントは、リクエスト処理前にトークンのスコープに必要なパーミッションが含まれているか確認します。
エラーレスポンス:
トークンが欠落または無効な場合は401 Unauthorizedを返してください。トークンは有効だがユーザーに必要なスコープやパーミッションがない場合は403 Forbiddenを返してください。RFC 6750に従って、エラー詳細を含むWWW-Authenticateヘッダーを含めてください。レスポンスに内部エラーの詳細(「鍵XYZでの署名検証に失敗」など)を決して含めないでください。実装の詳細が漏洩します。
ユースケース
SaaS APIがミドルウェアでJWTアクセストークンを検証し、クレームからテナントIDとユーザーロールを抽出して、すべてのリクエストでマルチテナントデータ分離を強制します。