サイトのAPI図鑑B版
掲載情報が正確でない可能性があります。
開発者向けAPIツール

API認証パターンの実装ガイド【APIキー・JWT・OAuth2・mTLS】

REST APIのAPIキー・JWT(JSON Web Token)・OAuth 2.0・mTLS認証の実装方法と使い分けを解説します。Node.js・Pythonでの認証実装例とセキュリティのベストプラクティスも紹介します。

#認証#JWT#OAuth2#APIキー

API認証方式の概要

APIの認証方式には目的と用途に応じていくつかの選択肢があります。適切な認証方式を選択することはAPIのセキュリティと使いやすさの両立に不可欠です。

APIキー認証の実装

// APIキーのハッシュ化保存
import { randomBytes, createHash } from 'crypto';

const generateApiKey = () => {
  const rawKey = randomBytes(32).toString('hex');
  const keyHash = createHash('sha256').update(rawKey).digest('hex');
  return { rawKey, keyHash }; // rawKeyのみユーザーに1回表示
};

// APIキーの検証ミドルウェア
const apiKeyAuth = async (req, res, next) => {
  const apiKey = req.headers['x-api-key'];
  if (!apiKey) return res.status(401).json({ error: 'APIキーが必要です' });
  
  const keyHash = createHash('sha256').update(apiKey).digest('hex');
  const keyRecord = await db.apiKeys.findUnique({ where: { keyHash } });
  
  if (!keyRecord || keyRecord.revokedAt) {
    return res.status(401).json({ error: '無効なAPIキー' });
  }
  
  // レート制限チェック(Redisを使用)
  const count = await redis.incr(`ratelimit:${keyRecord.id}:${getMinute()}`);
  await redis.expire(`ratelimit:${keyRecord.id}:${getMinute()}`, 60);
  
  if (count > keyRecord.rateLimit) {
    return res.status(429).json({ error: 'レート制限超過' });
  }
  
  req.apiKey = keyRecord;
  next();
};

JWT認証の実装

import jwt from 'jsonwebtoken';

// JWTの生成(ログイン時)
const generateTokens = (userId, email) => {
  const accessToken = jwt.sign(
    { sub: userId, email, type: 'access' },
    process.env.JWT_SECRET,
    { expiresIn: '15m' }
  );
  
  const refreshToken = jwt.sign(
    { sub: userId, type: 'refresh' },
    process.env.JWT_REFRESH_SECRET,
    { expiresIn: '30d' }
  );
  
  return { accessToken, refreshToken };
};

// JWT検証ミドルウェア
const jwtAuth = (req, res, next) => {
  const authHeader = req.headers.authorization;
  if (!authHeader?.startsWith('Bearer ')) {
    return res.status(401).json({ error: 'Authorization headerが必要です' });
  }
  
  const token = authHeader.slice(7);
  try {
    const payload = jwt.verify(token, process.env.JWT_SECRET);
    req.user = payload;
    next();
  } catch (err) {
    if (err.name === 'TokenExpiredError') {
      return res.status(401).json({ error: 'トークンが期限切れです', code: 'TOKEN_EXPIRED' });
    }
    return res.status(401).json({ error: '無効なトークン' });
  }
};

OAuth 2.0 Client Credentials(サーバー間認証)

// Client Credentialsフロー(サーバー間API認証)
const getServiceToken = async () => {
  const response = await fetch('https://auth.example.com/oauth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'client_credentials',
      client_id: process.env.CLIENT_ID,
      client_secret: process.env.CLIENT_SECRET,
      scope: 'api:read api:write'
    })
  });
  
  const { access_token, expires_in } = await response.json();
  // トークンをキャッシュしてexpires_in秒間再利用
  await redis.setEx('service_token', expires_in - 60, access_token);
  return access_token;
};

認証方式の選択ガイド

  • APIキー:シンプルなサーバー間・バックエンドAPIアクセス
  • JWT:ユーザー認証・SPA・モバイルアプリ向けAPI
  • OAuth 2.0 Authorization Code:サードパーティのユーザーリソースへのアクセス
  • OAuth 2.0 Client Credentials:マイクロサービス間・バッチ処理の認証
  • mTLS:金融・ペイメント系の高セキュリティなサーバー間通信

まとめ

API認証はセキュリティの基盤です。APIキーはシンプルで使いやすく、JWTはステートレスでスケーラブルです。OAuth 2.0はサードパーティ連携に必須です。用途に応じて適切な認証方式を選び、APIキーはDBにハッシュ化して保存・JWTは短い有効期限設定・リフレッシュトークンでUX向上というベストプラクティスを実践してください。

よくある質問

Q.JWTとセッションCookieの認証はどちらが良いですか?

JWTはステートレスでスケーラブル(サーバー側でセッションを持たない)、SPAやモバイルアプリのAPIに向いています。セッションCookieはサーバー側でセッション管理が必要ですが、いつでもセッションを無効化できる点がメリットです。マイクロサービスや複数ドメイン間のAPIにはJWTが適しています。

Q.JWTトークンはどこに保存すべきですか?

ブラウザでのJWT保存にはHttpOnly・Secure属性付きCookieが最も安全です。localStorageはXSSに脆弱なため避けるべきです。モバイルアプリではKeychain(iOS)・Keystore(Android)などのセキュアストレージを使います。

Q.APIキーとJWTの使い分けは?

APIキーはサーバー間・システム間のシンプルな認証に適しています。JWTはユーザー認証・権限情報を含んだトークンが必要な場合、特にSPA・モバイルアプリのAPIに適しています。

関連記事