Générez des applications démon et des identités d’agent avec Microsoft. Identity.Web

Dans cet article, vous créez des applications démon, des services en arrière-plan et des agents autonomes à l’aide de Microsoft. Identity.Web. Ces applications s’exécutent sans interaction utilisateur et s’authentifient à l’aide d’identités d’application (informations d’identification du client) ou d’identités d’agent.

Comprendre les scénarios pris en charge

Microsoft. Identity.Web prend en charge trois types d’applications non interactives :

Scénario Type d’authentification Type de jeton Cas d'utilisation
Démon standard Informations d’identification du client (secret/certificat) Jeton d’accès d’application uniquement Services en arrière-plan, travaux planifiés, traitement des données
Agent autonome Identité de l’agent avec les informations d’identification du client Jeton d’accès d’application uniquement pour l’agent Copilot agents, services autonomes agissant au nom d’une identité d’agent. (Généralement dans une API web protégée)
Identité utilisateur de l’agent Identité de l’utilisateur de l’agent Identité utilisateur de l’agent avec les informations d’identification du client Services autonomes agissant pour le compte d’une identité d’utilisateur agent. (Généralement dans une API web protégée)

Commencez

Prerequisites

Avant de commencer, assurez-vous d’avoir :

  • .NET 8.0 ou version ultérieure
  • Microsoft Entra enregistrement de l'application avec des identifiants client (secret client ou certificat)
  • Pour les scénarios d’agent : Identités d’agent configurées dans votre instance Microsoft Entra

Installer des packages

Ajoutez les packages NuGet requis à votre projet :

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

Choisir une approche de configuration

Microsoft. Identity.Web fournit deux façons de configurer des applications démon :

Meilleur pour : Prototypes rapides, applications console, tests et services démon simples.

Le code suivant crée un TokenAcquirerFactory, configure les API et les Microsoft Graph en aval, puis appelle le API Graph :

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();

Avantages :

  • Code réutilisable minimal
  • Se charge automatiquement appsettings.json
  • Parfait pour les scénarios simples
  • Initialisation sur une ligne

Inconvénients:

  • Non adapté aux tests exécutés en parallèle (singleton)

Meilleur pour : Applications de production, scénarios complexes, injection de dépendances, testabilité.

Le code suivant utilise l’hôte générique .NET pour configurer l’authentification, l’acquisition de jetons, la mise en cache et un service en arrière-plan :

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();

Avantages :

  • Contrôle total sur les fournisseurs de configuration
  • Meilleure testabilité avec injection de constructeur
  • S’intègre avec ASP.NET Core modèle d’hébergement
  • Prend en charge des scénarios complexes (plusieurs schémas d’authentification)
  • Architecture prête pour la production
  • Prend en charge l’exécution de tests parallèles (fournisseur de services isolé par test)

Note

Le paramètre trueAddTokenAcquisition(true) signifie que le service est inscrit en tant que singleton (instance unique pour la durée de vie de l’application). Utiliser false pour la durée de vie définie dans les applications web.

Recommandation : Commencez avec TokenAcquirerFactory pour les prototypes et les tests monothread. Migrez vers le modèle complet ServiceCollection lors de la génération d’applications de production ou d’exécution de tests parallèles.


Configurer des applications démon standard

Les applications démon standard s’authentifient à l’aide des informations d’identification client (secret client ou certificat) et obtiennent des jetons d’accès d’application uniquement pour appeler des API.

Configurer les paramètres d’authentification

Ajoutez la configuration suivante à votre fichier appsettings.json . Vous pouvez utiliser une clé secrète client ou un certificat (recommandé pour la production) :

{
  "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
    ]
  }
}

Important : Configurez votre appsettings.json pour copier vers le répertoire de sortie. Ajoutez ce qui suit à votre .csproj fichier :

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

ASP.NET Core applications copient automatiquement ce fichier, mais les applications démon (et les applications OWIN) ne le font pas.

Définir la configuration du service

Le code Program.cs suivant enregistre les options d'identité Microsoft, l'acquisition de jetons, la mise en cache et un service en arrière-plan hébergé.

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();

Appeler Microsoft Graph

La classe DaemonWorker.cs suivante utilise le Kit de développement logiciel (SDK) Graph pour répertorier les utilisateurs selon une planification périodique :

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);
        }
    }
}

Utiliser le IAuthorizationHeaderProvider

Pour plus de contrôle sur les appels HTTP, utilisez cette option IAuthorizationHeaderProvider pour créer manuellement des en-têtes d’autorisation :

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;
    }
}

