-
Notifications
You must be signed in to change notification settings - Fork 219
v2.0
Whether you are building an ASP.NET or OWIN web app or web API, or a daemon application running on .NET Framework, or .NET Core, you can now use the same code to acquire tokens to call (downstream) web APIs:
- If you want to call Microsoft graph, get a GraphServiceClient
- If you want to call a downstream web API other than Microsoft Graph and don't use an SDK provided by this service, use IDownstreamRestApi. Microsoft Identity Web takes care of the details about authentication tokens and protocols.
- If you need to use a specific SDK, or can't use IDownstreamRestApi, use:
- IAuthorizationHeaderProvider that computes the authorization header to call a downstream API (any protocol)
- or ITokenAcquirer if your SDK requires a token. In that case, the SDK probably only supports the bearer protocol.
You can use one configuration for all the platforms, in JSON, and inspired from the ASP.NET Core configuration.
The following sample configuration file is understood by ASP.NET Core, but also OWIN web apps and web APIs using Microsoft.Identity.Web, and daemon applications. This simplifies a lot the code.
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com",
"TenantId": "common",
"ClientId": "GUID", // from app registration
"EnablePiiLogging": false, // set to true to enable PII
// Computed by Id.Web, but overridable (and also to support other IdPs than AAD)
// "Authority": "https://login.microsoftonline.com/common/v2.0",
// If the app calls downstream APIs
"ClientCredentials": [
{
// Typically used with Federation identity with MSI
"SourceType": "SignedAssertionFromManagedIdentity",
"ManagedIdentityClientId": "optional GUID of user assigned Managed identity"
},
{
// Typically used with AKS (signed assertion from Identity federation for Kubernates
// for instance, if your app runs on AKS)
"SourceType": "SignedAssertionFilePath",
// If SignedAssertionFileDiskPath is not provided (below), uses the
// content of the AZURE_FEDERATED_TOKEN_FILE environment variable.
// "SignedAssertionFileDiskPath": "path to file on disc.",
},
{
"SourceType": "KeyVault",
"KeyVaultUrl": "https://webappsapistests.vault.azure.net",
"KeyVaultCertificateName": "Self-Signed-5-5-22"
},
{
"SourceType": "ClientSecret",
"ClientSecret": "***"
}
],
"SendX5C": false,
// If the app is a web API
"TokenDecryptionCredentials": [
{
"SourceType": "KeyVault",
"KeyVaultUrl": "https://webappsapistests.vault.azure.net",
"KeyVaultCertificateName": "Self-Signed-5-5-22"
}
],
"AllowWebApiToBeAuthorizedByACL": false,
// If the app is a web app:
"ResetPasswordPath": "/MicrosoftIdentity/Account/ResetPassword",
"ErrorPath": "/MicrosoftIdentity/Account/Error",
"WithSpaAuthCode": false,
"Audience": "Audience of your web API",
"Audiences": [],
"AzureRegion" : "TryAutoDetect",
// B2C Specific
"Domain": "microsoft.com",
"EditProfilePolicyId": null,
"SignUpSignInPolicyId": null,
"ResetPasswordPolicyId": null,
"DefaultUserFlow": null
},
// Downstream APIs
"DownstreamApis": [
{
"GraphBeta": {
"BaseUrl": "https://graph.microsoft.com/beta",
"Scopes": "user.read"
}
}
],
"Logging": {
}
}
For ASP.NET Core, see web apps and web APIs
IAppBuilder now has extension methods:
- AddMicrosoftIdentityWebApp (which supports guest accounts)
- AddMicrosoftIdentityWebApi
From the Controllers, it's possible to get an instance of GraphServiceClient, ITokenAcquirerFactory, and IAuthorizationHeaderProvider
The full code is available from tests/aspnet-mvc/OwinWebApp
The Startup.auth.cs can now be:
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Owin;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.TokenCacheProviders.InMemory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Identity.Client;
namespace OwinWebApp
{
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.AddMicrosoftIdentityWebApp(configureServices: services =>
{
services.Configure<ConfidentialClientApplicationOptions>(options =>
{ options.RedirectUri = "https://localhost:44386/"; });
services.AddMicrosoftGraph();
services.AddInMemoryTokenCaches();
});
}
}
}
The full code is available from tests\aspnet-mvc\OwinWebApi
using Owin;
using Microsoft.Identity.Web;
using Microsoft.IdentityModel.Logging;
using Microsoft.Identity.Web.TokenCacheProviders.InMemory;
using System.Diagnostics.Tracing;
using System.IO;
using System;
namespace OwinWebApi
{
public partial class Startup
{
// For more information on configuring authentication, please visit https://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
app.AddMicrosoftIdentityWebApi(configureServices: services =>
{
services.AddMicrosoftGraph();
services.AddInMemoryTokenCaches();
});
}
}
}
[Authorize]
public class TodoListController : ApiController
{
private static readonly Dictionary<int, Todo> todoStore = new Dictionary<int, Todo>();
// GET api/values
public async Task<IEnumerable<Todo>> Get()
{
// Example calling Graph
GraphServiceClient? graphServiceClient = this.GetGraphServiceClient();
var me = await graphServiceClient?.Me?.Request()?.GetAsync();
// Example getting a token to call a downstream web API
ITokenAcquirer tokenAcquirer = this.GetTokenAcquirer();
var result = await tokenAcquirer.GetTokenForUserAsync(new[] { "user.read" });
The full code is available from tests/daemon-app/Daemon-app/Program.cs
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Graph;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.TokenCacheProviders.Distributed;
namespace daemon_console
{
/// <summary>
/// This sample shows how to query the Microsoft Graph from a daemon application
/// which uses application permissions.
/// For more information see https://aka.ms/msal-net-client-credentials
/// </summary>
class Program
{
static async Task Main(string[] args)
{
TokenAcquirerFactory tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
IConfiguration configuration = tokenAcquirerFactory.Configuration;
IServiceCollection services = tokenAcquirerFactory.Services;
services.Configure<MicrosoftAuthenticationOptions>(option => configuration.Bind(option));
services.AddMicrosoftGraph(); // or services.AddTokenAcquisition() if you don't need graph
// Add a cache
services.AddDistributedTokenCaches();
var serviceProvider = tokenAcquirerFactory.Build();
// Example of usage of Microsoft Graph
GraphServiceClient graphServiceClient = serviceProvider.GetRequiredService<GraphServiceClient>();
var users = await graphServiceClient.Users
.Request()
.WithAppOnly()
.WithAuthenticationOptions(options => options.ProtocolScheme = "Bearer")
.GetAsync();
Console.WriteLine($"{users.Count} users");
// Get the authorization request creator service
IAuthorizationHeaderProvider authorizationHeaderProvider = serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>();
string authorizationHeader = await authorizationHeaderProvider.CreateAuthorizationHeaderForAppAsync("https://graph.microsoft.com/.default");
Console.WriteLine(authorizationHeader.Substring(0, authorizationHeader.IndexOf(" ")+4)+"...");
// Example of getting a token to call a dowstream web API
ITokenAcquirer tokenAcquirer = tokenAcquirerFactory.GetTokenAcquirer();
var result = await tokenAcquirer.GetTokenForAppAsync("https://graph.microsoft.com/.default");
Console.WriteLine($"Token expires on {result.ExpiresOn}");
}
}
}
When you use the Graph, you can now augment the request with WithAuthenticationOptions, which provides you with all the control you need.
var users = await graphServiceClient.Users
.Request()
.WithAppOnly()
.WithAuthenticationOptions(options => options.ProtocolScheme = "Bearer")
.GetAsync();
In the past, Microsoft.Identity.Web was exposing the MicrosoftIdentityOptions, but this was:
- only on ASP.NET Core
- and it inherited from OpenIdConnectOptions.
In v2.0, Microsoft.Identity.Web proposes MicrosoftAuthenticationOptions (specific to AAD), inheriting from AuthenticationOptions (standard compliant), and makes these available in OWIN and SDK/daemon scenarios as well as in ASP.NET Core. To avoid breaking you, the default configuration is still MicrosoftIdentityOptions in ASP.NET Core.
Between x3 and x6 for an end to end call to web API calling graph.
In Microsoft.Identity.Web 1.x, you could specify the ClientCertificates, in many different ways.
From Microsoft.Identity.Web 2.x, you can now specify ClientCredentials. In addition to certificates, (and client secrets), you'll be able to specify signed assertions generated by Managed identity, for instance when the app is hosted in Kubernetes, leveraging the identity federation for Kubernetes based on Azure workload identity for kubernetes .
// If the app calls downstream APIs
"ClientCredentials": [
// When running in the container with Azure workload identity for kubernetes.
{
"SourceType": "SignedAssertionFilePath",
"SignedAssertionFileDiskPath": "optional path to signed assertion"
},
// Fallback when running locally to debug
{
"SourceType": "KeyVault",
"KeyVaultUrl": "https://webappsapistests.vault.azure.net",
"KeyVaultCertificateName": "Self-Signed-5-5-22"
}
],
Microsoft.Identity.Web will try the credentials in the order you specify them, which means you can try things out locally, or deployed, seamlessly.
More credentials will be available as Azure AD supports them.
You can also now provide the UserAssignedManagedIdentityClientId per credential, instead of providing it statically for the application.
If you have specific ways to load your certificates, not supported by Microsoft.Identity.Web, you can add your own credential loader to the CredentialLoaders property of DefaultCertificateLoader
. For this, implement the ICredentialLoader
interface, and assign a value other than the enumerations in CredentialSource
.
/// <summary>
/// Interface to implement loading of credentials.
/// </summary>
public interface ICredentialLoader
{
/// <summary>
/// Load the credential from the description, if needed.
/// </summary>
/// <param name="credentialDescription">Description of the credential.</param>
void LoadIfNeeded(CredentialDescription credentialDescription);
/// <summary>
/// Loadable CredentialSource.
/// </summary>
CredentialSource CredentialSource { get; }
}
Microsoft.Identity.Web 1.x proposed IDownstreamWebApi, which grew organically, and had a number of feature requests that would provoke breaking changes. We kept IDownstreamWebApi, but propose a new interface IDownstreamRestApi, which takes into account your feedback
var httpResponseMessage = await downstreamRestApi.CallRestApiForAppAsync("GraphBeta", options =>
{
options.BaseUrl = "https://myapiUrl";
options.Scopes = new string[] { "api://myApi/scope" };
}).ConfigureAwait(false);
There are also all kind of generic overloads that enable you to pass-in input data and get back output.
-
The code is distributed in different assemblies
-
You won't have any breaking change if you were already doing the right thing with the authentication schemes (that is when you configure options you are already specifying an authentication scheme)
-
On ASP.NET core, Microosft.Identity.Web.MicrosoftGraph does no longer reference Microsoft.Identity.Web ...
- Home
- Why use Microsoft Identity Web?
- Web apps
- Web APIs
- Using certificates
- Minimal support for .NET FW Classic
- Logging
- Azure AD B2C limitations
- Samples
- Web apps
- Web app samples
- Web app template
- Call an API from a web app
- Managing incremental consent and conditional access
- Web app troubleshooting
- Deploy to App Services Linux containers or with proxies
- SameSite cookies
- Hybrid SPA
- Web APIs
- Web API samples
- Web API template
- Call an API from a web API
- Token Decryption
- Web API troubleshooting
- web API protected by ACLs instead of app roles
- gRPC apps
- Azure Functions
- Long running processes in web APIs
- Authorization policies
- Generic API
- Customization
- Logging
- Calling graph with specific scopes/tenant
- Multiple Authentication Schemes
- Utility classes
- Setting FIC+MSI
- Mixing web app and web API
- Deploying to Azure App Services
- Azure AD B2C issuer claim support
- Performance
- specify Microsoft Graph scopes and app-permissions
- Integrate with Azure App Services authentication
- Ajax calls and incremental consent and conditional access
- Back channel proxys
- Client capabilities