Microsoft Authentication Library for .NET(MSAL.NET) は、リフレッシュトークンを内部でキャッシュしていて、それを使ってアクセストークンを再取得できる。
ただ、キャッシュはメモリ上にしかないので、そのままだとプロセス終了したら失われてしまう。次回起動時もアクセストークンをサイレントに取得したいなら、永続化しないと。
Microsoft.Identity.Client.Extensions.Msal というパッケージを導入すれば、キャッシュを永続化できそう。
Microsoft Graph を呼び出すサンプルに組み込んでみた。
using System.Net.Http.Headers; using Microsoft.Graph; using Microsoft.Identity.Client; using Microsoft.Identity.Client.Extensions.Msal; // 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 ブラウザでログインするときのメールアドレス。 // ちゃんと対応するときは、この情報も永続化しておく必要がある。 var loginHint = "your-address@outlook.jp"; var pca = PublicClientApplicationBuilder.Create(clientId) .WithTenantId(tenantId) .WithRedirectUri("http://localhost") .Build(); // キャッシュをシリアライズ・デシリアライズできるようにする。 var storageProperties = new StorageCreationPropertiesBuilder( "UserTokenCache", AppContext.BaseDirectory) .Build(); var cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties); cacheHelper.RegisterCache(pca.UserTokenCache); AuthenticationResult? authResult = null; try { // キャッシュされているリフレッシュトークンを使って、 // 新しいアクセストークンを取得。 authResult = await pca.AcquireTokenSilent(scopes, loginHint) .WithForceRefresh(true) .ExecuteAsync(); Console.WriteLine($"ExpiresOn: {authResult.ExpiresOn}"); } catch (MsalClientException ex) { // アクセストークンを取得できなかったら、 // Web ブラウザを表示して、 // ユーザーに Microsoft アカウントにログインし、 // アクセストークンを取得。 authResult = await pca.AcquireTokenInteractive(scopes).ExecuteAsync(); Console.WriteLine($"ExpiresOn: {authResult.ExpiresOn}"); } // DelegateAuthenticationProvider を使って、 // 取得しておいたアクセストークンを Authorization ヘッダーにセットして // Microsoft Graph を呼び出せるようにする。 var authProvider = new DelegateAuthenticationProvider(request => { request.Headers.Authorization = new AuthenticationHeaderValue( "Bearer", authResult.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();