【ツール活用|実務向け】APIテストの生産性を最大化する!AxiosインターセプターによるBearer Token自動更新の実装

導入

API開発やテストを行っている際、短命なアクセストークンの期限切れにより、頻繁に認証エラー(401 Unauthorized)が発生して作業が中断されることはありませんか?そのたびに手動でトークンを取得し、環境変数を書き換える作業は非常に非効率です。本記事では、フロントエンドやNode.js環境で広く使われるHTTPクライアント「Axios」のインターセプター機能を活用し、トークン切れを自動検知して再試行する仕組みを解説します。これにより、認証フローを意識せずにテストに集中できる環境を構築します。

基礎知識

OAuth2における「アクセストークン」は、APIへのアクセス権を証明する鍵です。セキュリティ向上のため短時間で失効するように設計されており、期限が切れた際は「リフレッシュトークン」を使用して新しいアクセストークンを発行します。この「401エラーを検知→トークン再取得→元のリクエストを再送信」という一連の処理をクライアント側で自動化することで、ユーザー体験やテストの継続性を向上させることができます。

実装/解決策

Axiosの「レスポンスインターセプター」を利用します。レスポンスが401を返した場合、Promiseを利用して処理を一時停止させ、トークン更新APIを呼び出します。更新が成功したら、保持していたリクエストを再送します。これにより、呼び出し側は認証の有効性を気にする必要がなくなります。

サンプルプログラム

以下は、Axiosの設定ファイル(axios-client.js)を想定した実装例です。

import axios from 'axios';

const apiClient = axios.create({ baseURL: 'https://api.example.com' });

// リクエスト送信時に最新のトークンをヘッダーに付与
apiClient.interceptors.request.use(config => {
  const token = localStorage.getItem('access_token');
  if (token) config.headers.Authorization = `Bearer ${token}`;
  return config;
});

// レスポンスインターセプター:401検知時にトークンを更新
apiClient.interceptors.response.use(
  response => response,
  async error => {
    const originalRequest = error.config;
    
    // 401エラーかつ再試行済みでない場合のみ実行
    if (error.response?.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;
      
      try {
        // リフレッシュトークンを使用して新しいアクセストークンを取得
        const refreshToken = localStorage.getItem('refresh_token');
        const { data } = await axios.post('/auth/refresh', { refreshToken });
        
        // 新しいトークンを保存
        localStorage.setItem('access_token', data.accessToken);
        
        // 元のリクエストのヘッダーを更新して再試行
        originalRequest.headers.Authorization = `Bearer ${data.accessToken}`;
        return apiClient(originalRequest);
      } catch (refreshError) {
        // 更新失敗時はログイン画面へ遷移させる等の処理
        return Promise.reject(refreshError);
      }
    }
    return Promise.reject(error);
  }
);

export default apiClient;

応用・注意点

同時リクエストへの対応
同時に複数のAPIリクエストが投げられ、全リクエストが同時に401になった場合、トークン更新APIが乱発されるリスクがあります。これを防ぐには、「トークン更新中フラグ」を設け、更新処理中は他のリクエストをキューに入れる(待機させる)仕組みを実装するのが一般的です。

無限ループの回避
リフレッシュトークン自体が期限切れの場合、インターセプター内で無限ループに陥らないよう、`originalRequest._retry` フラグで再試行回数を制限することが不可欠です。また、認証サーバー側のログで「なぜ401が多発しているのか」を確認できるよう、リクエストのトレーサビリティを確保しておくことも推奨します。

コメント

タイトルとURLをコピーしました