このエントリは2019/09/27現在の情報に基づいています。将来の機能追加・変更に伴い、記載内容との乖離が発生する可能性があります。
シナリオ
今回考えているユースケースは以下の通り。
- アプリがOAuth 2.0の認可コードフローに従い、OAuth 2.0プロバイダーであるAzure ADにOAuth 2.0 tokenを取得しにいく
- 取得したOAuth 2.0 tokenを使ってAPIを呼び出す
- APIをホストしているGatewayは、API呼び出し時に送信されたOAuth 2.0 tokenを検証する
- 検証の結果問題なければ、バックエンドサービスへリクエストを流し、アプリはレスポンスを受け取る

なお、バックエンドサービス自体はOAuth 2.0 tokenを受け付けないものとする。
実はこのシナリオ自体は以下のドキュメントに記載があるが、日本語版では一部記述が古く、そして英語版でも記述に間違いがあるように見えるため、このエントリを備忘録として記載しておく。
Azure Active Directory と API Management で OAuth 2.0 を使用して API を保護する / Protect an API by using OAuth 2.0 with Azure Active Directory and API Management
https://docs.microsoft.com/azure/api-management/api-management-howto-protect-backend-with-aad
検証目的のため、今回はAPIを呼び出すアプリ(API Client)としてDeveloper Portalを、APIはAPIMにデフォルトで存在するEcho APIを使う。
まずは…
Azure API Management (以下APIM) インスタンスの作成
APIMインスタンスを作成する。SKUは問わない。インスタンス作成完了までに時間がかかる。
Azure ADでの設定
API を表すアプリケーションを Azure ADに登録
インスタンス生成後、APIMでホストするAPIをアプリケーションとしてAzure ADに登録する(サービスプリンシパルを作成する)。Azure CLIなどでも作成できるが、今回はAzure Portalを使って作成する。
Azure AD > 管理 > アプリの登録 で [新規登録] をクリックし、名前、サポートされているアカウントの種類を指定。リダイレクトURLは不要。

APIの公開
APIとかアプリケーションとか用語が統一されていないために困惑するが、このAPIは先ほど作成したアプリケーション、つまり今回はEcho APIというAPIを表すアプリケーションを公開する、というもの。
まず、このアプリケーションに対して利用許可を設定するために、アプリケーション ID の URIを作成する必要がある。作成したアプリケーションの概要で、[アプリケーション ID URI の追加]クリック、もしくは 管理 > APIの公開 をクリックする。

