JWTによるAPI認証

Bearerトークン、ミドルウェア検証、スコープベース認可、エラーハンドリングのベストプラクティスを含むJWTベースのAPI認証実装方法を解説します。

Usage

詳細な説明

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とユーザーロールを抽出して、すべてのリクエストでマルチテナントデータ分離を強制します。

試してみる — JWT Decoder

フルツールを開く