RKSAD0001 — AuthenticationContext
ADAL’s AuthenticationContext is the entry point every ADAL consumer touches first. Microsoft deprecated ADAL in June 2022 and stopped security updates. The replacement is MSAL (Microsoft.Identity.Client), and it has a different shape — builder pattern, different exceptions, different token cache model, different silent-acquisition semantics.
Rokstep.IdentityModel.Clients.ActiveDirectory.Shims keeps your existing code compiling on .NET 6/8 by delegating every ADAL call to an MSAL client internally. That’s enough to unblock your migration build, but the diagnostic keeps firing so you know this line still needs to be rewritten.
30-second fix — drop-in shim
dotnet add package Rokstep.IdentityModel.Clients.ActiveDirectory.ShimsNo code changes. Compile. Done. The shim logs a build warning for each AuthenticationContext reference so you can track what’s left to migrate.
Real migration — confidential client (service-to-service / daemon apps)
If you were using ADAL with a ClientCredential (client ID + client secret), you want MSAL’s IConfidentialClientApplication:
Before (ADAL):
using Microsoft.IdentityModel.Clients.ActiveDirectory;
var context = new AuthenticationContext("https://login.microsoftonline.com/contoso.onmicrosoft.com");var credential = new ClientCredential("client-id-guid", "client-secret");
AuthenticationResult result = await context.AcquireTokenAsync( resource: "https://graph.microsoft.com", clientCredential: credential);
string accessToken = result.AccessToken;After (MSAL):
using Microsoft.Identity.Client;
var app = ConfidentialClientApplicationBuilder .Create("client-id-guid") .WithClientSecret("client-secret") .WithAuthority("https://login.microsoftonline.com/contoso.onmicrosoft.com") .Build();
AuthenticationResult result = await app .AcquireTokenForClient(new[] { "https://graph.microsoft.com/.default" }) .ExecuteAsync();
string accessToken = result.AccessToken;Three things changed:
- Builder pattern. You build the app once (at startup) and reuse it, not instantiate
AuthenticationContextper call. - Scopes, not resources. ADAL’s
resource: "https://graph.microsoft.com"becomesscopes: new[] { "https://graph.microsoft.com/.default" }. The.defaultsuffix means “give me the app’s statically-granted permissions.” You can also request specific scopes likeUser.Readfor delegated flows. - Separate method per flow. ADAL’s
AcquireTokenAsyncdid everything via overloads. MSAL splits intoAcquireTokenForClient(client credentials),AcquireTokenInteractive(interactive user),AcquireTokenSilent(cached token), etc.
Real migration — public client (interactive user login)
If you were using ADAL for interactive user login (desktop app, MAUI, device code flow):
Before (ADAL):
var context = new AuthenticationContext("https://login.microsoftonline.com/common");var result = await context.AcquireTokenAsync( resource: "https://graph.microsoft.com", clientId: "client-id-guid", redirectUri: new Uri("http://localhost"), parameters: new PlatformParameters(PromptBehavior.Auto));After (MSAL):
var app = PublicClientApplicationBuilder .Create("client-id-guid") .WithAuthority("https://login.microsoftonline.com/common") .WithRedirectUri("http://localhost") .Build();
var result = await app .AcquireTokenInteractive(new[] { "https://graph.microsoft.com/.default" }) .ExecuteAsync();Gotchas
1. Token cache persistence is now your problem
ADAL’s TokenCache was an in-process dictionary — you passed it to the AuthenticationContext constructor and ADAL used it. MSAL has a similar cache but it’s in-memory only by default. For desktop/daemon apps that need persistence across restarts, you must wire up a serializer:
// Desktop app: persist token cache to user profile via MSAL.Net token cache helpervar storageProperties = new StorageCreationPropertiesBuilder( "myapp_cache.bin", MsalCacheHelper.UserRootDirectory) .Build();
var cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties);cacheHelper.RegisterCache(app.UserTokenCache);Install the helper: dotnet add package Microsoft.Identity.Client.Extensions.Msal.
Without this, every restart of your app forces the user through interactive login again.
2. MsalUiRequiredException, not AdalSilentTokenAcquisitionException
ADAL threw AdalSilentTokenAcquisitionException when a cached token was missing or expired and silent refresh wasn’t possible. MSAL throws MsalUiRequiredException, and you’re expected to catch it and fall back to interactive acquisition:
try{ result = await app.AcquireTokenSilent(scopes, account).ExecuteAsync();}catch (MsalUiRequiredException){ result = await app.AcquireTokenInteractive(scopes).ExecuteAsync();}If you had a try/catch on AdalSilentTokenAcquisitionException anywhere in your ADAL code, that’s where you need to update the catch clause first.
3. Authority URL format hasn’t changed, but tenant-specific is strongly recommended
ADAL and MSAL both accept https://login.microsoftonline.com/common (multi-tenant), https://login.microsoftonline.com/organizations, https://login.microsoftonline.com/consumers, or a specific tenant ID/domain. If you know your tenant, use the tenant-specific authority. It’s measurably faster (no tenant discovery round-trip) and avoids the single most common MSAL configuration error (“which account should sign in?“).
4. The shim does NOT cover UserPasswordCredential (ROPC)
Resource Owner Password Credentials flow (username + password sent directly to the auth endpoint) was removed from MSAL entirely because it’s incompatible with MFA, Conditional Access, and modern identity hygiene. If your ADAL code used new UserPasswordCredential(user, pass), the shim emits RKSAD0004 as an error (not a warning) — you cannot ship this pattern in MSAL. Migrate the affected code paths to device code flow or interactive flow before you can compile on .NET 8.
While you’re at it
The migration is a good moment to review the Hardened Migration Security Checklist — specifically items 1 (hardcoded secrets), 2 (expired auth flows), and 3 (weak crypto). If your ADAL code was hardcoding client secrets in web.config, this is the moment to move them to Key Vault.
Related IDs in rokstep-adal-shims
RKSAD0002 · RKSAD0003 · RKSAD0004 · RKSAD0005 · RKSAD0006 · RKSAD0007 · RKSAD0008 · RKSAD0009 · RKSAD0010 · RKSAD0011
Not your kind of work? Let me do it for you.