Consultez également Appeling en aval pour en savoir plus sur toutes les façons dont Microsoft Identity Web propose d’appeler des API en aval.


Configurer des agents autonomes (identité de l’agent)

Les agents autonomes utilisent des identités d’agent pour obtenir des jetons d’application uniquement. Ce modèle est utile pour les scénarios Copilot et les services autonomes.

Note

Microsoft recommande que les agents appelant des API en aval le font à partir d’API web protégées, même lorsque les agents obtiennent un jeton d’application.

Configurer les services d’agent

Le code suivant configure la prise en charge de l’authentification, de l’acquisition de jetons et de l’identité de l’agent à l’aide de la configuration en mémoire :

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();

Acquérir des jetons avec l’identité de l’agent

Après avoir configuré les services d’agent, achetez des jetons à l’aide de IAuthorizationHeaderProvider ou du Kit de développement logiciel (SDK) Microsoft Graph :

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);
    });
});

Examiner un exemple complet d’agent autonome

La classe suivante regroupe l’acquisition de jetons d’identité de l’agent et d’appels à l’API Graph dans un service réutilisable.

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>();
    }
}

Configurer l’identité utilisateur de l’agent

L’identité utilisateur de l’agent permet aux agents d’agir au nom d’un utilisateur d’agent disposant d’autorisations déléguées. Utilisez ce modèle pour les agents qui ont besoin de leur propre boîte aux lettres ou d’autres ressources étendues à l’utilisateur.

Prerequisites

Pour utiliser l’identité utilisateur de l’agent, vous avez besoin des éléments suivants :

  • Modèle d'agent enregistré dans Microsoft Entra ID
  • Identité de l’agent créée et liée à l’application de l’agent
  • Identité utilisateur de l’agent associée à l’identité de l’agent

Configurer les services utilisateur de l’agent

Le code suivant configure l’identité d’application de l’agent avec des informations d’identification de certificat et inscrit les services requis :

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();

Acquérir des jetons utilisateur avec l’identité de l’agent

Vous pouvez identifier l’utilisateur cible par UPN ou ID d’objet.

Par nom d’utilisateur (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 d’objet utilisateur

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));
});

Mise en cache des jetons avec ClaimsPrincipal

Pour améliorer les performances, mettre en cache les jetons utilisateur en passant une instance ClaimsPrincipal. Le premier appel remplit le principal avec uid et utid assertions ; les appels suivants réutilisent le jeton mis en mémoire cache :

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

Remplacer le locataire

Pour les scénarios multilocataires, vous pouvez remplacer le locataire au moment de l’exécution. Cela est utile lorsque l’application est configurée avec "common" , mais doit cibler un locataire spécifique :

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";
    });
});

Examiner un exemple complet d’identité utilisateur de l’agent

La classe suivante fournit des méthodes pour obtenir des profils utilisateur et des en-têtes d’autorisation à l’aide de l’identité utilisateur de l’agent :

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());
    }
}

Créer une configuration de service réutilisable

Définir une méthode d’extension

Créez une méthode d’extension réutilisable pour encapsuler la configuration d’identité de l’agent dans votre application :

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();
    }
}

Utiliser la méthode d’extension

Appelez la méthode d’extension pour configurer les services dans une seule ligne :

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

var serviceProvider = services.ConfigureServicesForAgentIdentities(configuration);

Appeler les API

Cette section montre comment appeler des API à l’aide de chacun des trois modèles d’authentification.

Appeler Microsoft Graph

Les exemples suivants illustrent l’appel de Microsoft Graph en tant que démon standard, un agent autonome et une identité utilisateur de l’agent :

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"));
});

Appeler des API personnalisées avec IDownstreamApi

Utilisez cette option IDownstreamApi pour appeler vos propres API protégées avec l’un des trois modèles d’authentification suivants :

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");
    });

Effectuer des appels HTTP manuels

Utilisez IAuthorizationHeaderProvider directement lorsque vous avez besoin d’un contrôle total sur les requêtes HTTP :

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);

Configurer la mise en cache des jetons

Choisissez une stratégie de mise en cache basée sur votre environnement.

Développement : cache en mémoire

Utilisez la mise en cache en mémoire pour le développement et les tests locaux :

services.AddInMemoryTokenCaches();

Production : Cache distribué

Pour la production, utilisez un cache distribué pour conserver les jetons entre les redémarrages de l’application et les instances de scale-out.

SQL Server

Stockez des jetons dans une table SQL Server :

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

Redis

Utilisez Redis pour la mise en cache des jetons distribués hautes performances :

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

Cosmos DB

Utilisez Cosmos DB pour la mise en cache des jetons distribués à l’échelle mondiale :

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

