#はじめに
本記事では、Microsoft FlowからMicrosoft Graph APIを利用する際の2通りの実装方法の手順を続けて紹介していきます。
また今回の手順の紹介を通じてAzure ADにおける認証プロトコル(Azure AD v2.0エンドポイント)に対する理解も深めていきます。
#方法1:アプリがユーザーに成り代わってGraph APIにアクセスする方法
###前提
- Office365アカウントを利用します。
- ここでは例として「User.Read」権限を利用してユーザー情報をGraph APIから取得するFlowを作成します。
- Azure AD、Flow、OneDrive for Businessの機能を利用します。
- Graph APIにアクセスするたびに新しいアクセストークンとリフレッシュトークンを取得します。
- 最新のリフレッシュトークンを保持するリポジトリとしてOneDrive for Businessを利用します。
また、手順を始める前にAzure AD v2.0 エンドポイントに関する以下の基本情報を頭に入れておくと捗ります。
- Azure ADは認証に成功したクライアントにアクセストークンとリフレッシュトークンを発行する。
- リソース(Graph API)アクセス時の認可に必要なアクセストークンの有効期限は短い。(標準で1時間)
- 新しいアクセストークンを取得するためにはリフレッシュトークンが必要。
- offline_access権限を利用するとリフレッシュトークンを利用して新しいアクセストークンを取得する際に同時に新しいリフレッシュトークンも取得できる。
###アプリを登録する
アプリを Azure AD v2.0 エンドポイントに登録する を参考に Microsoft アプリ登録ポータル にてAzureADにアプリの登録を行います。設定は下記のように行ってください。
- プロパティ :任意の名前を指定(今回は「testApp」)。アプリケーションIDを控えておく。
- アプリケーション シークレット :[新しいパスワードを生成]をクリック。生成されるパスワードを控えておく。
- プラットフォームの追加 :[プラットフォームの追加]をクリックして[Web]を選択し、リダイレクト URLに「http://localhost/myapp/」を指定。
- Microsoft Graph のアクセス許可 :「委任されたアクセス許可」で[追加]をクリックし、「offline_access」を選択。(このアクセス許可が付与されなければ新しいリフレッシュトークンが発行されず、新しいアクセストークンを継続的に取得することができない)
最後に[保存]をクリックして登録を完了させます。
###承認を取得する
Webブラウザで以下の同意エンドポイントURLにアクセスします。(見やすさのため改行を入れています)
<アプリケーションID>にはアプリ登録時に控えた値を指定します。
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?
response_type=code&
redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F&
response_mode=query&
scope=offline_access%20user.read&
state=12345&
client_id=<アプリケーションID>
Office365アカウントでサインインし、画面表示される下記の同意エクスペリエンス画面で[承諾]をクリックします。(全体管理者でサインインした場合は、「組織の代理として同意する」チェックボックスが表示されますが、今回はチェックは不要です。)
以下のようなlocalhostへの接続が拒否された旨のエラー画面が表示され、URL欄に表示されたリダイレクト先 localhost/myapp/ にcodeパラメータが含まれていれば承認の取得は成功です。codeパラメータの値を控えておいてください。
###リフレッシュトークンを取得してOneDriveに保存する
新規フローを作成し、「モバイルのflowボタン」トリガーを追加。
「HTTP」アクションを追加し、以下のように設定。
・方法:POST
・URI:https://login.microsoftonline.com/common/oauth2/v2.0/token
・ヘッダー Content-Type:application/x-www-form-urlencoded
・本文:
client_id=<アプリ登録時に控えたアプリケーションID>
&scope=user.read
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&grant_type=authorization_code
&client_secret=<アプリ登録時に控えたパスワード>
&code=<承認取得時に控えたコードパラメータ>
「json の解析」アクションを追加し、以下のように設定。
・コンテンツ:@{body('HTTP')}
・スキーマ:{"type": "object","properties": {"token_type": {"type": "string"},"scope": {"type": "string"},"expires_in": {"type": "integer"},"ext_expires_in": {"type": "integer"},"access_token": {"type": "string"},"refresh_token": {"type": "string"}}}
OneDrive for Businessの「ファイルの作成」アクションを追加し、以下のように設定。
・フォルダーのパス:OneDrive内の任意のパス(今回はルートパス)
・ファイル名:任意のファイル名(今回は「testApp_refreshToken.info」)
・ファイルコンテンツ:@{body('JSON_の解析')?['refresh_token']}
作成したFlowを実行し、正常に実行されたことを確認します。
※このときHTTPアクションで「AADSTS70008」エラーが発生してFlowが失敗した場合は、承認取得時のコードが期限切れとなっているため、承認取得手順を再度実施し新しいコードを使用してFlowを作成してください。
OneDriveにリフレッシュトークンを格納できたら、ここで作成したFlowは不要のため削除して構いません。
##Graph APIを利用するFlowの作成
新規フローを作成し、「モバイルのflowボタン」トリガーを追加。
OneDrive for Businessの「パスによるファイル コンテンツの取得」アクションを追加し、以下のように設定。
・フォルダーのパス:OneDriveに作成したtestApp_refreshToken.infoのパス
「HTTP」アクションを追加し、以下のように設定。
・方法:POST
・URI:https://login.microsoftonline.com/common/oauth2/v2.0/token
・ヘッダー Content-Type:application/x-www-form-urlencoded
・本文:
client_id=<アプリ登録時に控えたアプリケーションID>
&scope=offline_access%20user.read
&refresh_token=@{body('パスによるファイル_コンテンツの取得')}
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&grant_type=refresh_token
&client_secret=<アプリ登録時に控えたパスワード>
「json の解析」アクションを追加し、以下のように設定。
・コンテンツ:@{body('HTTP')}
・スキーマ:{"type": "object","properties": {"token_type": {"type": "string"},"scope": {"type": "string"},"expires_in": {"type": "integer"},"access_token": {"type": "string"},"refresh_token": {"type": "string"}}}
「HTTP」アクションを追加し、以下のように設定。
・方法:GET
・URI:https://graph.microsoft.com/v1.0/me
・ヘッダー Authorization:Bearer @{body('JSON_の解析')?['access_token']}
OneDrive for Businessの「ファイルを更新します」アクションを追加し、以下のように設定。
・フォルダーのパス:OneDriveに作成したtestApp_refreshToken.infoのパス
・ファイルコンテンツ:@{body('JSON_の解析')?['refresh_token']}
###動作確認
Flowを実行すると、HTTP2アクションの出力の本文に、アクセス許可の委任を同意したユーザーのユーザー情報が表示されます。Flowを実行するたびにOneDriveに保存されたリフレッシュトークンが更新されて、Flowを繰り返し実行できれば動作はOKです。
#方法2:アプリが直接Graph APIにアクセスする方法
###前提
- Office365アカウントを利用します。
- ここでは例として「Calendar.Read」権限を利用して予定表のイベント情報をGraph APIから取得するFlowを作成します。
- Azure AD、Flow、Exchange Onlineの機能を利用します。
###アプリを登録する
方法1で利用したアプリ登録ポータルは古いポータルであり、方法2で実施する一部設定が出来ないため、次は新しいポータルとなるAzure Portalを利用してアプリを登録していきます。
Microsoft Azure ポータル に接続して画面左のブレードメニューから[Azure Active Directory]-[アプリの登録(プレビュー)]と開き、「+ 新規登録」をクリックします。(アプリ一覧には先程登録したアプリ(testApp)が表示されています。)
「名前」で任意のアプリ名(今回はtestApp2)を指定し、「登録」をクリックします。
testApp2の[概要]を開いて、[アプリケーション(クライアント)ID]と[ディレクトリ(テナント)ID]の値を控えておきます。
[testApp2 - APIのアクセス許可]を開いて、「+ アクセス許可の追加」クリックします。
「アプリケーションの許可」を選択し、利用したいアクセス許可(今回は「Calendar.Read」)をチェックして、「アクセス許可の追加」ボタンをクリックします。
[testApp2 - APIのアクセス許可]を開いて、[***に管理者の同意を与えます]をクリックし、確認ダイアログで「はい」をクリックします。
[testApp2 - 証明書とシークレット]を開いて、[+ 新しいクライアントシークレット]をクリックし、追加ダイアログで[追加]をクリックします。新しく生成したシークレットの値を控えます。
###Graph APIを利用するFlowの作成
新規フローを作成し、「モバイルのflowボタン」トリガーを追加。
「HTTP」アクションを追加し、詳細オプションを展開して以下のように設定。
・方法:GET
・URI:https://graph.microsoft.com/v1.0/users/<アプリを登録したAzureAD上の任意のユーザーのUPN>/events
・認証:Active Directory OAuth
・テナント:<アプリ登録時に控えたディレクトリID>
・対象ユーザー:https://graph.microsoft.com
・クライアントID:<アプリ登録時に控えたアプリケーションID>
・資格情報の種類:シークレット
・シークレット:<アプリ登録時に控えたシークレット>
###動作確認
Flowを実行して、HTTPアクションの出力の本文に、先程指定したUPNのユーザーの予定表のイベント情報が表示できていれば動作はOKです。
#方法1と方法2の違い
ここまで紹介した2つの方法に見られるAzure AD v2.0エンドポイントの利用の違いを自分なりに解釈して以下の通り整理してみました。(まだ理解の浅い部分も多分にあるので間違っていたらご指摘ください)
認証フローの違い
一番分かりやすい OAuth の説明 および v2.0 プロトコル - OAuth 2.0 と OpenID Connect を参考に、方法1,方法2それぞれをOAuth 2.0 フローに当てはめてみます。
・方法1
①②③④:「承認を取得する」手順に対応
⑤⑥:「リフレッシュトークンを取得してOneDriveに保存する」手順に対応
補足すると、実際のサードパーティアプリでは①②と④⑤⑥のフローはWeb画面の自動遷移により自動的に行われますが、今回はFlowだけを利用しているため「承認を取得する」「リフレッシュトークンを取得してOneDriveに保存する」手順での手作業が発生しています。
・方法2
アプリ登録時にアプリに付与するアクセス許可の種類の違い
・方法1:[委任されたアクセス許可]により、同意エクスペリエンスによりユーザーからアクセス許可を委任されて利用できるアクセス権
・方法2:[アプリケーションのアクセス許可]により、アプリ自身が利用できるアクセス権
アプリがリソース(Graph API)にアクセスする際の違い
・方法1:アプリ(testApp)がアクセス許可の委任に同意したユーザーに成り代わってリフレッシュトークンを使ってAzureADに認証し、リソースにアクセス
・方法2:アプリ(testApp2)がアプリ自身としてシークレットを使ってAzureADに認証し、リソースにアクセス
v2.0 用のアプリケーションの種類のうち該当するアプリパターン
・方法1:モバイル アプリとネイティブ アプリ
・方法2:デーモンおよびサーバー側のアプリ
ユーザーによる同意の種類の違い
・方法1:動的なユーザーの同意(scopeパラメータを使用して承認コードに含めるアクセス許可を動的に指定できる同意のこと)
・方法2:管理者の同意([testApp2 - APIのアクセス許可]で[***に管理者の同意を与えます]をクリックする同意のこと。手順作成後に分かったが、実は管理者用の同意エンドポイントURLを使っても同じ操作が可能)
#実務でFlowからGraph APIを使うなら方法2がおすすめ
方法2の方が構成が簡単になる以外にも以下のような理由があります。
- リフレッシュトークンの有効期限は標準で90日間らしいので、方法1だとFlowを3ヶ月間実行しない(リフレッシュトークンを更新しない)と「承認を取得する」「リフレッシュトークンを取得してOneDriveに保存する」手順が再度発生する。
- 方法1は委任するユーザー自身のデータに限定したアクセス権を定義できるため、一般ユーザーによる利用も可能だが、「承認を取得する」手順を一般ユーザーに行わせるのは難しい。よって管理者が管理目的のため利用するのが現実的。
#Microsoft Graph API が体系的にまとまっているサイト
公式なら Office 365 API や Microsoft Graph REST API v1.0 リファレンス、
MSの中の人の記事なら Microsoft Graph を使ってみよう がおすすめです。
ただ各Graph APIに対応する権限スコープ(アプリに付与するアクセス許可)がまとめられた記事は見当たらなかったため、利用する際は各自で要デバッグです。
#おわりに
今回の方法2を利用して私もPowerApps + Flow + Graph API から成るアプリをいくつか作成して自分で運用しているので、こちらもまたの機会に紹介したいと思います。
Azure AD v2.0エンドポイント(v1.0とは微妙に違いがあるようですが今回の本質ではないので無視しました)は、MS公式でもドキュメントが非常に多岐にわたっており、うかつに深入りすると相当大変であることを実感しました。当初は方法1と2の手順のみを記載したタイトルの範囲内の記事にしようとしていましたが、興味本位で認証のしくみを調べていくうちにこんな枝葉に及ぶ記事になってしまっていました。