Microsoftを使用してデーモン アプリケーションとエージェント ID を構築します。Identity.Web

この記事では、Microsoftを使用してデーモン アプリケーション、バックグラウンド サービス、自律エージェントを構築します。Identity.Web。 これらのアプリケーションは、ユーザーの操作なしで実行され、 アプリケーション ID (クライアント資格情報) または エージェント ID を使用して認証されます。

サポートされているシナリオを理解する

Microsoft。Identity.Web では、次の 3 種類の非対話型アプリケーションがサポートされています。

シナリオ 認証の種類 トークンの種類 ユースケース(事例)
Standard デーモン クライアント資格情報 (シークレット/証明書) アプリ専用アクセス トークン バックグラウンド サービス、スケジュールされたジョブ、データ処理
自律エージェント クライアント資格情報を使用するエージェント識別 エージェントのアプリ専用アクセス トークン Copilotエージェント、自律的にエージェントIDを代理して動作するサービス。 (通常、保護された Web API の場合)
エージェント ユーザー ID エージェント ユーザー ID クライアント資格情報を持つエージェント ユーザー ID エージェント ユーザー ID に代わって動作する自律サービス。 (通常、保護された Web API の場合)

概要

前提条件

開始する前に、以下の項目があることを確認します:

  • .NET 8.0 以降
  • Microsoft Entra で、クライアント資格情報(クライアントシークレットまたは証明書)を使用してアプリを登録する
  • エージェント シナリオの場合: Microsoft Entra テナントで設定されたエージェントの識別情報

パッケージをインストールする

必要な NuGet パッケージをプロジェクトに追加します。

dotnet add package Microsoft.Identity.Web
dotnet add package Microsoft.Extensions.Hosting

構成方法を選択する

Microsoft。Identity.Web には、デーモン アプリケーションを構成する 2 つの方法があります。

次の場合に最適です。 クイック プロトタイプ、コンソール アプリ、テスト、単純なデーモン サービス。

次のコードでは、TokenAcquirerFactoryを作成し、ダウンストリーム API とMicrosoft Graphを構成し、Graph APIを呼び出します。

using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;

// Get the token acquirer factory instance
var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();

// Configure downstream API and Microsoft Graph (optional)
tokenAcquirerFactory.Services.AddDownstreamApis(
    tokenAcquirerFactory.Configuration.GetSection("DownstreamApis"))
    .AddMicrosoftGraph();

var serviceProvider = tokenAcquirerFactory.Build();

// Call Microsoft Graph
var graphClient = serviceProvider.GetRequiredService<GraphServiceClient>();
var users = await graphClient.Users.GetAsync();

長所:

  • 最小定型コード
  • 自動的に読み込まれる appsettings.json
  • 単純なシナリオに最適
  • 1 行の初期化

欠点:

  • 並列 (シングルトン) で実行されているテストには適していません

次の場合に最適です。 運用アプリケーション、複雑なシナリオ、依存関係の挿入、テスト可能性。

次のコードでは、.NET 汎用ホストを使用して、認証、トークン取得、キャッシュ、およびバックグラウンド サービスを構成します。

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Identity.Web;

var host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((context, services) =>
    {
        // Configure authentication
        services.Configure<MicrosoftIdentityApplicationOptions>(
            context.Configuration.GetSection("AzureAd"));

        // Add token acquisition (true = singleton lifetime)
        services.AddTokenAcquisition(true);

        // Add token cache (in-memory for development)
        services.AddInMemoryTokenCaches();

        // Add HTTP client for API calls
        services.AddHttpClient();

        // Add Microsoft Graph (optional)
        services.AddMicrosoftGraph();

        // Add your background service
        services.AddHostedService<DaemonWorker>();
    })
    .Build();

await host.RunAsync();

