タイトルが長くなってしまった…。
いきなり余談だがAzure Active DirectoryがMicrosoft Entra IDに名称変更したみたいだ…。
Node.jsでMicrosoft GraphのAPIを使う時に、まず前段としてアクセストークを取得する必要があるのだが、公式のチュートリアルだとmsal-nodeモジュールを使う方法しか記載がなく、モジュールを使わずに取得する情報が見当たらなかったので書く。
Node.jsでの取得方法
アクセストークンを取得するためにはAzureAD上で作成したアプリケーション(サービスプリンシパル)のクライアントID、テナントID、クライアントシークレットが必要になってくる。
そもそもアプリケーションを作成していない場合は、ここを参考にアプリケーションを作成し、APIアクセス許可やクライアントシークレットの発行まで済ませる。
環境
$ node -v
v18.17.1
$ npm -v
10.0.0
$ npm list
|-- axios@1.5.1
httpリクエストにはAxiosモジュールを使用。
コード
ヘッダーのContent-Typeが、よくあるapplication/json
ではなくて、application/x-www-form-urlencoded
なところが注意点。
// モジュール読み込み
const axios = require('axios');
// AzureAD情報
const clientId = 'クライアントID';
const tenantId = 'テナントID';
const clientSecret = 'クライアントシークレット';
// トークンリクエストのAPIエンドポイント
const tokenEndpoint = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
// トークンリクエストボディ
const reqTokenBody = {
client_id: clientId,
scope: 'https://graph.microsoft.com/default',
client_secret: clientSecret,
grant_type: 'client_credentials'
};
// トークンリクエストのコンフィグ
const reqTokenConfig = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded' // application/jsonではないので注意
}
};
/* main */
(async () => {
// アクセストークン取得
const resToken = await axios.post(tokenEndpoint, reqTokenBody, reqTokenConfig);
console.log(resToken.status); // レスポンスステータスコード
const accessToken = resToken.data.access_token;
console.log(accessToken); // アクセストークン
})();
トークンの使い方
上記で取得したアクセストークンをコンフィグのヘッダーに乗せればOK。
// 上述の処理と同じなので省略
/* main */
(async () => {
// アクセストークン取得
const resToken = await axios.post(tokenEndpoint, reqTokenBody, reqTokenConfig);
const accessToken = resToken.data.access_token;
// Get a user API
const targetUser = 'john132564@hogehoge.com';
const usersApi = `https://graph.microsoft.com/v1.0/users/${targetUser}`;
const reqUsersConfig = {
headers: {
'Content-Type': 'application/json', // ここはjson
'Authorization': `Bearer ${accessToken}` // ここに取得したアクセストークンを乗せる
}
};
const resUser = await axios.get(usersApi, reqUsersConfig);
console.log(reqUser.data);
})();
そもそも困っていたところ(余談)
元々この記事を書こうとした経緯としては、application/x-www-form-urlencoded
の時にaxiosにリクエストボディのオブジェクトを渡しても空扱いされてうまくいかなかったため、「URLエンコードすると解決するよ」という旨の記事を書こうとしたのだが、実際に記事を書こうとして検証してみると再現しなかった。
const qs = require('qs');
// 以前はこうしないとpostした時にclient_id = nullのエラーになっていた
const reqTokenBodyStr = qs.stringify(reqTokenBody);
半年くらい前に実装していた時は上記のようにしないと動かなかったのだが、夢でも見ていたのだろうか…。
AxiosのREADMEにも「application/x-www-form-urlencoded
に設定すればオブジェクトでもOK」的なことが書かれている…。
🆕 Automatic serialization to URLSearchParams
Axios will automatically serialize the data object to urlencoded format if the content-type header is set to "application/x-www-form-urlencoded".const data = { x: 1, arr: [1, 2, 3], arr2: [1, [2], 3], users: [{name: 'Peter', surname: 'Griffin'}, {name: 'Thomas', surname: 'Anderson'}], }; await axios.postForm('https://postman-echo.com/post', data, {headers: {'content-type': 'application/x-www-form-urlencoded'}} );
この事象について何か知見のある方、よろしければコメントください。
おわりに
以上の方法でMicrosoft Graph APIのアクセストークンが取得できる。
基本的にはmsal-nodeモジュールを使うと思うが、そうでない時の参考にしていただければうれしい。
参考
-
Microsoft Graph API利用手順忘備録
…PowerShellでのクライアントシークレットを使ったアクセストークン取得方法 -
Microsoft identity platform and the OAuth 2.0 client credentials flow
…公式ドキュメントのOAuthトークン取得方法(HTTPしかない…) - Axios - github