En savoir plus :Configuration du cache de jetons


Explorer des exemples de Azure

Microsoft fournit des exemples illustrant les modèles d’application démon.

Exemple de référentiel

active-directory-dotnetcore-daemon-v2

Ce référentiel contient plusieurs scénarios :

Exemple Description Lien
1-Call-MSGraph Démon de base appelant Microsoft Graph avec les informations d’identification du client Afficher l’exemple
2-Call-OwnApi Démon appelant votre propre API web protégée Afficher l’exemple
3-Using-KeyVault Démon utilisant Azure Key Vault pour le stockage de certificats Afficher l’exemple
4-Multilocataire Application démon multilocataire Afficher l’exemple
5-Call-MSGraph-ManagedIdentity Démon utilisant Managed Identity sur Azure Afficher l’exemple

Comparer des exemples de modèles à des modèles de production

Les exemples Azure utilisent TokenAcquirerFactory.GetDefaultInstance() par souci de simplicité : l’approche recommandée pour les applications de console simple, les prototypes et les tests. Ce guide présente les deux modèles :

modèle TokenAcquirerFactory (exemples Azure) :

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

Modèle ServiceCollection complet (applications de production) :

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

Quand utiliser lequel :

  • Utiliser TokenAcquirerFactory pour : applications console, prototypes rapides, tests unitaires, services démon simples
  • Utiliser ServiceCollection pour : applications de production, l'intégration à ASP.NET Core, scénarios DI complexes, services d'arrière-plan avec IHostedService

Les deux approches sont entièrement prises en charge et prêtes pour la production. Choisissez en fonction de la complexité et des besoins d’intégration de votre application.


Résoudre les erreurs courantes

AADSTS700016 : Application introuvable

Cause :ClientId non valide ou l’application n’est pas inscrite dans le tenant.

Solution : Vérifiez que le ClientId dans votre configuration correspond à l'enregistrement de votre application Microsoft Entra.

AADSTS7000215 : clé secrète client non valide

Cause : La clé secrète client est incorrecte, expirée ou non configurée.

Solution:

  • Vérifiez que le secret dans Azure portail correspond à votre configuration
  • Vérifier la date d’expiration du secret
  • Envisagez d’utiliser des certificats pour la production

AADSTS700027 : l’assertion du client contient une signature non valide

Cause : Le certificat introuvable, expiré ou clé privée n’est pas accessible.

Solution:

  • Vérifier que le certificat est installé dans le magasin de certificats correct
  • Vérifier que le nom unique du certificat correspond à la configuration
  • Vérifier que l’application dispose de l’autorisation de lire la clé privée
  • Consultez le Guide de configuration des certificats

AADSTS650052 : l’application a besoin d’un accès à un service

Cause : Les autorisations d’API requises ne sont pas accordées ou le consentement administrateur est manquant.

Solution:

  1. Accédez au portail Azure → inscriptions d'applications → autorisations d’API de votre application →
  2. Ajouter des autorisations requises (par exemple, User.Read.All pour Microsoft Graph)
  3. Cliquez sur le bouton « Accorder le consentement administrateur »

Erreurs d’identité de l’agent

AADSTS50105 : l’utilisateur connecté n’est pas affecté à un rôle

Cause : L’identité de l’agent n’est pas correctement configurée ou n’est pas affectée à l’application.

Solution:

  • Vérifier que l’identité de l’agent existe dans Microsoft Entra ID
  • Vérifier que l’identité de l’agent est liée à votre application
  • Vérifier que l’identité de l’agent dispose des autorisations requises

Jetons acquis mais avec des autorisations incorrectes

Cause : Utilisation de l’identité utilisateur de l’agent, mais demande des autorisations d’application, ou inversement.

Solution:

  • Pour les jetons d’application uniquement : utiliser CreateAuthorizationHeaderForAppAsync avec WithAgentIdentity
  • Pour les jetons délégués : utiliser CreateAuthorizationHeaderForUserAsync avec WithAgentUserIdentity
  • S'assurer que les autorisations d'API correspondent au type de jeton (application ou délégué)

Problèmes de mise en cache des jetons

Problème: Les jetons ne sont pas mis en cache, ce qui force une nouvelle acquisition à chaque fois.

Solution:

  • Pour l’identité de l’utilisateur de l’agent : réutiliser la même ClaimsPrincipal instance entre les appels
  • Vérifier la connexion de cache distribué (si vous utilisez Redis/SQL)
  • Activer la journalisation du débogage pour afficher les opérations de cache

Guide détaillé des diagnostics :journalisation et diagnostics