このエントリは2019/10/01現在の情報に基づいています。将来の機能追加・変更に伴い、記載内容との乖離が発生する可能性があります。
はじめに
先日動作確認したAuthorization Codeを踏まえて、Client credentials grantでの設定と動作を確認する。
なお、バックエンドサービス自体は以前と同様、OAuth 2.0 tokenを受け付けないものとする。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は不要。

アプリケーション ID の URIを作成
API Clientに対して利用許可を設定するために、APIを表すアプリケーションでアプリケーション ID の URIを作成する。作成したアプリケーションの概要で、[アプリケーション ID URI の追加]クリック、もしくは 管理 > APIの公開 をクリックする。

開いた画面で、[アプリケーション ID の URI]の右にある[設定]をクリックして、URIを取得する。
APIのアクセス許可
RBACを使ったClient credentials grantの利用の場合、Authorization code grantの場合のようなDelegated permission(委任済みの許可)ではなく、Application permission(アプリケーションの許可)を構成する必要があり、今回の場合、アプリケーションロールを作成する必要がある。そのため、APIを表すアプリケーションで 管理 > マニフェスト を選択し、appRolesに以下のコードを追加する。
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"description": "[API のアクセス許可]で表示される説明",
"displayName": "[API のアクセス許可]で表示される表示名",
"id": "[guid]",
"isEnabled": true,
"value": "API.Request"
}
]
上記JSONの各要素の意味は以下の通り。
要素 | 意味 |
---|---|
allowedMemberTypes | 割り当てたいロールの対象。UserもしくはApplication、その両方を指定できる |
description | [API のアクセス許可]で表示される説明 |
displayName | [API のアクセス許可]で表示される表示名 |
id | このロールに割り当てるguid。PowerShellやCloud Shellで生成したものを貼り付ける。以下はPowerShell/Cloud Shellの例 [guid]::NewGuid() |
isEnabled | 有効化するか否か。当然true |
value | [APIのアクセス許可]でスコープとして見えるもの。Authorization code grantで作成したスコープと同じ。 |
アプリケーションのマニフェストとアプリケーションロールの設定方法は以下のドキュメントを参照。
Azure Active Directory のアプリ マニフェスト / Azure Active Directory app manifest
https://docs.microsoft.com/azure/active-directory/develop/reference-app-manifest
方法:アプリケーションにアプリ ロールを追加してトークンで受け取る / How to: Add app roles in your application and receive them in the token
https://docs.microsoft.com/azure/active-directory/develop/howto-add-app-roles-in-azure-ad-apps
Microsoft ID プラットフォームと OAuth 2.0 クライアント資格情報フロー / Microsoft identity platform and the OAuth 2.0 client credentials flow
https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
ここまででAPIを表すアプリケーションに対する設定は終了。
API Clientを表すアプリケーションを Azure ADに登録
API Client(今回はREST Client)をOAuth2クライアントとしてアプリケーションを登録する。アプリケーションの登録自体はAPIの場合と同じ。リダイレクトURIは設定不要。
このタイミングで、OAuth 2.0のエンドポイントを確認、メモしておく。登録したアプリケーションの概要で[エンドポイント]をクリックする。

右から出てくる画面でOAuth2認可サーバー作成時に必要な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 tokenを取得するためには、クライアントシークレットが必要である。
クライアントシークレットは、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のアクセス許可
API Clientに対し、先ほど公開したAPI(を表すアプリケーション)へのアクセス許可を設定する。Azure AD > 管理 > アプリの登録をクリックしてAPI Clientを表すアプリケーションを選択し、管理 > API のアクセス許可 を開いて、[+アクセス許可の追加]をクリックする。

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

画面が切り替わるので、ここでアクセス許可を追加したいスコープを選択して[アクセス許可の追加]をクリックする。今回の場合、マニフェストに追加したAPI.Requestが確認できるので、これを選択して[アクセス許可の追加]をクリックする。

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

その他の設定項目は以下の通り。記載されていない設定項目はデフォルトでよい。指定後、[作成]をクリック。
設定項目 | 値 |
---|---|
承認許可の種類 | クライアントの資格情報(Client Credentials) |
承認エンドポイントのURL | 先ほどメモした値 |
承認要求方法 | POSTも選択 |
トークンエンドポイントのURL | 先ほどメモした値 |
クライアントの資格情報 | API Clientを表すアプリケーション作成時に取得したクライアントIDとクライアントシークレット |
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として先ほど作成したもの(今回の例ではlogico-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は本来なら設定する必要がないのだが、取得したOAuth2トークンを調べた限り、APIMが期待しているIssuerと異なるため、今回はこのIssuerを追加している。
設定項目 | 値 |
---|---|
Header name | Authorization |
Failed validation error message | 認証が失敗しました。アクセストークンがないか、適切ではありません。 |
Issuers | https://sts.windows.net/{tenant id}/ |
Required claims > Name | aud |
Required claims > Match | any |
Required claims > Values | アプリケーション ID の URIとアプリケーションID つまり、api://xxxxxとxxxxxを2個。 |
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@match | any |
validate-jwt/required-claims/claim/value | アプリケーション ID の URIとアプリケーションID つまり、api://xxxxxとxxxxxを2個。 |
以上で完了。
試してみる
REST ClientとしてPostmanを使う。何も考えずにAPIを呼び出すとAuthorizationヘッダーにBearer tokenをつけていないので、当然401が返ってくる。

では、続いてAccess tokenを取得し、取得したtokenをBearer tokenとしてつけて呼び出す。Client credentials grantでOAuth 2.0 tokenを取得する。このとき、Scopeには以下の文字列を指定する。
{APIを表すアプリケーションID}/.default
例えばAPIを表すアプリケーションIDが6ae96d41-273e-5c15-caa4-def0053b6a26である場合、以下の値をScopeに指定する。
6ae96d41-273e-5c15-caa4-def0053b6a26/.default

取得したtokenを使って呼び出すと、問題なく200が返ってくることがわかる(200でResponseがないのは、Query Parameterを指定していないためで、この挙動自体に問題はない)。

JWTトークンの内容を見ると、以下のよう。
