Microsoft Authentication Library for .NET でアクセストークンを再取得して Microsoft Graph を呼び出す

Azure.Identity でアクセストークンを再取得する方法を見つけることができなかったので、Azure.Identity が依存している Microsoft Authentication Library for .NET(MSAL.NET) を試してみた。

using System.Net.Http.Headers;
using Microsoft.Graph;
using Microsoft.Identity.Client;

// Microsoft Todo のタスクとリストを CRUD するには
// Tasks.ReadWrite の許可が必要。
// リフレッシュトークンを取得するためには
// offline_access も必要。
var scopes = new[]
{
    "offline_access",
    "Tasks.ReadWrite",
};

// 一般ユーザーの Microsoft Todo にアクセスするときは
// common を指定すれば良いみたい。
var tenantId = "common";

// Azure AD で登録したアプリケーションの ID (Client ID)
var clientId = "YOUR_CLIENT_ID";

// Web ブラウザを表示して、
// ユーザーに Microsoft アカウントにログインし、
// アクセストークンを取得。
var pca = PublicClientApplicationBuilder.Create(clientId)
    .WithTenantId(tenantId)
    .WithRedirectUri("http://localhost")
    .Build();
var authResult = await pca.AcquireTokenInteractive(scopes).ExecuteAsync();
Console.WriteLine($"ExpiresOn: {authResult.ExpiresOn}");

// 内部でキャッシュされているリフレッシュトークンを使って、
// 新しいアクセストークンを取得。
var refreshResult = await pca.AcquireTokenSilent(scopes, authResult.Account.Username)
    .WithForceRefresh(true)
    .ExecuteAsync();
Console.WriteLine($"ExpiresOn: {refreshResult.ExpiresOn}");

// DelegateAuthenticationProvider を使って、
// 取得しておいたアクセストークンを Authorization ヘッダーにセットして
// Microsoft Graph を呼び出せるようにする。
var authProvider = new DelegateAuthenticationProvider(request =>
{
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", refreshResult.AccessToken);
    return Task.CompletedTask;
});
var graphClient = new GraphServiceClient(authProvider);

// リスト一覧表示
var todoLists = await graphClient.Me
    .Todo
    .Lists
    .Request()
    .GetAsync();
foreach (var todoList in todoLists)
{
    Console.WriteLine($"既存のリスト: {todoList.DisplayName}");
}

Console.ReadLine();

MSAL.NET はリフレッシュトークンを内部でキャッシュしているけど、取り出す手段は提供されていない。AcquireTokenSilent を呼び出すと、内部でキャッシュしているリフレッシュトークンを使って、アクセストークンを再取得してくれる。

.NET 6 で実行。

アクセストークンを再取得して Microsoft Graph を呼び出し、Microsoft Todo の TodoList 取得に成功した。

リフレッシュトークンのキャッシュはインメモリなので、プログラムを終了したら失われてしまう。永続化する方法を調べないといけないな。