長所:

  • 構成プロバイダーを完全に制御する
  • コンストラクターの挿入によるテスト性の向上
  • ASP.NET Core ホスティング モデルとの統合
  • 複雑なシナリオ (複数の認証スキーム) をサポートします
  • 運用対応アーキテクチャ
  • 並列テスト実行をサポートします (テストごとに分離されたサービス プロバイダー)

trueAddTokenAcquisition(true)パラメーターは、サービスがシングルトン (アプリの有効期間の単一インスタンス) として登録されていることを意味します。 Web アプリケーションでスコープ付き有効期間に false を使用します。

推薦: プロトタイプとシングルスレッド テストの TokenAcquirerFactory から始めます。 運用アプリケーションをビルドするとき、または並列テストを実行する場合は、完全な ServiceCollection パターンに移行します。


標準デーモン アプリケーションを構成する

標準デーモン アプリケーションは 、クライアント資格情報 (クライアント シークレットまたは証明書) を使用して認証し、API を呼び出す アプリ専用アクセス トークン を取得します。

認証設定を構成する

appsettings.json ファイルに次の構成を追加します。 クライアント シークレットまたは証明書 (運用環境に推奨) を使用できます。

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-client-id",

    "ClientSecret": "your-client-secret",

    "ClientCredentials": [
      // Option 1: Client Secret
      {
        "SourceType": "ClientSecret",
        "ClientSecret": "your-client-secret",
      },
      // Option 2: Certificate (recommended for production)
      {
        "SourceType": "StoreWithDistinguishedName",
        "CertificateStorePath": "CurrentUser/My",
        "CertificateDistinguishedName": "CN=DaemonAppCert"
      }
      // More options: https://aka.ms/ms-id-web/client-credentials
    ]
  }
}

大事な: 出力ディレクトリにコピーするように appsettings.json を設定します。 .csproj ファイルに次を追加します。

<ItemGroup>
  <None Update="appsettings.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>

ASP.NET Coreアプリケーションはこのファイルを自動的にコピーしますが、デーモン アプリ (および OWIN アプリ) はコピーしません。

サービス構成を設定する

次のProgram.cs コードは、Microsoft Identity オプション、トークン取得、キャッシング、ホストされたバックグラウンド サービスを登録します。

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Identity.Web;

var host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((context, services) =>
    {
        IConfiguration configuration = context.Configuration;

        // Configure Microsoft Identity options
        services.Configure<MicrosoftIdentityApplicationOptions>(
            configuration.GetSection("AzureAd"));

        // Add token acquisition (true = singleton)
        services.AddTokenAcquisition(true);

        // Add token cache
        services.AddInMemoryTokenCaches(); // For development
        // services.AddDistributedTokenCaches(); // For production

        // Add HTTP client
        services.AddHttpClient();

        // Add Microsoft Graph SDK (optional)
        services.AddMicrosoftGraph();

        // Add your background service
        services.AddHostedService<DaemonWorker>();
    })
    .Build();

await host.RunAsync();

Microsoft Graph を呼び出す

次の DaemonWorker.cs クラスでは、Graph SDK を使用して、定期的なスケジュールでユーザーを一覧表示します。

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Graph;
using Microsoft.Identity.Abstractions;

public class DaemonWorker : BackgroundService
{
    private readonly GraphServiceClient _graphClient;
    private readonly ILogger<DaemonWorker> _logger;

    public DaemonWorker(
        GraphServiceClient graphClient,
        ILogger<DaemonWorker> logger)
    {
        _graphClient = graphClient;
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                // Call Microsoft Graph with app-only permissions
                var users = await _graphClient.Users
                    .GetAsync(cancellationToken: stoppingToken);

                _logger.LogInformation($"Found {users?.Value?.Count} users");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error calling Microsoft Graph");
            }

            await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
        }
    }
}

IAuthorizationHeaderProvider を使用する

HTTP 呼び出しをより詳細に制御するには、 IAuthorizationHeaderProvider を使用して承認ヘッダーを手動で作成します。

