Integración de la API downstream con Microsoft.Identity.Web

Microsoft. Identity.Web proporciona varios enfoques para llamar a las API de bajada(incluidos Microsoft Graph, servicios de Azure y API REST personalizadas) desde las aplicaciones de ASP.NET Core, OWIN o .NET. Este artículo le ayuda a elegir el enfoque adecuado para su escenario y empezar a trabajar rápidamente.

Selección de enfoques

Use este árbol de decisión para seleccionar el mejor método para su escenario:

Tipo de API/Escenario Decisión/Criterios Cliente o clase recomendados
Microsoft Graph Debe llamar a las API de Microsoft Graph GraphServiceClient
SDK de Azure (Almacenamiento, KeyVault, etc.) Debe llamar a las API de Azure (SDK de Azure) MicrosoftIdentityTokenCredential con clientes de SDK de Azure
API personalizada con vinculación de token Seguridad mejorada con vinculación de certificados (mTLS PoP) IDownstreamApi con ProtocolScheme: "MTLS_POP"
API personalizada con vinculación de token Seguridad mejorada con la integración de HttpClient (mTLS PoP) MicrosoftIdentityMessageHandler con ProtocolScheme: "MTLS_POP"
API personalizada Simple, configurable IDownstreamApi
API personalizada uso de HttpClient + controlador de delegación MicrosoftIdentityMessageHandler
API personalizada usando tu HttpClient IAuthorizationHeaderProvider

Comparación de enfoques por complejidad y flexibilidad

En la tabla siguiente se resume cada enfoque por su caso de uso previsto, el nivel de complejidad y la flexibilidad.

Enfoque Mejor para Complejidad Configuración Flexibilidad
GraphServiceClient API de Microsoft Graph Low Simple Medio
MicrosoftIdentityTokenCredential clientes de SDK de Azure Low Simple Low
IDownstreamApi API REST con patrones estándar Low JSON + Código Medio
MicrosoftIdentityMessageHandler HttpClient con canalización de autenticación Medio Código Alto
IAuthorizationHeaderProvider Lógica de autenticación personalizada Alto Código Muy alto

Patrones de adquisición de tokens

Microsoft. Identity.Web admite tres patrones principales de adquisición de tokens:

graph LR
    A[Token Acquisition] --> B[Delegated<br/>On behalf of user]
    A --> C[App-Only<br/>Application permissions in all apps]
    A --> D[On-Behalf-Of OBO<br/>in web API]

    B --> B1[Web Apps]
    B --> B2[Daemon acting as user / user agent]
    C --> C1[Daemon Apps]
    C --> C2[Web APIs with app permissions]
    D --> D1[Web APIs calling other APIs]

    style B fill:#cfe2ff
    style C fill:#fff3cd
    style D fill:#f8d7da

Permisos delegados (tokens de usuario)

Use permisos delegados cuando la aplicación actúe en nombre de un usuario que ha iniciado sesión.

  • Escenario: la aplicación web llama a la API en nombre del usuario que ha iniciado sesión y a la identidad de usuario del agente autónomo.
  • Tipo de token: token de acceso con permisos delegados
  • Métodos: CreateAuthorizationHeaderForUserAsync(), GetForUserAsync()

Permisos de aplicación (tokens solo para aplicaciones)

Use permisos de aplicación cuando no haya ningún usuario presente y la aplicación se autentique como sí misma.

  • Escenario: una aplicación en modo daemon o un servicio en segundo plano que llama a una API. Identidad del agente autónomo
  • Tipo de token: token con permisos de aplicación para acceso
  • Métodos: CreateAuthorizationHeaderForAppAsync(), GetForAppAsync()

Flujo En nombre de (OBO)

Use el flujo de OBO cuando una API web necesite llamar a otra API de bajada mientras conserva la identidad del usuario.

  • Escenario: la API web recibe el token de usuario, llama a otra API en nombre de ese usuario y agentes interactivos.
  • Tipo de token: Nuevo token de acceso a través del flujo de OBO
  • Métodos: CreateAuthorizationHeaderForUserAsync() desde el contexto de la API web

Enlace de tokens (poP de mTLS)

El enlace de tokens agrega una capa adicional de seguridad mediante la vinculación criptográfica de tokens de acceso a certificados X.509.

  • Escenario: seguridad mejorada en la que los tokens se enlazan criptográficamente a los certificados según RFC 8705
  • Tipo de token: token de acceso con enlace de certificado (cnf reclamación)
  • Métodos: GetForAppAsync() con ProtocolScheme: "MTLS_POP"
  • Seguridad: impide el robo de tokens mediante el enlace de tokens a certificados específicos

