Power Automate で Graph API の「委任されたアクセス許可」でアクセストークンを発行する方法

# はじめに

以前投稿しました[「Power Virtual Agents と Power Automate でユーザーのパスワードリセットするチャットボット作成【情シスボットシリーズ①】」](https://qiita.com/MiyakeMito/items/e433059661dbfcd4fdf4)では、Graph PAI 認証に [OAuth 2.0 リソース所有者のパスワード資格情報 (ROPC) 付与](https://docs.microsoft.com/ja-jp/azure/active-directory/develop/v2-oauth-ropc) を利用しました。
この認証方式は、API利用者の資格情報をIDPに送信し、トークンを受信します。
アプリケーション（Power Automate）にユーザーのパスワードを保持する必要があります。また、多要素認証（MFA）によるログインには対応していません。

より安全な認証方式である[「OAuth 2.0 認証コードの付与フロー」](https://docs.microsoft.com/ja-jp/graph/auth-v2-user)を利用したPower Automateによる実装を記載します。

本記事を投稿するにあたり、
@r-wakatsuki さんの [Microsoft FlowでMicrosoft Graph APIを利用する２通りの方法](https://qiita.com/r-wakatsuki/items/3c84fff0471c658a99c1)
を大変参考に（ほぼコピー）させていただきました。ありがとうございます。

仕様変更等により、上記記事の内容では動作しなかった部分を、本記事では現在の仕様に合わせた方法で記載しています。

また、Docsも参考にしています。

https://docs.microsoft.com/ja-jp/graph/auth-v2-user




# 注意
プレミアムコネクタを利用します。有料ライセンスが必要です。
運用環境での使用は許可されていませんが、開発向けプランや開発者テナントであれば無償でお試しいただけます。

[開発者向けプラン](https://powerapps.microsoft.com/ja-jp/developerplan/)
[Microsoft 365 開発者テナント ](https://developer.microsoft.com/ja-jp/microsoft-365/dev-program)








# 1．Azure Portalでアプリを登録する

## 1-1．アプリケーション登録

![{5DB2ECAB-E045-4E79-BEA6-90E21F38D16E}.tmp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/8d2e4712-2808-7a86-9a23-a04be5727ebd.png)

https://portal.azure.com/ に管理者権限でログインし、[アプリの登録]－[新規作成]


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/5fefc609-a9ba-3992-ac38-47e2a8e747ed.png)
任意の名前を入力、[アカウントの種類を追加]はマルチテナントを選び[登録]

:::note alert
OAuth 2.0 認証コードの付与フローでは、アカウントの種類は
**任意の組織ディレクトリ内のアカウント (任意の Azure AD ディレクトリ - マルチテナント)**
で設定してください。
承認要求で、common エンドポイントを使用する場合は、アプリケーションをマルチテナントとして構成する必要があるためです
:::

![{5DB2ECAB-E045-4E79-BEA6-90E21F38D16E}.tmp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/4c901fa7-63f7-439b-49e1-9a26bafe45a9.png)
アプリケーション(クライアント)ID と ディレクトリ (テナント) ID をコピーしておきます。



## 1-2．APIアクセス許可設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/668318a9-d7b4-45a1-b865-ffc7c23e1a0e.png)
[APIのアクセス許可]－[アクセス許可の追加]

![{5DB2ECAB-E045-4E79-BEA6-90E21F38D16E}.tmp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/1fe438d5-f3c3-3e52-9199-0ec00682fc26.png)
[Microsoft Graph]を選択

![{5DB2ECAB-E045-4E79-BEA6-90E21F38D16E}.tmp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/4267e757-fd17-c097-caeb-dd6033c6b30f.png)
[委任されたアクセス許可]－[{任意の権限スコープを設定し}]－[アクセス許可の追加]


![{5DB2ECAB-E045-4E79-BEA6-90E21F38D16E}.tmp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/4b484efa-4f64-7f72-32eb-555fa77f1dd9.png)
追加したアクセス許可に管理の同意を与えます。







## 1-3．クライアントシークレット追加

![{5DB2ECAB-E045-4E79-BEA6-90E21F38D16E}.tmp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/1cd5c73e-522f-cb2b-6162-dd301c7739e9.png)
[証明書とシークレット]－[新しいクライアントシークレット]

![{5DB2ECAB-E045-4E79-BEA6-90E21F38D16E}.tmp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/4f9a6503-f93b-36e0-efd8-c59c96046f30.png)
クライアントシークレットの有効期限は、以前「無制限」が存在していましたが、今は最長24ヶ月です。
ただし、Powershellからの追加であれば設定可能です。
https://jpazureid.github.io/blog/azure-active-directory/azuread-clientsecrets-202104/


![{5DB2ECAB-E045-4E79-BEA6-90E21F38D16E}.tmp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/2e5374d4-75e5-21a9-6428-ebb5c429e8e4.png)
シークレットの値をコピーしておきます。

:::note warn
この画面から遷移してしまうと、シークレットの値は再表示できなくなります。
:::




## 1-4．応答URIを設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/ecc3bdd2-5a85-f69e-5d2c-0113bc077e59.png)

[認証]－[プラットフォームを追加]－[web]

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/cb79f178-2a32-0d15-9ee3-9b9354715dad.png)
[リダイレクト URI]に

```
http://localhost/myapp/
```

を入力し－[構成]










# 2.Power Automate アクセストークンを取得

以下の仕様で、Graph　APIへのトークンリクエストの仕組みを作ります。

1. Graph APIにアクセスするたびに、新しいアクセストークンとリフレッシュトークンを取得する
1. 最新のリフレッシュトークンは OneDrive for Business に登録する


Microsoft ID プラットフォームのエンドポイントからアクセス トークンを取得する際の仕様は以下です。

* 発行されるアクセストークンの有効期限は長くはありません
* 新しいアクセストークンを取得するためには、リフレッシュトークンが必要
* スコープにoffline_accessを含んだ状態でアクセストークンを取得すると、アクセストークンに加えリフレッシュトークンも取得できる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/eca51bf0-d8b2-fb14-de60-d78c463d37d6.png)

Azure AD に対し承認要求します。
承認され発行された認可コードを元に、再度Azure ADへアクセストークンをリクエストします。
アクセストークンと共にリフレッシュトークンが発行されます。
リフレッシュトークンをODfBへ登録します。
ここまでの手順はアプリケーション登録後、初回のみ実行します。

API実行のつど、前回のリフレッシュトークンを使いアクセストークンを発行要求します。
この時もアクセストークンと共にリフレッシュトークンが発行されますので、ODfBへ登録しておきます。


## 2-1.承認要求

Webブラウザのアドレスバー下記のURLを入力し、承認要求エンドポイントへアクセスします。
{アプリケーション(クライアント)ID}は 「1-1．アプリケーション登録」 でコピーした値です。

```
https://login.microsoftonline.com/common/oauth2/v2.0/authorize
?client_id={アプリケーション(クライアント)ID}
&response_type=code
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&response_mode=query
&scope=offline_access%20user.read%20mail.read
&state=12345
```
365アカウントでサインインすると、下記画面が表示されますので、[承認]。
[組織の代理として同意する]にチェックを入れると、`&scope=` で記載しているアクセス許可に対し、管理の同意が行われます。（「1-2．APIアクセス許可設定」の操作と同様の結果となります）

![{5DB2ECAB-E045-4E79-BEA6-90E21F38D16E}.tmp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/4298b248-2edc-9aee-7a66-064167c38bea.png)



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/7b0e9a5a-4ed8-7d1a-573c-62bd62fcb6a6.png)
その後、「申し訳ございません。～」のメッセージが表示されますが、URL欄に表示されたリダイレクト先 `localhost/myapp/` に `code=` のパラメータが含まれていれば承認の要求は成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/fc27ae7f-772a-8b5c-811a-ad45d05638cd.png)
表示されているURLのうち、認可コードとなる `code=` のパラメータ （`code=` から `&state=` まで）の値をコピーします。











