Note
Access to this page requires authorization. You can try signing in or .
Access to this page requires authorization. You can try .
Migrate confidential client applications from ADAL.NET to MSAL.NET
In this how-to guide you'll migrate a confidential client application from Azure Active Directory Authentication Library for .NET (ADAL.NET) to Microsoft Authentication Library for .NET (MSAL.NET). Confidential client applications include web apps, web APIs, and daemon applications that call another service on their own behalf. For more information about confidential apps, see Authentication flows and application scenarios. If your app is based on ASP.NET Core, see Microsoft.Identity.Web.
For app registrations:
- You don't need to create a new app registration. (You keep the same client ID.)
- You don't need to change the preauthorizations (admin-consented API permissions).
Migration steps
Find the code that uses ADAL.NET in your app.
The code that uses ADAL in a confidential client app instantiates
AuthenticationContextand calls eitherAcquireTokenByAuthorizationCodeor one override ofAcquireTokenAsyncwith the following parameters:- A
resourceIdstring. This variable is the app ID URI of the web API that you want to call. - An instance of
IClientAssertionCertificateorClientAssertion. This instance provides the client credentials for your app to prove the identity of your app.
- A
After you've identified that you have apps that are using ADAL.NET, install the MSAL.NET NuGet package Microsoft.Identity.Client and update your project library references. For more information, see Install a NuGet package. To use token cache serializers, install Microsoft.Identity.Web.TokenCache.
Update the code according to the confidential client scenario. Some steps are common and apply across all the confidential client scenarios. Other steps are unique to each scenario.
Confidential client scenarios:
- Daemon scenarios supported by web apps, web APIs, and daemon console applications.
- Web API calling downstream web APIs supported by web APIs calling downstream web APIs on behalf of the user.
- Web app calling web APIs supported by web apps that sign in users and call a downstream web API.
You might have provided a wrapper around ADAL.NET to handle certificates and caching. This guide uses the same approach to illustrate the process of migrating from ADAL.NET to MSAL.NET. However, this code is only for demonstration purposes. Don't copy/paste these wrappers or integrate them in your code as they are.
Migrate daemon apps
Daemon scenarios use the OAuth2.0 client credential flow. They're also called service-to-service calls. Your app acquires a token on its own behalf, not on behalf of a user.
Find out if your code uses daemon scenarios
The ADAL code for your app uses daemon scenarios if it contains a call to AuthenticationContext.AcquireTokenAsync with the following parameters:
- A resource (app ID URI) as a first parameter
IClientAssertionCertificateorClientAssertionas the second parameter
AuthenticationContext.AcquireTokenAsync doesn't have a parameter of type UserAssertion. If it does, then your app is a web API, and it uses the web API calling downstream web APIs scenario.
Update the code of daemon scenarios
The following steps for updating code apply across all the confidential client scenarios:
- Add the MSAL.NET namespace in your source code:
using Microsoft.Identity.Client;. - Instead of instantiating
AuthenticationContext, useConfidentialClientApplicationBuilder.Createto instantiateIConfidentialClientApplication. - Instead of the
resourceIdstring, MSAL.NET uses scopes. Because applications that use ADAL.NET are preauthorized, you can always use the following scopes:new string[] { $"{resourceId}/.default" }. - Replace the call to
AuthenticationContext.AcquireTokenAsyncwith a call toIConfidentialClientApplication.AcquireTokenXXX, where XXX depends on your scenario.
In this case, replace the call to AuthenticationContext.AcquireTokenAsync with a call to IConfidentialClientApplication.AcquireTokenClient.
Here's a comparison of ADAL.NET and MSAL.NET code for daemon scenarios:
ADAL
MSAL
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
public partial class AuthWrapper
{
const string ClientId = "Guid (AppID)";
const string authority
= "https://login.microsoftonline.com/{tenant}";
// App ID URI of web API to call
const string resourceId = "https://target-api.domain.com";
X509Certificate2 certificate = LoadCertificate();
public async Task<AuthenticationResult> GetAuthenticationResult()
{
var authContext = new AuthenticationContext(authority);
var clientAssertionCert = new ClientAssertionCertificate(
ClientId,
certificate);
var authResult = await authContext.AcquireTokenAsync(
resourceId,
clientAssertionCert,
);
return authResult;
}
}
using Microsoft.Identity.Client;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
public partial class AuthWrapper
{
const string ClientId = "Guid (Application ID)";
const string authority
= "https://login.microsoftonline.com/{tenant}";
// App ID URI of web API to call
const string resourceId = "https://target-api.domain.com";
X509Certificate2 certificate = LoadCertificate();
IConfidentialClientApplication app;
public async Task<AuthenticationResult> GetAuthenticationResult()
{
var app = ConfidentialClientApplicationBuilder.Create(ClientId)
.WithCertificate(certificate)
.WithAuthority(authority)
.Build();
// Setup token caching https://learn.microsoft.com/azure/active-directory/develop/msal-net-token-cache-serialization?tabs=aspnet
// For example, for an in-memory cache with 1GB limit, use
app.AddInMemoryTokenCache(services =>
{
// Configure the memory cache options
services.Configure<MemoryCacheOptions>(options =>
{
options.SizeLimit = 1024 * 1024 * 1024; // in bytes (1 GB of memory)
});
}
var authResult = await app.AcquireTokenForClient(
new [] { $"{resourceId}/.default" })
// .WithTenantId(specificTenant)
// See https://aka.ms/msal.net/withTenantId
.ExecuteAsync()
.ConfigureAwait(false);
return authResult;
}
}
Benefit from token caching
If you don't setup token caching, the token issuer will throttle you, resulting in errors. It also takes a lot less to get a token from the cache (10-20ms) than it is from ESTS (500-30000ms).
If you want to implement a distributed token cache, see Token cache for a web app or web API (confidential client application).
Learn more about the daemon scenario and how it's implemented with MSAL.NET or Microsoft.Identity.Web in new applications.
MSAL benefits
Key benefits of MSAL.NET for your app include:
Resilience. MSAL.NET helps make your app resilient through:
- Microsoft Entra ID Cached Credential Service (CCS) benefits. CCS operates as a Microsoft Entra backup.
- Proactive renewal of tokens if the API that you call enables long-lived tokens through continuous access evaluation.
Security. You can acquire Proof of Possession (PoP) tokens if the web API that you want to call requires it. For details, see Proof Of Possession tokens in MSAL.NET
Performance and scalability. If you don't need to share your cache with ADAL.NET, disable the legacy cache compatibility when you're creating the confidential client application (
.WithLegacyCacheCompatibility(false)) to significantly increase performance.app = ConfidentialClientApplicationBuilder.Create(ClientId) .WithCertificate(certificate) .WithAuthority(authority) .WithLegacyCacheCompatibility(false) .Build();
Troubleshooting
MsalServiceException
The following troubleshooting information makes two assumptions:
- Your ADAL.NET code was working.
- You migrated to MSAL by keeping the same client ID.
If you get an exception with either of the following messages:
AADSTS700027: Client assertion contains an invalid signature. [Reason - The key was not found.]
AADSTS90002: Tenant 'aaaabbbb-0000-cccc-1111-dddd2222eeee' not found. This may happen if there are no activesubscriptions for the tenant. Check to make sure you have the correct tenant ID. Check with your subscriptionadministrator.
Troubleshoot the exception using these steps:
- Confirm that you're using the latest version of MSAL.NET.
- Confirm that the authority host that you set when building the confidential client app and the authority host that you used with ADAL are similar. In particular, is it the same cloud (Azure Government, Microsoft Azure operated by 21Vianet, or Azure Germany)?
MsalClientException
In multi-tenant apps, specify a common authority when building the app to target a specific tenant such as, the tenant of the user when calling a web API. Since MSAL.NET 4.37.0, when you specify .WithAzureRegion at the app creation, you can no longer specify the Authority using .WithAuthority during the token requests. If you do, you'll get the following error when updating from previous versions of MSAL.NET:
MsalClientException - "You configured WithAuthority at the request level, and also WithAzureRegion. This is not supported when the environment changes from application to request. Use WithTenantId at the request level instead."
To remediate this issue, replace .WithAuthority on the AcquireTokenXXX expression by .WithTenantId. Specify the tenant using either a GUID or a domain name.
Next steps
Learn more about:
