どのAPIチームも同じ壁にぶつかります。エンドポイントは単体では機能しますが、誰かがOAuth 2.0を有効にすると、テストスイートの半分が401エラーを返し始めます。突然、認証サーバー、短命なアクセストークン、スコープをやりくりすることになり、cURLの応答からヘッダーフィールドにトークンを手作業でコピーする作業は、3回目の実行でうんざりするものになります。
解決策は、テストで認証をスキップすることではありません。トークン処理をテストセットアップの一部にすることで、手作業をなくすことです。このガイドでは、ほとんどすべてのテスト計画で遭遇する2つのフローについて説明します。それは、ユーザーの代わりに動作するAPIのためのOAuth認可コードフロー(PKCE付き)と、マシン間呼び出しのためのクライアントクレデンシャルズフローです。まず、グラントの全体像を知りたい場合は、当社のOAuth 2.0フロー概要でそれらすべてを解説しています。
次に、実践的な内容に入ります。ApidogでのOAuth 2.0認証の設定、トークンを一度取得して複数のリクエストで再利用する方法、期限切れトークンを自動的に更新させる方法、フォルダーレベルでの認証継承、そしてセキュリティレビューで問われるであろう失敗パスのテストについてです。
ボタン
APIテストで重要な2つのフロー
OAuth 2.0はいくつかのグラントタイプを定義していますが、日常的なAPIテストではそのうちの2つにほとんどの時間を費やすことになります。1つの質問に基づいて選択してください。APIはユーザーの代理として動作するのか、それともサービスの代理として動作するのか?
認可コードフロー(PKCE付き)
認可コードフローは、ユーザーに紐付くトークンを取得する標準的な方法です。クライアントはユーザーを認可サーバーに送り、ユーザーはログインして同意します。サーバーはワンタイムコードを付けてリダイレクトし、クライアントはそのコードをトークンエンドポイントでアクセストークンと交換します。RFC 6749のセクション4.1で、この一連の流れが定義されています。
PKCE(Proof Key for Code Exchange、RFC 7636)は、この交換プロセスを強化します。クライアントはランダムな検証子を生成し、認可リクエストとともにハッシュ化されたチャレンジを送信します。そして、コードを引き換える際に元の検証子を保持していることを証明します。これにより、コードを傍受した攻撃者はそれを使用できません。PKCEはモバイルアプリの修正として始まりましたが、oauth.netからの現在のガイダンスでは、機密クライアントを含むすべての認可コード交換に推奨されています。
エンドポイントの動作がユーザーによって異なる場合(呼び出し元の注文のみを返すGET /orders、ロールで制限された管理エンドポイント、ユーザーごとのレート制限など)は、常にこのフローでテストしてください。
クライアントクレデンシャルズフロー
OAuth 2.0クライアントクレデンシャルズグラントは、ユーザーを完全にスキップします。クライアントは自身のIDとシークレットで認証し、アプリケーション自体を表すトークンを受け取ります。トークンエンドポイントへのPOSTリクエスト1回で、ブラウザもリダイレクトも不要です。
curl -X POST https://auth.example.com/oauth/token \
-d grant_type=client_credentials \
-d client_id=orders_service \
-d client_secret=s3cr3t_value \
-d scope="orders:read orders:write"
これは、内部マイクロサービス、cronジョブ、デプロイAPIを呼び出すCIパイプラインなど、マシン間APIのためのフローです。また、人間の介入が不要であるため、自動テストの主力でもあります。テスト環境でテストクライアントをプロビジョニングできる場合、ユーザーIDがテスト対象であるケースを除いて、すべてにクライアントクレデンシャルズを使用してください。
ApidogでのOAuth 2.0認証の設定
ApidogはOAuth 2.0を第一級の認証タイプとして扱います。リクエストまたはフォルダーの「Auth」タブで一度設定すれば、プラットフォームがトークンの取得、付与、更新を処理します。サポートされているグラントタイプには、認可コード、認可コード(PKCE付き)、クライアントクレデンシャルズ、パスワードクレデンシャルズ、インプリシットが含まれます。
上記の2つのフローの設定について、架空の注文管理APIを例に説明します。
クライアントクレデンシャルズの設定
リクエスト(またはより良い方法としてフォルダー。これについては後述します)を開き、認証タイプをOAuth 2.0に切り替え、グラントタイプとして「Client Credentials」を選択します。以下の項目を入力します。
- アクセストークンURL:
https://auth.example.com/oauth/token - クライアントID:
orders_service - クライアントシークレット: プロビジョニングされたシークレット
- スコープ:
orders:read orders:write(詳細オプションで設定)
Apidogでは、資格情報を送信する方法が2つあります。Basic Authヘッダーとして、またはリクエストボディ内です。認可サーバーが期待するものに合わせてください。Auth0とOktaは両方を受け入れますが、一部の社内サーバーはボディのみを解析します。
「トークンを取得」をクリックします。Apidogはトークンエンドポイントを呼び出し、結果を保存し、その有効期間とともにトークンを表示します。それ以降、すべての送信でBearerプレフィックス付きでAuthorizationヘッダーにトークンが添付されます。コピー&ペーストも、{{token}}変数の配管も不要です。
認可コード(PKCE付き)の設定
ユーザーコンテキストのテストでは、グラントタイプとして「Authorization Code (With PKCE)」を選択します。ApidogではPKCEはチェックボックスではなく、独立したグラントオプションです。さらにいくつかのフィールドが必要です。
- 認証URL:
https://auth.example.com/oauth/authorize - アクセストークンURL:
https://auth.example.com/oauth/token - コールバックURL: プロバイダーに登録されたリダイレクトURI
- クライアントIDとクライアントシークレット: OAuthアプリの登録情報から
「トークンを取得」をクリックすると、Apidogはログインページを指すブラウザウィンドウを開きます。テストユーザーとしてサインインし、同意画面を承認すると、トークンが返され、以前と同じ管理スロットに格納されます。プロバイダーがアクセストークンと一緒にOpenID Connect IDトークンを返す場合、「Token Type Used」オプションを使用すると、どちらを添付するかを切り替えることができます。これは、テスト対象のAPIがIDトークンを検証する場合に役立ちます。
実用的なヒントを1つ。カバーする必要のあるロール(購入者、管理者、読み取り専用監査人など)ごとに専用のテストユーザーを用意してください。各ユーザーとしてトークンを取得し、同じシナリオを再実行することが、ロールベースのアクセスルールを検証する最も迅速な方法です。
トークンの再利用と自動更新
アクセストークンは通常1時間以内に期限が切れます。Apidogがこれを処理する前は、期限切れのトークンは実行の失敗と手動での再取得を意味し、これはチームが無視することを学ぶような不安定な失敗でした。
現在、認可サーバーがリフレッシュトークンを発行した場合、ApidogはOAuth 2.0トークンを自動的に更新します。この機能は6月のアップデートで提供されました。保存されたアクセストークンが期限切れになると、Apidogはリフレッシュトークンを使用して新しいトークンを取得し、送信前にそれと交換します。プロバイダーが2つのエンドポイントを分離している場合は、詳細設定でカスタムのリフレッシュトークンURLを指定することもできます。
クライアントクレデンシャルズの場合、多くのサーバーはリフレッシュトークンを完全にスキップします(クライアントはいつでも再認証できるため、仕様で許可されています)。実際にはこれは問題ありません。「トークンを取得」で再取得するのはワンクリックで済みますし、スケジュール実行やCI実行では、各実行の開始時に新しいトークンをリクエストできます。
フォルダーレベルでの認証継承
すべてのリクエストでOAuthを設定するのは、間違ったアプローチです。Apidogでは、フォルダーに認証を設定でき、その中のリクエストは親から設定を継承します。「Orders API」フォルダーにOAuth 2.0を一度設定すれば、その下のすべてのリクエスト(次のスプリントでチームメイトが追加する新しいリクエストを含む)が同じ管理されたトークンを送信します。
これは多段階テストシナリオで最も重要になります。チェックアウトシナリオでは、POST /carts、POST /carts/{id}/items、POST /ordersを連結するかもしれません。フォルダーレベル認証を使用すると、これら3つのステップすべてが1つのトークンと1つの設定を共有します。シナリオの途中でトークンが期限切れになっても、自動更新がそれをカバーします。また、セキュリティチームがクライアントシークレットをローテーションした場合、40のリクエストではなく、1つのフォルダーを更新するだけで済みます。
リクエストには親設定を上書きするオプションが残されており、これはネガティブテストを行う上でまさに望ましいものです。それについてはこれから詳しく説明します。
失敗パスのテスト
ハッピーパスのOAuthテストは、トークンパイプラインが機能することを示します。失敗パスのテストは、APIが認証を強制することを示します。これらをスキップすると、フレームワークのデフォルトを信頼することになります。自動化する価値のある3つのケースを以下に示します。各ステータスコードが何を意味すべきかについては、APIキーとベアラートークンの比較をご覧ください。
期限切れまたは欠落したトークン: 401を期待
シナリオ内の1つのリクエストを複製し、継承された認証を「認証なし」またはBearer expired_token_do_not_rotateのようなハードコードされた、完全に無効なベアラートークンで上書きします。以下をアサートします。
- ステータスコードが
401であること WWW-Authenticate応答ヘッダーが存在すること(RFC 6749の付随RFC 6750で期待される)- ボディがスタックトレースや内部ホスト名を漏洩しないこと
ここで200が返されるのは重大なバグです。403は、チケットを切る価値のある設計上の問題です。サーバーは「あなたは誰だか知らない」と「あなたは知っているが許可しない」を区別すべきです。
誤ったスコープ: 403を期待
orders:readに限定された2番目のテストクライアントをプロビジョニングし、そのトークンを取得して、POST /ordersのような書き込みエンドポイントを呼び出します。ステータスが403であり、APIがRFC 6750に従っている場合は、WWW-Authenticateヘッダーにerror="insufficient_scope"が含まれていることをアサートします。このテストは、一部のルートではゲートウェイでスコープがチェックされ、他のルートでは忘れられているという典型的な設定ミスを検出します。スコープがチームにとって新しい場合は、OAuth 2.0スコープの解説でそれらの分割方法が説明されています。
無効なクライアント: クリーンなトークンエンドポイントエラーを期待
偽のclient_secretを使って、https://auth.example.com/oauth/tokenに直接リクエストを送信します。RFC 6749セクション5.2によれば、サーバーは"error": "invalid_client"を含むJSONボディと共に400(またはクライアント認証失敗の場合は401)を返す必要があります。両方をアサートします。認可サーバーもAPIであり、そのエラー契約はあなたの表面の一部です。
テストシナリオでのトークン応答のアサート
トークンエンドポイントは、無効なクライアントの場合を超えて、独自のカバレッジを持つべきです。テストシナリオに、トークンエンドポイントを直接呼び出すステップを追加し、その応答にアサーションを付加します。
access_tokenが存在し、空ではないことtoken_typeがbearerと等しいこと(仕様上、大文字小文字を区別しない)expires_inが0より大きく、ポリシー内であること(例えば3600以内)scopeがリクエストされたものと一致すること(サーバーが密かにグラントを狭めているのを捕捉)
Apidogのテストシナリオでは、これらの視覚的なアサーションを応答JSONに追加でき、スクリプトは不要です。また、マネージド認証を使用する代わりに生のハンドシェイクをテストしたい場合は、access_tokenを変数に抽出して後続のステップで使用することもできます。このシナリオをCI実行に組み込めば、動作不良の認可サーバーが本番環境で謎の401として現れる代わりに、ビルドが失敗します。
全体の流れは次のようになります。ハッピーパス用のフォルダーレベルOAuth 2.0設定、401および403ケースごとのリクエスト上書き、そしてトークンエンドポイントの契約を検証する1つのシナリオ。これにより、PKCE付き認可コードを介したユーザーコンテキストAPIと、クライアントクレデンシャルズを介したサービス間APIがカバーされ、トークンの更新も自動で処理されます。Apidogをダウンロードして無料で試してみてください。OAuth 2.0認証タイプは無料プランで利用できるため、数分で独自のトークンエンドポイントを指すことができます。
よくある質問 (FAQ)
APIテストにはどのOAuthフローを使用すべきですか?
マシン間通信やほとんどの自動スイートにはクライアントクレデンシャルズを使用してください。ブラウザ操作が不要なためです。テストがユーザーIDに依存する場合(ユーザーごとのデータ分離、ロールチェック、同意動作など)は、PKCE付きの認可コードフローを使用してください。新しいテスト計画では、インプリシットグラントとパスワードグラントは避けるべきです。両方とも現在のOAuthガイダンスで非推奨とされています。
Apidogで期限切れトークンを自動的に更新するにはどうすればよいですか?
「Auth」タブでOAuth 2.0を設定し、「トークンを取得」でトークンを取得します。認可サーバーがリフレッシュトークンを返した場合、Apidogはあなたが再認証することなく、期限切れ時にアクセストークンを更新します。また、プロバイダーがリフレッシュトークンURLを別にしている場合は、詳細設定でそれを設定できます。リフレッシュトークンを使用しないクライアントクレデンシャルズ設定の場合、「トークンを取得」を再実行すれば新しいトークンが発行されます。
シナリオ内のすべてのリクエストで1つのOAuthトークンを共有できますか?
はい、できます。親フォルダーにOAuth 2.0設定を行うと、その中のリクエストはそれを継承するため、多段階シナリオは単一の管理されたトークンの下で実行されます。個々のリクエストはフォルダーの設定を上書きすることも可能であり、これがネガティブテスト(期限切れトークン、誤ったスコープ)を同じシナリオに組み込む方法です。
OAuthで保護されたAPIにおいて、401と403はそれぞれ何を意味すべきですか?
認証が失敗した場合(トークンがない、期限切れ、形式が不正など)は401を返します。トークンは有効だが権限がない場合(スコープが不足しているなど)は403を返します。これらを混同するとクライアントのリトライロジックが破綻します。なぜなら、401はクライアントに再認証を促す一方、403は停止を促すからです。JWT認証のテストに関するガイドでは、トークン自体の検証について掘り下げています。