## 2-2.リフレッシュトークンをODfBに保存する

Power Automate でプッシュトリガーフローを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/8cbda3af-dc4b-8ede-e709-4f7b1d024848.png)

HTTPアクション を追加し以下のように設定します。
![{5DB2ECAB-E045-4E79-BEA6-90E21F38D16E}.tmp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/1d46c068-cf41-0efa-8458-21ac10e02f67.png)
■方法
```
POST
```

■URI
```
https://login.microsoftonline.com/common/oauth2/v2.0/token
```

■ヘッダー
```
Content-Type : application/x-www-form-urlencoded
```

■本文
```
client_id={「1-1．アプリケーション登録」でコピーしたアプリケーション(クライアント)ID}
&scope=offline_access%20user.read%20mail.read
&code={「2-1.承認要求」で取得し認可コード}
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&grant_type=authorization_code
&client_secret={「1-3．クライアントシークレット追加」で取得したシークレット}
```

OneDrive for Business コネクタの「ファイルの作成」アクションを追加し、下記のように設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/23d5b451-53fd-bd70-bf59-7fd623014e82.png)
■フォルダーパス
任意

■ファイル名
任意

■ファイルコンテンツ
```
body('HTTP')?['refresh_token']
```



:::note info
ここまでの、1-1.から2-2.までの処理は、一度実行すればOKです。
この後の2-3.のみ、Grahp実行毎に実行する必要があります。
:::