開いた画面で、[アプリケーション ID の URI]の右にある[設定]をクリックして、URIを取得する。その上で、スコープを追加する。今回、スコープはtest、同意できるユーザーは管理者のみとしておく。作成したスコープ(api://xxxxx/test)は後で利用するのでメモしておく。

APIを表すアプリケーションに対する設定はこれで終了。
API Clientを表すアプリケーションを Azure ADに登録
API Client(ここではDeveloper Portal)をOAuth 2.0クライアントとしてアプリケーションを登録する。アプリケーションの登録自体はAPIの場合と同じ。リダイレクトURIは、APIMポータルのサインインURL(https://{APIM Instance Name}.portal.azure-api.net/signin)もしくは、新しいDeveloper PortalのサインインURL(https://{APIM Instance Name}.developer.azure-api.net/signin)を指定する(後から設定することも可能)。
このタイミングで、OAuth 2.0のエンドポイントを確認、メモしておく。登録したアプリケーションの概要で[エンドポイント]をクリックする。

右から出てくる画面でOAuth 2.0認可サーバー作成時に必要なURLが表示されるので、以下のURLをメモしておく。なお、今回はV2を利用する。

これらのURLは以下のような構造になっている。
URL | |
---|---|
認可URL Authorization URL | https://login.microsoftonline.com/{tenantid}/oauth2/v2.0/authorize |
トークンエンドポイント Token endpoint | https://login.microsoftonline.com/{tenantid}/oauth2/v2.0/token |
OpenID Connectメタデータ ドキュメント | https://login.microsoftonline.com/{tenantid}/v2.0/.well-known/openid-configuration |
クライアントシークレットの作成
API ClientからAPI(を表すアプリケーション)へのアクセスに必要なOAuth 2.0トークンを取得するためには、クライアントシークレットが必要である。
クライアントシークレットは、API Clientを表すアプリケーションとして登録したアプリをクリックし、管理 > 証明書とシークレット をクリック、 [新しいクライアント シークレットの追加] をクリックして、説明と有効期限を指定する(説明はオプション)。今回は無期限にしておく。画面が戻ると、値の場所にランダムな文字が入っている。これがクライアントシークレットである。この値は後から取得できないので、この時点でメモしておく。

詳細は以下のドキュメントを参照。
クライアント アプリケーションを表す別のアプリケーションを Azure AD に登録する / Register another application in Azure AD to represent a client application
https://docs.microsoft.com/azure/api-management/api-management-howto-protect-backend-with-aad#register-another-application-in-azure-ad-to-represent-a-client-application
アプリケーションの許可
API Clientに対し、先ほど公開したAPI(を表すアプリケーション)へのアクセス許可を設定する。Azure AD > 管理 > アプリの登録をクリックしてAPI Clientを表すアプリケーションを選択し、管理 > API のアクセス許可 を開いて、[+アクセス許可の追加]をクリックする。

[アクセス許可の要求]が右側から出てくるので、[自分のAPI]タブを選択し、先ほど公開したアプリケーション(下図ではLogico API)を選択する。

画面が切り替わるので、ここでアクセス許可を追加したいスコープを選択して[アクセス許可の追加]をクリックする。

ここまででAzure ADでの設定はひとまず完了(実はあと1個だけ設定しなければならない)。
APIMでの設定
APIMでOAuth2認可サーバーを構成
OAuth 2.0認可サーバーをAPIMに追加する。セキュリティ > OAuth 2.0 を選択し、 [+追加] をクリックして必要事項を入力する。クライアント登録URLが必須になっているが、これはひとまずhttps://localhost/ としておく(必須になっていること自体どうなの、というツッコミは置いておく)。

その他の設定項目は以下の通り。記載されていない設定項目はデフォルトでよい。指定後、[作成]をクリック。
設定項目 | 値 |
---|---|
承認許可の種類 | 承認コード(Authorization Code) |
承認エンドポイントのURL | 先ほどメモした値 |
承認要求方法 | POSTも選択 |
トークンエンドポイントのURL | 先ほどメモした値 |
アクセストークンの送信方法 >既定のスコープ | API(を表すアプリケーション)で作成したスコープの値 (今回の場合、api://xxxxx/test) |
クライアントの資格情報 | API Clientを表すアプリケーション作成時に取得したクライアントIDとクライアントシークレット |
作成完了すると、OAuth 2.0の認可フローで使われるリダイレクトURIが生成されるので、再度Azure AD > アプリの登録 > API Clientを表すアプリケーション を選択し、生成されたリダイレクトURIをリダイレクトURIに設定しておく。種類はWebでOK。

OAuth 2.0認可を使うようにAPIを構成する
今回は既存のEcho APIを使う。簡単のために、APIはサブスクライブしていなくても呼び出せるようにしておく(もちろんAPI Keyを有効化しておいてもかまわない)。
APIMの画面でAPI Management > API で構成したいAPI(今回の例ではEcho API)を選択し、Settingsタブをクリックする。下にスクロールするとSecurityの項目があるので、そこでOAuth 2.0を選択し、OAuth 2.0 Serverを先ほど作成したもの(今回の例ではOAuth2)を選択して [Save] をクリックし、設定を保存する。

validate-jwt ポリシーをAPIに追加する
続いて、validate-jwt ポリシーをAPIのInbound側に設定する。validate-jwt ポリシーの詳細は以下のドキュメントを参照。
JWT を検証する / Validate JWT
https://docs.microsoft.com/azure/api-management/api-management-access-restriction-policies#ValidateJWT
Designタブに移動し、All operationsを選択して、Inbound processingで[+Add policy]をクリックし、Validate JWTをクリックする。フォーム形式の画面が現れるので、Fullをクリックして構成していく。

設定内容は以下の通り。なお、記載のないものはデフォルト設定のまま。
(注意点)Issuerは本来なら設定する必要がないのだが、取得したOAuth 2.0トークンを調べた限り、APIMが期待しているIssuerと異なるため、今回はこのIssuerを追加している。
設定項目 | 値 |
---|---|
Header name | Authorization |
Failed validation error message | 認証が失敗しました。アクセストークンがないか、適切ではありません。 |
Issuers | https://sts.windows.net/{tenant id}/ |
Required claims > Name | aud |
Required claims > Values | アプリケーション ID の URI |
Open ID URLs | 先ほどメモしたOpen ID Connect メタデータ ドキュメントのURL |

なお、コード表示すると、以下のようなXML形式で確認できる(表示上、XML attributeごとに改行しているが、実際には1行)。

上記設定は以下の要素、属性に反映されている。
XML Element/Attribute | 値 |
---|---|
validate-jwt@header-name | Authorization |
validate-jwt@failed-validation-error-message | 認証が失敗しました。アクセストークンがないか、適切ではありません。 |
validate-jwt/openid-config@url | メモしたOpenID Connectメタデータ ドキュメントのURL。 |
validate-jwt/issuers/issuer | https://sts.windows.net/{tenant id}/ |
validate-jwt/required-claims/claim@name | aud |
validate-jwt/required-claims/claim/value | アプリケーション ID の URI |
以上で完了。
試してみる
まずは、Developer Portalで、何も考えずにAPIを呼び出す。Access tokenをつけていないので、当然401が返ってくる。

では、続いてAccess tokenを取得し、Bearer tokenとして取得したtokenをつけて呼び出してみる。AuthorizationでOAuth 2.0を選択、同意画面で同意した上で、OAuth 2.0 tokenを取得する。

そのtokenを使って呼び出すと、問題なく200が返ってくることがわかる。
