【OutSystems】OAuth2.0のクライアントクレデンシャルズ方式を実装した

諸事情によりSharePointのリストに格納されているデータを日次バッチでOracleのデータベースに取り込む仕組みを構築する必要がありOutSystemsを使ってバッチを実装したのでメモ。
ハードルとなるのはM365の世界にあるデータ（SharePointのリスト）にどうやってバッチがアクセス（主に認可・認証関係）してOracleの世界にデータを突っ込むかということ。
結論から言うとOAuth2.0の実装が必要となるのだが、今回M365（EntraID）側の作業者とも連携して作業を進める必要がありあっち側の世界の作業も含めて全体感を記録しておく。

## 1.やりたいこと
OutSystems側のバッチ処理が起動してSharePointのListデータにアクセスしてユーザーIDや登録日の情報を取得してOracleのDBにインサートするバッチです。SharePointへのアクセスにあたってはEntraID側で必要な認可設定を事前にしてもらいアクセストークンの発行が必要となります。バッチアプリはトークン受領後にSharePointに対してGraph APIを発行して対象のデータをゲットしてきます。（本記事では①～③までを記載）
![スクリーンショット 2024-07-15 104109.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/0a2bcc75-9a7b-1d32-0081-363a5f5e5a39.jpeg)
この処理でEntraIDはM365の利用ユーザーに対してアクセス許可、認可を行うのではなくバッチアプリケーションに対して認可を行う必要があるためクライアントクレデンシャルズ方式での実装が必要となります。

※そもそものOAuth2.0とは？に関してはこちらの記事が参考になります。
[OAuth 2.0 全フローの図解と動画](https://qiita.com/TakahikoKawasaki/items/200951e5b5929f840a1f)


## 2.処理概要
### 2.1 事前の準備作業（EntraID側の管理者作業）
まずはEntraID側でアクセスしてくるプログラムを予め許可してあげる作業が必要となる。
具体的には以下の認証情報の払出とアクセス許可の設定作業です。（この辺が結構これまで曖昧だったけどEntraIDの担当者と会話して初めて何しているのか分かりました。）

その１-EntraIDの担当者に相談して以下の情報を払出してもらう。
　【Tenant】：M365のテナントID（M365契約時に発行されているはず）
　【client_id】：EntraID側で割り当てるアプリの識別ID（アプリ単位で割り当て）
　【client_secret】：EntraID側で生成した秘密鍵情報の様な情報
 
その２-SharePointのサイトに対してバッチアプリの権限を付与してもらう
　・バッチアプリに対して特定のSharePointサイトのSites.Read.Allを付与

 上記２つの作業をすることで必要な認証と認可の事前準備が整います。

 
### 2.2 アクセストークンの要求処理（バッチ開発者側の作業）
開発者側はMicrosoftから公開されている[クライアント資格情報フロー](https://learn.microsoft.com/ja-jp/entra/identity-platform/v2-oauth2-client-creds-grant-flow#first-case-access-token-request-with-a-shared-secret)のAPIのIFに沿って必要な情報をセットします。

必要なパラメータは以下です。
【Tenant】：事前準備で払い出されたTenantIDをセット
【client_id】：事前準備で払い出されたアプリIDをセット
【scpoe】：トークンに付与する権限（https：//graph.microsoft.com/.default)
　※上記の場合EntraID管理者がその２で設定したGraphAPIのアクセス権が付与される
【client_secret】：事前準備で払い出されたクライアントシークレットをセット
【grant_type】：client_credentials（固定）をセット

これをEtnraIDにリクエストして問題無ければ成功応答が返ってきます。
EntraIDからのレスポンスパラメータ
【access_token】：アクセストークン文字列
【token_type】：トークインタイプ（bearer）
【expire_in】：有効時間


### 2.3 GraphAPIの発行（バッチ開発者側の作業）
トークンの情報をヘッダーにセットしてSharePointに対してデータ取得のAPI（GraphAPI）を発行します。GraphAPIの細かい仕様は[こちら](https://learn.microsoft.com/ja-jp/graph/api/listitem-get?view=graph-rest-1.0&tabs=http#http-request)を参照。
今回はSharePointのListのItem情報を取得する以下のAPIを発行します。

https：//graph.microsoft.com/v1.0/sites/<b>{site-id}</b>/lists/<b>{list-id}</b>/items?expand=fields(select=<b>{item_name}</b>)

リクエストパラメータの詳細
【site-id】：SharePointサイトの一意識別番号
【list-id】：リストの一意の識別番号
【Item_name】：取得項目

上記の処理を実装することでSharePointのListの情報をJson形式で取得できるので後はプログラム側でよしなに集計してOracleにインサートしてあげればOKです。

## 3.OutSystemsでの実装処理
### 3.1 アクセストークンの要求処理
まずはアクセストークンの取得と返却値を受け取る処理を実装します。
・REST処理からアクセストークンを取得するAPIをコンジュームしてあげます。
・必要なパラメータはSite Propertiesにセットしています。
　※client_secretは暗号化してDBに持たせた方がいいのかもしれない。。。
・要求が成功するとResponseのAccess_tokenにトークンがセットされて返ってきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/01590515-b647-1655-dcf7-e06cd6672632.png)
トークン取得用のREST APIメソッドを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/72440fd9-abd7-ed02-e324-cfd0381886c6.png)
このAPI（RequestToken）をバッチの初期処理で呼び出してあげればトークンの取得が可能です。


### 3.2 SharePointへのGraphAPIの発行
次に発行されたトークンを使ってSharePointに対してデータ取得用のGraphAPIを発行します。
・サイトIDやリストIDをパラメータにGET処理を投げます。
・リクエストパラメータのAuthorizationには取得したトークン文字列をセットしてあげます。
・Listから取得したデータはFields各項目にリスト形式でセットされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/4c70d89e-c5c6-e95f-2674-94c2fa1b68b0.png)
GraphAPI発行用のREST APIメソッドを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/616b1451-32c5-c4b0-7f47-8b6b54a1bc3a.png)

ちなみにトークン文字列がセットされているAuthorizationはRequestHeadersで使用します。（この情報をみてSharePoint側はアクセスの可否を判断します。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/d62403e9-a6a4-fe73-48c4-efb13ba7eb08.png)

このAPI（GetListData）をバッチで呼び出してあげればSharePointのListデータの取得は可能となります。
後は取得したリストの件数分インサート処理を実装してあげればOracleへのデータ登録が可能になります。

今回はSharePointとの連携を実装しましたがM365のサービス全般（OneDriveなど）も含めてこの考え方が活用できそうです。M365とOutSystemsの異なる世界観でのデータ連携ではOAuth認証やGraphAPIの発行といった仕組みを活用することで幅が広がりそうですね。