## 2-3.リフレッシュトークンからアクセストークンを取得しAPIを実行する

Power Automate でフローを任意のトリガーで作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/08a4f21d-f229-4541-21f8-37eafd1f52de.png)


OneDrive for Business コネクタの「パスによるファイル コンテンツの取得」アクションを追加し、下記のように設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/88750541-7368-f3c8-87ac-2c84b48e2f1d.png)
■ファイルパス
「2-2.リフレッシュトークンをODfBに保存する」でリフレッシュトークンを保存したファイル名

リフレッシュトークンを元に、アクセストークンとリフレッシュトークンを取得します。
HTTPアクション を追加し以下のように設定します。
![{5DB2ECAB-E045-4E79-BEA6-90E21F38D16E}.tmp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/d4bf2f21-6862-3046-fe50-4de1088df347.png)
■方法
```
POST
```

■URI
```
https://login.microsoftonline.com/common/oauth2/v2.0/token
```

■ヘッダー
```
Content-Type : application/x-www-form-urlencoded
```

■本文
```
client_id={「1-1．アプリケーション登録」でコピーしたアプリケーション(クライアント)ID}
&scope=offline_access%20user.read%20mail.read
&refresh_token=@{body('パスによるファイル_コンテンツの取得')}
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&grant_type=authorization_code
&client_secret={「1-3．クライアントシークレット追加」で取得したシークレット}
```

再取得したリフレッシュトークンをODfBに上書きします。
OneDrive for Business コネクタの「ファイルを更新します」アクションを追加し、下記のように設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/f52a9467-9491-08bb-d7ca-289b1d2edcfc.png)
■ファイル
「2-2.リフレッシュトークンをODfBに保存する」でリフレッシュトークンを保存したファイル名
■ファイルコンテンツ
```
@{body('HTTP')?['refresh_token']}
```

## 2-4.アクセストークンを使用してGraphを呼び出す

アクセス トークンの取得後は、そのトークンを使用して (トークンを要求の Authorization ヘッダーに含める)、Microsoft Graph を呼び出すことができます。
HTTPアクション のヘッダー部分は以下のように設定してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/73bba1c4-3df6-f0fd-e170-5aa0514f0d14.png)
■ヘッダー
```
Authorization : Bearer @{body('HTTP')?['access_token']}
```
他の項目は呼び出すGraphの仕様に従ってください。



以上です