Office365連携アプリからのリソースへのアクセスを企業管理者が許可するためのscope設定

Office365のOutlook予定表とOAuth2.0、Outlook REST API v2.0で連携しているサービスを運用していて、AzureADで一般ユーザーの連携アプリの利用を制限している企業への導入で躓いたので、対応方法を残しておきます。

参考： [Azure AD v2 endpoint – How to use custom scopes for admin consent](https://tsmatz.wordpress.com/2018/02/07/azure-active-directory-v2-endpoint-custom-scope-for-admin-consent-and-application-permissions/)

#前提
## 発生していた事象
+ サードパーティ製のアプリの利用を制限しているOffice365環境で、弊社製の連携アプリが利用できない
+ 企業の管理者の方はポリシー的に弊社製のアプリだけ利用を許可することは可能と言っている

## やりたいこと
+ サードパーティ製のアプリを制限しているOffice365環境で、管理者がOfficeのリソースへアクセスする特定のアプリの使用を許可し、一般ユーザーが使用できるようにする
+ APIはMicrosoft　Graphのエンドポイントではなく、レガシーのOutlook API エンドポイントを使っている場合でも対応できるようにする

# 実現方法
やりたいことを実現するための手順を予め箇条書きにすると以下の3工程となります。

1. Application Registration Portalでのscopeの設定  
1. AdminConsentで管理者が連携アプリに対してリソースアクセスを許可  
1. 一般ユーザーが通常通りOAuth認証でアプリの利用を始める

以下、順を追って手順を記します。

## Application Registration Portalでのscopeの設定
### OAuthのURIとscope
通常、連携アプリのscopeはOAuth認証時のURIで設定します。

**OAuth URI例**

```
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=xxxxx
&redirect_uri=xxxxx&response_type=code&scope=https%3A%2F%2Foutlook.office.com%2FCalendars.ReadWrite+openid+email+profile+offline_access&state=xxxxx
```

こうすることでユーザーが連携アプリに対してscope以下に書かれるリソースへのアクセスを許可することができます。

しかし、企業で管理しているアカウントの場合、企業管理者が連携アプリのリソースアクセスを制限していると、上記のOAuth認証をしようとしても以下のようなエラーとなります。

**OAuthエラー**
![認証エラー](https://qiita-image-store.s3.amazonaws.com/0/44798/1cc4d0e1-6351-d5fb-bf21-3c0ea9fa64ed.png)

### 管理者制限時のscope設定
このような場合、AdminConsentを利用し管理者が連携アプリからのリソースアクセスを許可すれば一般ユーザーがアプリを利用できるようになるのですが、そのためには[Application Registration Portal](Application Registration Portal - Microsoft)で予め許可するscopeを設定する必要があります。

![scope設定](https://qiita-image-store.s3.amazonaws.com/0/44798/ea738d82-0dc9-5b12-625b-08ee0a454511.png)

しかし、このページのUI上ではMicrosoft Graphのscopeしか設定できません。

今回、利用する **Outlook予定表のReadWrite**(https%3A%2F%2Foutlook.office.com) はMicrosoft Graphではないため、ページ上からは追加できませんでした。

### マニフェストの直接編集
このような場合は、マニフェストを直接編集します。
ページ下部の詳細オプション内の「アプリケーション マニフェストの編集」をクリックすると、マニフェストのJSONを編集する画面が開きます。

**マニフェスト編集画面**
![マニフェスト編集](https://qiita-image-store.s3.amazonaws.com/0/44798/f0cf2000-883e-16a9-9112-6e67f20ca162.png)

この中の`"requiredResourceAccess"`がアクセス許可を設定する要素です。
ここにOutlook予定表のReadWriteを追記すれば良いのですが、ID等に何を設定すれば良いかわかりませんね……

### scopeのIDの確認方法
IDは[AzurePortal](Microsoft Azure portal)の「Azure Active Directory>アプリの登録」で調べることができます。
ここで適当なアプリを登録し、「設定>必要なアクセス許可」で任意のアクセス許可を設定します。
こちらではMicrosoft Graph以外のscopeも選択可能です。
今回設定するOutlook予定表のReadWriteはOffice365ExchangeOnlineの「Read and write user and shared calendars」に該当するため、それを登録します。

![必要なアクセス許可](https://qiita-image-store.s3.amazonaws.com/0/44798/202577a7-c2be-3b4f-5f4a-e47c21012fbc.png)

その上で設定の横の「マニフェスト」をクリックしマニフェスト編集画面を開くと`"requiredResourceAccess"`の中にOutlook予定表のReadWriteに該当する要素が登録されています。

![マニフェスト編集ボタン](https://qiita-image-store.s3.amazonaws.com/0/44798/efce07ea-fbf1-8b85-d567-585fa8975709.png)

![マニフェスト編集](https://qiita-image-store.s3.amazonaws.com/0/44798/a744653c-acd5-bd24-4b8a-5c5e565eef08.png)

これをそのままコピーして"Application Registration Portal"のマニフェストの`"requiredResourceAccess"`に追加することで、Microsoft Graph以外のscopeを追加することが可能です。

## AdminConsentで管理者が連携アプリに対してリソースアクセスを許可
管理者が特定のアプリのリソースへのアクセスを許可するためにはAdmin consentを利用します。

参考： 
[Azure Active Directory v2.0 と OAuth 2.0 クライアント資格情報フロー](https://docs.microsoft.com/ja-jp/azure/active-directory/develop/active-directory-v2-protocols-oauth-client-creds)
[How to use Application Permission with Azure AD v2 endpoint](https://tsmatz.wordpress.com/2016/10/07/application-permission-with-v2-endpoint-and-microsoft-graph/)


管理者が以下のようなAdminConsent用のURLにアクセスすると、アプリがリソースへアクセスすることを全ユーザーに対して適用するかの承諾画面になります。

**AdminConsent URI例**

```
https://login.microsoftonline.com/common/adminconsent?client_id=xxxx&redirect_uri=xxxx&response_type=code&state=xxxx
```

この際、画面には「Application Registration Portal」で設定したscopeが表示されていると思います。
(今回の例では、マニフェストに直接記述したOutlook予定表の権限が`Read and write user calendars`として表示されます)

**AdminConsent 承諾画面**
![Admin Consent](https://qiita-image-store.s3.amazonaws.com/0/44798/ba584ff0-56d1-decb-2ca4-542e1229b83e.png)

ここで「承諾」すると、一般ユーザーがOAuthの認証を行うことができるようになります。

## 一般ユーザーが通常通りOAuth認証でアプリの利用を始める
ここまで来ると、後は特にやることはありません。
連携アプリからのOfficeリソースへのアクセスが管理者によって許可されているため、一般ユーザーは通常通りアプリからOAuth認証すれば利用を開始することができます。

# 【補足】管理者によるリソースアクセスの制限
最後にそもそも管理者がどうやってリソースアクセスの制限をかけているのかについても書いておきます。
Office365環境で、企業管理者がサードパーティ製のアプリを制限するためには複数の設定方法があるようです。

## Office365の管理者ページでの設定 
Office365の管理者ページで「設定>サービスとアドイン>統合アプリ」を開き、サードパーティのアプリがOffice365の情報にアクセスできるかどうかの設定を"オフ"にする
![O365 統合アプリ](https://qiita-image-store.s3.amazonaws.com/0/44798/5ae52ae4-e779-d36b-af7d-8f9af7f98e96.png)

## AzurePortalのAzureADので設定
[AzurePortal](Microsoft Azure portal)で「Azure Active Directory>管理/ユーザー設定」を開き、エンタープライズアプリケーションの「ユーザーはアプリが自身の代わりに会社のデータにアクセスすることを許可できます」を"はい"にする

![AD アクセス許可](https://qiita-image-store.s3.amazonaws.com/0/44798/79a7970b-350e-b24e-1291-81d1320d3e2b.png)

上記2つの設定は連動している様で、片方の設定をするともう片方にも反映されます。
(ただし、画面に反映されるまでラグがあることが……)

この設定をすることで、一般ユーザーはサードパーティ製のアプリを勝手に登録することができなくなります。

# 最後に
今回、Outlook REST APIを、Microsoft Graph ではなく Outlook API エンドポイント (https://outlook.office.com/api) で利用していたため、マニフェストの直接編集という手間が発生してしまいました。
今後新規にAPIを使うならMicrosoft Graphのエンドポイントを使う方がいいんじゃないかな？と思います。

[Microsoft Graph と Outlook REST API のエンドポイントの比較](https://docs.microsoft.com/ja-jp/outlook/rest/compare-graph-outlook)