Aprender más sobre el enlace de token con PoP de mTLS

Ejemplos de código de inicio rápido

En los ejemplos siguientes se muestra cada enfoque con código de un extremo a otro que se puede adaptar a la aplicación.

En el ejemplo siguiente se registra GraphServiceClient y se usa para llamar a Microsoft Graph en nombre del usuario que ha iniciado sesión y como una llamada solo a la aplicación.

// Installation
// dotnet add package Microsoft.Identity.Web.GraphServiceClient

// Startup configuration
using Microsoft.Identity.Web;

builder.Services.AddMicrosoftGraph();

// Usage in controller
public class HomeController : Controller
{
    private readonly GraphServiceClient _graphClient;

    public HomeController(GraphServiceClient graphClient)
    {
        _graphClient = graphClient;
    }

    public async Task<IActionResult> Profile()
    {
        // Delegated - calls on behalf of signed-in user
        var user = await _graphClient.Me.GetAsync();

        // App-only - requires app permissions
        var users = await _graphClient.Users
            .GetAsync(r => r.Options.WithAppOnly());

        return View(user);
    }
}

Obtenga más información sobre la integración de Microsoft Graph

Migración de GraphServiceClient y uso detallado

En el ejemplo siguiente se registra MicrosoftIdentityTokenCredential y se pasa a un cliente de Azure Blob Storage.

// Installation
// dotnet add package Microsoft.Identity.Web.Azure
// dotnet add package Azure.Storage.Blobs

// Startup configuration
using Microsoft.Identity.Web;

builder.Services.AddMicrosoftIdentityAzureTokenCredential();

// Usage
public class StorageService
{
    private readonly MicrosoftIdentityTokenCredential _credential;

    public StorageService(MicrosoftIdentityTokenCredential credential)
    {
        _credential = credential;
    }

    public async Task<List<string>> ListBlobsAsync()
    {
        var blobClient = new BlobServiceClient(
            new Uri("https://myaccount.blob.core.windows.net"),
            _credential);

        var container = blobClient.GetBlobContainerClient("mycontainer");
        var blobs = new List<string>();

        await foreach (var blob in container.GetBlobsAsync())
        {
            blobs.Add(blob.Name);
        }

        return blobs;
    }
}

Obtenga más información sobre la integración de SDK de Azure

En el ejemplo siguiente se configura una API de bajada con nombre en appsettings.json y se llama a ella con tokens delegados y solo de aplicación.

// Installation
// dotnet add package Microsoft.Identity.Web.DownstreamApi

// appsettings.json
{
  "DownstreamApis": {
    "MyApi": {
      "BaseUrl": "https://myapi.example.com",
      "Scopes": ["api://myapi/read", "api://myapi/write"]
    }
  }
}

// Startup configuration
using Microsoft.Identity.Web;

builder.Services.AddDownstreamApis(
    builder.Configuration.GetSection("DownstreamApis"));

// Usage
public class ApiService
{
    private readonly IDownstreamApi _api;

    public ApiService(IDownstreamApi api)
    {
        _api = api;
    }

    public async Task<Product> GetProductAsync(int id)
    {
        // Delegated - on behalf of user
        return await _api.GetForUserAsync<Product>(
            "MyApi",
            $"api/products/{id}"
        );
    }

    public async Task<List<Product>> GetAllProductsAsync()
    {
        // App-only - using app permissions
        return await _api.GetForAppAsync<List<Product>>(
            "MyApi",
            "api/products");
    }
}

Más información sobre IDownstreamApi

Enlace de tokens con mTLS PoP (seguridad mejorada)

El enlace de tokens proporciona una seguridad mejorada al vincular criptográficamente los tokens de acceso a los certificados X.509. Incluso si se intercepta un token, no se puede usar sin el certificado correspondiente.

// Installation
// dotnet add package Microsoft.Identity.Web.DownstreamApi

// appsettings.json
{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-client-id",
    "ClientCredentials": [
      {
        "SourceType": "StoreWithDistinguishedName",
        "CertificateStorePath": "CurrentUser/My",
        "CertificateDistinguishedName": "CN=YourCertificate"
      }
    ],
    "SendX5c": true
  },
  "SecureApi": {
    "BaseUrl": "https://api.contoso.com/",
    "RelativePath": "api/data",
    "ProtocolScheme": "MTLS_POP",
    "RequestAppToken": true,
    "Scopes": [ "api://your-api/.default" ]
  }
}