using Microsoft.Identity.Abstractions;

public class DaemonService
{
    private readonly IAuthorizationHeaderProvider _authProvider;
    private readonly HttpClient _httpClient;

    public DaemonService(
        IAuthorizationHeaderProvider authProvider,
        IHttpClientFactory httpClientFactory)
    {
        _authProvider = authProvider;
        _httpClient = httpClientFactory.CreateClient();
    }

    public async Task<string> CallApiAsync()
    {
        // Get authorization header for app-only access
        string authHeader = await _authProvider
            .CreateAuthorizationHeaderForAppAsync(
                scopes: "https://graph.microsoft.com/.default");

        // Add to HTTP request
        _httpClient.DefaultRequestHeaders.Clear();
        _httpClient.DefaultRequestHeaders.Add("Authorization", authHeader);

        var response = await _httpClient.GetStringAsync(
            "https://graph.microsoft.com/v1.0/users");

        return response;
    }
}

ダウンストリーム API の呼び出しを参照して、Microsoft Identity Web がダウンストリーム API を呼び出す方法のすべてについて学んでください。


自律エージェントの構成 (エージェント ID)

自律エージェントは 、エージェント ID を 使用してアプリ専用トークンを取得します。 このパターンは、Copilotシナリオや自律サービスに役立ちます。

Microsoftでは、ダウンストリーム API を呼び出すエージェントは、エージェントがアプリ トークンを取得した場合でも、保護された Web API 内からそうすることをお勧めします。

エージェント サービスを構成する

次のコードでは、インメモリ構成を使用して、認証、トークン取得、およびエージェント ID のサポートを設定します。

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Identity.Web;

var services = new ServiceCollection();

// Configuration
var configuration = new ConfigurationBuilder()
    .AddInMemoryCollection(new Dictionary<string, string?>
    {
        ["AzureAd:Instance"] = "https://login.microsoftonline.com/",
        ["AzureAd:TenantId"] = "your-tenant-id",
        ["AzureAd:ClientId"] = "your-agent-app-client-id",
        ["AzureAd:ClientCredentials:0:SourceType"] = "StoreWithDistinguishedName",
        ["AzureAd:ClientCredentials:0:CertificateStorePath"] = "CurrentUser/My",
        ["AzureAd:ClientCredentials:0:CertificateDistinguishedName"] = "CN=YourCert"
    })
    .Build();

services.AddSingleton<IConfiguration>(configuration);

// Configure Microsoft Identity
services.Configure<MicrosoftIdentityApplicationOptions>(
    configuration.GetSection("AzureAd"));

services.AddTokenAcquisition(true);
services.AddInMemoryTokenCaches();
services.AddHttpClient();
services.AddMicrosoftGraph();

// Add agent identities support
services.AddAgentIdentities();

var serviceProvider = services.BuildServiceProvider();

エージェント ID を使用してトークンを取得する

エージェント サービスを構成した後、IAuthorizationHeaderProvider または Microsoft Graph SDK を使用してトークンを取得します。

using Microsoft.Identity.Abstractions;
using Microsoft.Graph;

// Your agent identity GUID
string agentIdentityId = "d84da24a-2ea2-42b8-b5ab-8637ec208024";

// Option 1: Using IAuthorizationHeaderProvider
IAuthorizationHeaderProvider authProvider =
    serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>();

var options = new AuthorizationHeaderProviderOptions()
    .WithAgentIdentity(agentIdentityId);

string authHeader = await authProvider.CreateAuthorizationHeaderForAppAsync(
    scopes: "https://graph.microsoft.com/.default",
    options);

// Option 2: Using Microsoft Graph SDK
GraphServiceClient graphClient =
    serviceProvider.GetRequiredService<GraphServiceClient>();

var applications = await graphClient.Applications.GetAsync(request =>
{
    request.Options.WithAuthenticationOptions(authOptions =>
    {
        authOptions.WithAgentIdentity(agentIdentityId);
    });
});

