.NET で MSAL トークンを X.509 証明書で取ってみる
この記事は .NET Core 3.1 のデーモンコンソールアプリで MSAL トークンをクライアント ID と X.509 証明書で取得してみた時の作業メモです。
やったこと:
- Azure Key Vault で証明書作成
- Azure AD アプリ作成
- .NET からトークン取得
環境
- Azure Key Vault
- .NET Core 3.1 (Win 10 x64)
- Microsoft.Identity.Client @ 4.27.0
- Microsoft.Graph @ 3.25.0
やったこと
1. Azure Key Vault で証明書作成
ただ証明書を作りたいだけなのでどこで作っても良いのですが、今回は Key Vault から作成しました。作成時のオプションはフラグを「デジタル署名」のみに変更した以外はデフォルト値です。
生成された証明書を pfx ファイルでダウンロードします。ダウンロードした pfx をクライアントにインストールします。そして証明書ツール( certmgr )から秘密キーを含まない cer ファイルとしてエクスポートします。証明書ツールはスタートメニューから cert
で検索するとアクセスしやすいです。個人とコンピューターとで違うので注意しましょう。私は個人の方にインポートました。
登録した証明書の拇印は証明書ツールまたは PowerShell で Get-ChildItem Cert:\CurrentUser\My
から確認できます。
2. Azure AD アプリ登録
コンソールアプリからの認証で使用する Azure AD アプリを登録します。登録後、「証明書とシークレット」から先にエクスポートした秘密キーを含まない cer ファイルをアップロードします。
3. .NET からトークン取得
最後に .NET コンソールアプリから Azure AD アプリのクライアント ID と証明書を使用してアクセストークンを取得します。
using System; using System.Linq; using System.Net.Http.Headers; using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; using Microsoft.Graph; using Microsoft.Identity.Client; namespace ConsoleApp1 { class Program { private const string TenantId = "*** AAD Tenant ID ***"; private const string ClientId = "*** AAD Client ID ***"; private const string CertThumbprint = "*** x.509 Certificate Thumbprint ***"; static async Task Main(string[] args) { // 証明書ストアから認証に使用する証明書を拇印で取得 using var store = new X509Store(); store.Open(OpenFlags.ReadOnly); var certificates = store.Certificates.Find(X509FindType.FindByThumbprint, CertThumbprint, false); var certificate = certificates.OfType<X509Certificate2>().Single(); // ConfidentialなIdentityClientをクライアントIDと証明書で生成 var app = ConfidentialClientApplicationBuilder.Create(ClientId) .WithCertificate(certificate) .WithTenantId(TenantId) .Build(); // MS Graphからユーザー一覧を取得 var graphServiceClient = new GraphServiceClient(new DelegateAuthenticationProvider(async req => { // アクセストークン取得 // "xxx//.default" で取らないと怒られる // Azure AD上でスコープの設定を忘れずに var scopes = new[] { @"https://graph.microsoft.com//.default" }; var authenticationResult = await app.AcquireTokenForClient(scopes).ExecuteAsync(); req.Headers.Authorization = new AuthenticationHeaderValue("bearer", authenticationResult.AccessToken); })); var users = await graphServiceClient.Users.Request().GetAsync(); Console.ReadLine(); } } }