// Startup configuration
builder.Services.AddDownstreamApi(
    "SecureApi",
    builder.Configuration.GetSection("SecureApi"));

// Usage
public class SecureApiService
{
    private readonly IDownstreamApi _api;

    public SecureApiService(IDownstreamApi api)
    {
        _api = api;
    }

    public async Task<SecureData> GetSecureDataAsync()
    {
        // Token is bound to certificate - enhanced security
        return await _api.GetForAppAsync<SecureData>("SecureApi");
    }
}

Ventajas clave:

  • Protección contra el robo de tokens: los tokens robados son inútiles sin el certificado
  • Prevención de ataques de reproducción: los tokens no se pueden reproducir desde distintos clientes
  • Alineación de confianza cero: enlace criptográfico seguro entre el cliente y el token

Más información sobre la vinculación de tokens (PoP de mTLS)

MicrosoftIdentityMessageHandler (para la integración de HttpClient)

En el ejemplo siguiente, se agrega un controlador de delegación a HttpClient para que cada solicitud saliente incluya automáticamente un encabezado de autorización. El controlador registra ámbitos en el inicio y las solicitudes individuales pueden invalidar las opciones de token.

// Startup configuration
using Microsoft.Identity.Web;

builder.Services.AddHttpClient("MyApiClient", client =>
{
    client.BaseAddress = new Uri("https://myapi.example.com");
})
.AddHttpMessageHandler(sp => new MicrosoftIdentityMessageHandler(
    sp.GetRequiredService<IAuthorizationHeaderProvider>(),
    new MicrosoftIdentityMessageHandlerOptions
    {
        Scopes = new[] { "api://myapi/.default" }
    }));

// Usage
public class ApiService
{
    private readonly HttpClient _httpClient;

    public ApiService(IHttpClientFactory httpClientFactory)
    {
        _httpClient = httpClientFactory.CreateClient("MyApiClient");
    }

    public async Task<Product> GetProductAsync(int id)
    {
        var request = new HttpRequestMessage(HttpMethod.Get, $"api/products/{id}")
            .WithAuthenticationOptions(options =>
            {
                options.RequestAppToken = false; // Use delegated token
                options.scopes = [ "myApi.scopes" ];
            });

        var response = await _httpClient.SendAsync(request);
        response.EnsureSuccessStatusCode();

        return await response.Content.ReadFromJsonAsync<Product>();
    }
}

Más información sobre MicrosoftIdentityMessageHandler

IAuthorizationHeaderProvider (máxima flexibilidad)

En el ejemplo siguiente se recupera directamente un encabezado de autorización para poder adjuntarlo a cualquier solicitud HTTP junto con encabezados personalizados.

// Direct usage for custom scenarios
public class CustomAuthService
{
    private readonly IAuthorizationHeaderProvider _headerProvider;

    public CustomAuthService(IAuthorizationHeaderProvider headerProvider)
    {
        _headerProvider = headerProvider;
    }

    public async Task<string> CallApiAsync()
    {
        // Get auth header (includes "Bearer " + token)
        string authHeader = await _headerProvider
            .CreateAuthorizationHeaderForUserAsync(
                scopes: new[] { "api://myapi/.default" });

        using var client = new HttpClient();
        client.DefaultRequestHeaders.Add("Authorization", authHeader);
        client.DefaultRequestHeaders.Add("X-Custom-Header", "MyValue");

        var response = await client.GetStringAsync("https://myapi.example.com/data");
        return response;
    }
}

Más información sobre IAuthorizationHeaderProvider

Patrones de configuración

Microsoft. Identity.Web admite la configuración json y la configuración basada en código.

configuración de appsettings.json

El siguiente JSON muestra una configuración típica que registra credenciales de Microsoft Entra ID y dos API de destino.

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-client-id",
    "ClientCredentials": [
      {
        "SourceType": "SignedAssertionFromManagedIdentity"
      }
    ]
  },
  "DownstreamApis": {
    "MicrosoftGraph": {
      "BaseUrl": "https://graph.microsoft.com/v1.0",
      "Scopes": ["User.Read", "Mail.Read"]
    },
    "MyApi": {
      "BaseUrl": "https://myapi.example.com",
      "Scopes": ["api://myapi/read"]
    }
  }
}

Note

En el caso de las aplicaciones de demonio o consola, configure las appsettings.json propiedades: "Copiar en el directorio de salida" = "Copiar si es más reciente"

Más información sobre la configuración de credenciales

Configuración basada en código