完全な自律エージェントの例を確認する

次のクラスは、エージェント ID トークンの取得とGraph API呼び出しを再利用可能なサービスにラップします。

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Graph;
using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;

public class AutonomousAgentService
{
    private readonly GraphServiceClient _graphClient;
    private readonly IAuthorizationHeaderProvider _authProvider;
    private readonly string _agentIdentityId;

    public AutonomousAgentService(
        string agentIdentityId,
        IServiceProvider serviceProvider)
    {
        _agentIdentityId = agentIdentityId;
        _graphClient = serviceProvider.GetRequiredService<GraphServiceClient>();
        _authProvider = serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>();
    }

    public async Task<string> GetAuthorizationHeaderAsync()
    {
        var options = new AuthorizationHeaderProviderOptions()
            .WithAgentIdentity(_agentIdentityId);

        return await _authProvider.CreateAuthorizationHeaderForAppAsync(
            "https://graph.microsoft.com/.default",
            options);
    }

    public async Task<IEnumerable<Application>> ListApplicationsAsync()
    {
        var apps = await _graphClient.Applications.GetAsync(request =>
        {
            request.Options.WithAuthenticationOptions(options =>
            {
                options.WithAgentIdentity(_agentIdentityId);
            });
        });

        return apps?.Value ?? Enumerable.Empty<Application>();
    }
}

エージェント ユーザー ID の構成

エージェント ユーザー ID を使用すると、エージェントは委任されたアクセス許可を持つ エージェント ユーザーに代わって 動作できます。 このパターンは、独自のメールボックスまたはその他のユーザー スコープ リソースを必要とするエージェントに使用します。

前提条件

エージェント ユーザー ID を使用するには、次のものが必要です。

  • Microsoft Entra IDに登録されているエージェント ブループリント
  • エージェント識別子が作成され、エージェント アプリケーションにリンクされました
  • エージェント ID に関連付けられているエージェント ユーザー ID

エージェント ユーザー サービスを構成する

次のコードでは、証明書資格情報を使用してエージェント アプリケーション ID を構成し、必要なサービスを登録します。

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Identity.Web;
using System.Security.Cryptography.X509Certificates;

var services = new ServiceCollection();

// Configure agent application
services.Configure<MicrosoftIdentityApplicationOptions>(options =>
{
    options.Instance = "https://login.microsoftonline.com/";
    options.TenantId = "your-tenant-id";
    options.ClientId = "your-agent-app-client-id";

    // Use certificate for agent authentication
    options.ClientCredentials = new[]
    {
        CertificateDescription.FromStoreWithDistinguishedName(
            "CN=YourCertificate",
            StoreLocation.CurrentUser,
            StoreName.My)
    };
});

// Add services (true = singleton)
services.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
services.AddTokenAcquisition(true);
services.AddInMemoryTokenCaches();
services.AddHttpClient();
services.AddMicrosoftGraph();
services.AddAgentIdentities();

var serviceProvider = services.BuildServiceProvider();

エージェント ID を使用してユーザー トークンを取得する

ターゲット ユーザーは UPN またはオブジェクト ID で識別できます。

ユーザー名(UPN)による

using Microsoft.Identity.Abstractions;
using Microsoft.Graph;

string agentIdentityId = "your-agent-identity-id";
string userUpn = "user@yourtenant.onmicrosoft.com";

// Get authorization header
IAuthorizationHeaderProvider authProvider =
    serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>();

var options = new AuthorizationHeaderProviderOptions()
    .WithAgentUserIdentity(
        agentApplicationId: agentIdentityId,
        username: userUpn);

string authHeader = await authProvider.CreateAuthorizationHeaderForUserAsync(
    scopes: new[] { "https://graph.microsoft.com/.default" },
    options);

// Or use Microsoft Graph SDK
GraphServiceClient graphClient =
    serviceProvider.GetRequiredService<GraphServiceClient>();

var me = await graphClient.Me.GetAsync(request =>
{
    request.Options.WithAuthenticationOptions(options =>
        options.WithAgentUserIdentity(agentIdentityId, userUpn));
});

ユーザー オブジェクト ID による

string agentIdentityId = "your-agent-identity-id";
Guid userObjectId = Guid.Parse("user-object-id");

var options = new AuthorizationHeaderProviderOptions()
    .WithAgentUserIdentity(
        agentApplicationId: agentIdentityId,
        userId: userObjectId);

string authHeader = await authProvider.CreateAuthorizationHeaderForUserAsync(
    scopes: new[] { "https://graph.microsoft.com/.default" },
    options);

// With Graph SDK
var me = await graphClient.Me.GetAsync(request =>
{
    request.Options.WithAuthenticationOptions(options =>
        options.WithAgentUserIdentity(agentIdentityId, userObjectId));
});

ClaimsPrincipal を使用してトークンをキャッシュする

パフォーマンスを向上させるには、 ClaimsPrincipal インスタンスを渡してユーザー トークンをキャッシュします。 最初の呼び出しでは、プリンシパルに uid 要求と utid 要求が設定されます。後続の呼び出しでは、キャッシュされたトークンが再利用されます。

using System.Security.Claims;
using Microsoft.Identity.Abstractions;

// First call - creates cache entry
ClaimsPrincipal userPrincipal = new ClaimsPrincipal();

string authHeader = await authProvider.CreateAuthorizationHeaderForUserAsync(
    scopes: new[] { "https://graph.microsoft.com/.default" },
    options,
    userPrincipal);

// ClaimsPrincipal now has uid and utid claims for caching
bool hasUserId = userPrincipal.HasClaim(c => c.Type == "uid");
bool hasTenantId = userPrincipal.HasClaim(c => c.Type == "utid");

// Subsequent calls - uses cache
authHeader = await authProvider.CreateAuthorizationHeaderForUserAsync(
    scopes: new[] { "https://graph.microsoft.com/.default" },
    options,
    userPrincipal); // Reuse the same principal

テナントをオーバーライドする

マルチテナント シナリオでは、実行時にテナントをオーバーライドできます。 これは、アプリが "common" で構成されているが、特定のテナントをターゲットにする必要がある場合に便利です。

var options = new AuthorizationHeaderProviderOptions()
    .WithAgentUserIdentity(agentIdentityId, userUpn);

// Override tenant (useful when app is configured with "common")
options.AcquireTokenOptions.Tenant = "specific-tenant-id";

string authHeader = await authProvider.CreateAuthorizationHeaderForUserAsync(
    scopes: new[] { "https://graph.microsoft.com/.default" },
    options);

// With Graph SDK
var me = await graphClient.Me.GetAsync(request =>
{
    request.Options.WithAuthenticationOptions(options =>
    {
        options.WithAgentUserIdentity(agentIdentityId, userUpn);
        options.AcquireTokenOptions.Tenant = "specific-tenant-id";
    });
});

完全なエージェント ユーザー ID の例を確認する

次のクラスは、エージェント ユーザー ID を使用してユーザー プロファイルと承認ヘッダーを取得するメソッドを提供します。

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Graph;
using Microsoft.Identity.Abstractions;
using System.Security.Claims;

public class AgentUserService
{
    private readonly IAuthorizationHeaderProvider _authProvider;
    private readonly GraphServiceClient _graphClient;
    private readonly string _agentIdentityId;

    public AgentUserService(
        string agentIdentityId,
        IServiceProvider serviceProvider)
    {
        _agentIdentityId = agentIdentityId;
        _authProvider = serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>();
        _graphClient = serviceProvider.GetRequiredService<GraphServiceClient>();
    }

    public async Task<User> GetUserProfileAsync(string userUpn)
    {
        var me = await _graphClient.Me.GetAsync(request =>
        {
            request.Options.WithAuthenticationOptions(options =>
                options.WithAgentUserIdentity(_agentIdentityId, userUpn));
        });

        return me!;
    }

    public async Task<User> GetUserProfileByIdAsync(Guid userObjectId)
    {
        var me = await _graphClient.Me.GetAsync(request =>
        {
            request.Options.WithAuthenticationOptions(options =>
                options.WithAgentUserIdentity(_agentIdentityId, userObjectId));
        });

        return me!;
    }

    public async Task<string> GetAuthHeaderForUserAsync(
        string userUpn,
        ClaimsPrincipal? cachedPrincipal = null)
    {
        var options = new AuthorizationHeaderProviderOptions()
            .WithAgentUserIdentity(_agentIdentityId, userUpn);

        return await _authProvider.CreateAuthorizationHeaderForUserAsync(
            scopes: new[] { "https://graph.microsoft.com/.default" },
            options,
            cachedPrincipal ?? new ClaimsPrincipal());
    }
}

再利用可能なサービス構成を作成する

拡張メソッドを定義する

アプリケーション全体でエージェント ID 構成をカプセル化する再利用可能な拡張メソッドを作成します。

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.TokenCacheProviders.InMemory;

public static class ServiceCollectionExtensions
{
    public static IServiceProvider ConfigureServicesForAgentIdentities(
        this IServiceCollection services,
        IConfiguration configuration)
    {
        // Add configuration
        services.AddSingleton(configuration);

        // Configure Microsoft Identity options
        services.Configure<MicrosoftIdentityApplicationOptions>(
            configuration.GetSection("AzureAd"));

        services.AddTokenAcquisition(true);

        // Add token caching
        services.AddInMemoryTokenCaches();

        // Add HTTP client
        services.AddHttpClient();

        // Add Microsoft Graph (optional)
        services.AddMicrosoftGraph();

        // Add agent identities support
        services.AddAgentIdentities();

        return services.BuildServiceProvider();
    }
}

拡張メソッドを使用する

拡張メソッドを呼び出して、1 行でサービスを構成します。

var services = new ServiceCollection();
var configuration = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json")
    .Build();

var serviceProvider = services.ConfigureServicesForAgentIdentities(configuration);

API の呼び出し

このセクションでは、3 つの認証パターンをそれぞれ使用して API を呼び出す方法を示します。

Microsoft Graph を呼び出す

次の例では、標準デーモン、自律エージェント、およびエージェント ユーザー ID としてMicrosoft Graphを呼び出す方法を示します。

using Microsoft.Graph;

GraphServiceClient graphClient =
    serviceProvider.GetRequiredService<GraphServiceClient>();

// Standard daemon (app-only)
var users = await graphClient.Users.GetAsync();

// Autonomous agent (app-only with agent identity)
var apps = await graphClient.Applications.GetAsync(request =>
{
    request.Options.WithAuthenticationOptions(options =>
    {
        options.WithAgentIdentity("agent-identity-id");
        options.RequestAppToken = true;
    });
});

// Agent user identity (delegated with user context)
var me = await graphClient.Me.GetAsync(request =>
{
    request.Options.WithAuthenticationOptions(options =>
        options.WithAgentUserIdentity("agent-identity-id", "user@tenant.com"));
});

IDownstreamApi を使用してカスタム API を呼び出す

IDownstreamApiを使用して、次の 3 つの認証パターンのいずれかで独自の保護された API を呼び出します。

using Microsoft.Identity.Abstractions;

IDownstreamApi downstreamApi =
    serviceProvider.GetRequiredService<IDownstreamApi>();

// Standard daemon
var result = await downstreamApi.GetForAppAsync<ApiResponse>(
    serviceName: "MyApi",
    options => options.RelativePath = "api/data");

// With agent identity
var result = await downstreamApi.GetForAppAsync<ApiResponse>(
    serviceName: "MyApi",
    options =>
    {
        options.RelativePath = "api/data";
        options.WithAgentIdentity("agent-identity-id");
    });

// Agent user identity
var result = await downstreamApi.GetForUserAsync<ApiResponse>(
    serviceName: "MyApi",
    options =>
    {
        options.RelativePath = "api/data";
        options.WithAgentUserIdentity("agent-identity-id", "user@tenant.com");
    });

手動の HTTP 呼び出しを行う

HTTP 要求を完全に制御する必要がある場合は、 IAuthorizationHeaderProvider を直接使用します。

using Microsoft.Identity.Abstractions;

IAuthorizationHeaderProvider authProvider =
    serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>();

HttpClient httpClient = new HttpClient();

// Standard daemon
string authHeader = await authProvider.CreateAuthorizationHeaderForAppAsync(
    "https://graph.microsoft.com/.default");

httpClient.DefaultRequestHeaders.Add("Authorization", authHeader);
var response = await httpClient.GetStringAsync("https://graph.microsoft.com/v1.0/users");

// With agent identity
var options = new AuthorizationHeaderProviderOptions()
    .WithAgentIdentity("agent-identity-id");

authHeader = await authProvider.CreateAuthorizationHeaderForAppAsync(
    "https://graph.microsoft.com/.default",
    options);

// Agent user identity
var userOptions = new AuthorizationHeaderProviderOptions()
    .WithAgentUserIdentity("agent-identity-id", "user@tenant.com");

authHeader = await authProvider.CreateAuthorizationHeaderForUserAsync(
    new[] { "https://graph.microsoft.com/.default" },
    userOptions);

トークン キャッシュの構成

環境に基づいてキャッシュ戦略を選択します。

開発: メモリ内キャッシュ

ローカルの開発とテストには、メモリ内キャッシュを使用します。

services.AddInMemoryTokenCaches();

プロダクション: 分散キャッシュ

運用環境では、分散キャッシュを使用して、アプリの再起動とスケールアウト インスタンス間でトークンを保持します。

SQL Server

SQL Server テーブルにトークンを格納します。

services.AddDistributedSqlServerCache(options =>
{
    options.ConnectionString = configuration["ConnectionStrings:TokenCache"];
    options.SchemaName = "dbo";
    options.TableName = "TokenCache";
});
services.AddDistributedTokenCaches();

Redis

Redis を使用して、高パフォーマンスの分散トークン キャッシュを行います。

services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = configuration["Redis:ConnectionString"];
    options.InstanceName = "TokenCache_";
});
services.AddDistributedTokenCaches();

Cosmos DB

グローバル分散トークン キャッシュには Cosmos DB を使用します。

services.AddCosmosDbTokenCaches(options =>
{
    options.CosmosDbConnectionString = configuration["CosmosDb:ConnectionString"];
    options.DatabaseId = "TokenCache";
    options.ContainerId = "Tokens";
});

詳細情報:トークン キャッシュの構成


Azureサンプルを調べる

Microsoftでは、デーモン アプリのパターンを示すサンプルを提供します。

サンプル リポジトリ

active-directory-dotnetcore-daemon-v2

このリポジトリには、複数のシナリオが含まれています。

サンプル 説明 リンク
1-Call-MSGraph クライアント資格情報を使用したデーモンによるMicrosoft Graphの基本的な呼び出し サンプルを表示
2-Call-OwnApi 独自の保護された Web API を呼び出すデーモン サンプルを表示
3-Using-KeyVault 証明書ストレージにAzure Key Vaultを使用するデーモン サンプルを表示
4-マルチテナント マルチテナント デーモン アプリケーション サンプルを表示
5-Call-MSGraph-ManagedIdentity Azureでマネージド ID を使用するデーモン サンプルを表示

サンプル パターンと運用パターンを比較する