También puede configurar credenciales y APIs descendentes directamente en el código, como se muestra en el ejemplo siguiente.

// Explicit configuration in code
builder.Services.Configure<MicrosoftIdentityApplicationOptions>(options =>
{
    options.Instance = "https://login.microsoftonline.com/";
    options.TenantId = "your-tenant-id";
    options.ClientId = "your-client-id";
    options.ClientCredentials = new[]
    {
        CertificateDescription.FromKeyVault(
            "https://myvault.vault.azure.net",
            "MyCertificate")
    };
});

builder.Services.AddDownstreamApi("MyApi", options =>
{
    options.BaseUrl = "https://myapi.example.com";
    options.Scopes = new[] { "api://myapi/read" };
});

Guías específicas del escenario

El mejor enfoque depende de dónde llame a la API desde:

Integración de aplicaciones web

Normalmente, las aplicaciones web llaman a las API de bajada en nombre del usuario que ha iniciado sesión.

  • Patrón principal: permisos delegados (en nombre del usuario)
  • Adquisición de tokens: se produce automáticamente durante el inicio de sesión.
  • Consideraciones especiales: consentimiento incremental, control de errores de consentimiento

Lea la guía de Web Apps

Integración de API web

Las APIs web utilizan el flujo On-Behalf-Of para intercambiar el token de usuario recibido por un nuevo token limitado al ámbito de la API de destino.

  • Patrón principal: flujo de On-Behalf-Of (OBO)
  • Adquisición de Token: Intercambiar el token entrante por el token descendente
  • Consideraciones especiales: procesos de ejecución prolongada, almacenamiento en caché de tokens, identidades de agente.

Lea la guía de API web.

Integración de aplicaciones en segundo plano

Las aplicaciones demonio se autentican por sí mismas sin un usuario que haya iniciado sesión.

  • Patrón principal: permisos de aplicación (solo para aplicaciones)
  • Adquisición de tokens: flujo de credenciales de cliente
  • Consideraciones especiales: No hay contexto de usuario, requiere consentimiento del administrador.
  • Avanzado: agentes autónomos, identidades de usuario del agente

Lea la guía de aplicaciones Daemon.

Manejo de errores para la adquisición de tokens

Todos los métodos de adquisición de tokens pueden producir excepciones que la aplicación debe controlar. En las apps web, el atributo [AuthorizeForScope(scopes)] gestiona el consentimiento incremental del usuario o su reautenticación.

En el ejemplo siguiente se muestra cómo detectar y controlar excepciones comunes de adquisición de tokens.

using Microsoft.Identity.Abstractions;

try
{
    var result = await _api.GetForUserAsync<Data>("MyApi", "api/data");
}
catch (MicrosoftIdentityWebChallengeUserException ex)
{
    // User needs to sign in or consent to additional scopes
    // In web apps, this triggers a redirect to Microsoft Entra ID
    throw;
}
catch (HttpRequestException ex)
{
    // Downstream API returned error
    _logger.LogError(ex, "API call failed");
}

Escenarios de error comunes

En la tabla siguiente se enumeran las excepciones más comunes y cómo resolverlas.

Exception Meaning Solución
MicrosoftIdentityWebChallengeUserException Se requiere el consentimiento del usuario Redireccione a Microsoft Entra ID para obtener el consentimiento. Usar el atributo AuthorizeForScopes o la clase ConsentHandler
MsalUiRequiredException Autenticación interactiva necesaria Gestionar desafíos en aplicaciones web
MsalServiceException error del servicio Microsoft Entra ID Comprobación de la configuración, reintento
HttpRequestException Error de API descendente Control de errores específicos de la API

Paquetes de NuGet necesarios

Elija el paquete que coincida con su escenario. En la tabla siguiente se enumeran cada paquete y cuándo usarlo.

Package propósito Cuándo se deben usar
Microsoft. Identity.Web.TokenAcquisition Servicios de adquisición de tokens Paquete principal
Microsoft. Identity.Web.DownstreamApi Abstracción de IDownstreamApi Llamada a las API REST
Microsoft. Identity.Web.GraphServiceClient integración de Microsoft Graph Llamando a Microsoft Graph (guía de migración)
Microsoft. Identity.Web. Azure integración de SDK de Azure Llamar a servicios de Azure
Microsoft. Identity.Web ASP.NET Core aplicaciones web y API web ASP.NET Core
Microsoft. Identity.Web.OWIN ASP.NET aplicaciones web OWIN y API web OWIN

Explore estas guías para ver tutoriales detallados y escenarios avanzados.