Azure サンプルでは、TokenAcquirerFactory.GetDefaultInstance()を使ってわかりやすくします。これは、simple コンソール アプリ、プロトタイプ、テストに推奨されるアプローチです。 このガイドでは、両方のパターンを示します。

TokenAcquirerFactory パターン (Azure サンプル):

// Simple, perfect for prototypes and tests
var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
tokenAcquirerFactory.Services.AddDownstreamApi("MyApi", ...);
var serviceProvider = tokenAcquirerFactory.Build();

Full ServiceCollection パターン (運用アプリ):

// More control, testable, follows DI best practices
var services = new ServiceCollection();
services.AddTokenAcquisition(true); // true = singleton
services.Configure<MicrosoftIdentityApplicationOptions>(...);
var serviceProvider = services.BuildServiceProvider();

使用するタイミング:

  • を使用する: コンソール アプリ、迅速プロトタイプ、単体テスト、単純なデーモン サービス
  • ServiceCollection

どちらの方法も完全にサポートされ、運用環境に対応しています。 アプリケーションの複雑さと統合のニーズに基づいて選択します。


一般的なエラーのトラブルシューティング

AADSTS700016: アプリケーションが見つかりません

原因: 無効な ClientId またはアプリケーションがテナントに登録されていません。

Solution: 構成の ClientId がMicrosoft Entra アプリの登録と一致するかどうかを確認します。

AADSTS7000215: クライアント シークレットが無効です

原因: クライアント シークレットが正しくない、期限切れ、または構成されていない。

Solution:

  • Azure ポータルのシークレットが構成と一致するかどうかを確認する
  • シークレットの有効期限を確認する
  • 運用環境での証明書の使用を検討する

AADSTS700027: クライアント アサーションに無効な署名が含まれています

原因: 証明書が見つからない、期限切れ、秘密キーにアクセスできない。

Solution:

  • 証明書が正しい証明書ストアにインストールされていることを確認する
  • 証明書の識別名が構成と一致するかどうかを確認する
  • アプリケーションに秘密キーを読み取るアクセス許可があることを確認する
  • 証明書構成ガイドを参照してください

AADSTS650052: アプリがサービスにアクセスする必要がある

原因: 必要な API アクセス許可が付与されていないか、管理者の同意がありません。

Solution:

  1. Azure ポータル → アプリの登録 → アプリ → API のアクセス許可
  2. 必要なアクセス許可を追加する (例: User.Read.All for Microsoft Graph)
  3. [管理者の同意を付与する] ボタンをクリックします

エージェント ID エラー

AADSTS50105: サインインしているユーザーがロールに割り当てられない

原因: エージェント ID が正しく構成されていないか、アプリケーションに割り当てされていません。

Solution:

  • Microsoft Entra IDにエージェント ID が存在するかどうかを確認する
  • エージェント ID がアプリケーションにリンクされていることを確認する
  • エージェント ID に必要なアクセス許可があることを確認する

トークンが取得されましたが、アクセス許可が間違っています

原因: エージェント ユーザー ID を使用するが、アプリのアクセス許可を要求する、またはその逆。

Solution:

  • アプリ専用トークンの場合CreateAuthorizationHeaderForAppAsyncWithAgentIdentityを使用する。
  • 委任されたトークンの場合: CreateAuthorizationHeaderForUserAsyncと一緒にWithAgentUserIdentityを使用する
  • API のアクセス許可がトークンの種類と一致していることを確認する (アプリケーションと委任)

トークン キャッシュの問題

問題: トークンはキャッシュされないため、毎回新しい取得が強制されます。

Solution:

  • エージェント ユーザー ID の場合: 呼び出し間で同じ ClaimsPrincipal インスタンスを再利用する
  • 分散キャッシュ接続を確認する (Redis/SQL を使用している場合)
  • デバッグ ログを有効にしてキャッシュ操作を表示する

詳細な診断:ログ記録と診断ガイド