-
Notifications
You must be signed in to change notification settings - Fork 394
Description
Library version used
4.82.1
.NET version
Summary
When using MSAL.NET with the Windows broker (WAM), silent token acquisition sometimes returns a token for a different OS-known account than the one explicitly requested, even though the tenant is pinned and an explicit IAccount is passed to AcquireTokenSilent. The same code and app registration with the Android broker (Microsoft Authenticator) consistently returns the correct account. This appears to be a WAM-specific account selection regression/bug.
Environment
- MSAL packages:
- Microsoft.Identity.Client = 4.82.1
- Microsoft.Identity.Client.Broker = 4.82.1
- Microsoft.Identity.Client.Extensions.Msal = 4.82.1
- OS / Device:
- Windows 11 (repro)
- Android 24 (works as expected)
- .NET target: 10
- App type: Desktop public client using WAM broker (
WithBroker) - Scopes:
https://api.businesscentral.dynamics.com/.default
Minimal Code Sample
var tenantId = "<TENANT_ID>";
var clientId = "<CLIENT_ID>";
var scopes = new[] { "https://api.businesscentral.dynamics.com/.default" };
var pca = PublicClientApplicationBuilder
.Create(clientId)
.WithAuthority($"https://login.microsoftonline.com/organizations")
.WithDefaultRedirectUri()
.WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows))
.Build();
// Optional: file cache if desired
// var storageProps = new StorageCreationPropertiesBuilder("MSAL.dat", "<CACHE_DIR>").Build();
// var cacheHelper = await MsalCacheHelper.CreateAsync(storageProps);
// cacheHelper.RegisterCache(pca.UserTokenCache);
// A) Interactive (force account picker)
var interactive = pca.AcquireTokenInteractive(scopes)
.WithTenantId(tenantId);
.WithPrompt(Prompt.SelectAccount);
var resultInteractive = await interactive.ExecuteAsync();
// B) Silent for the *same* account
var accounts = await pca.GetAccountsAsync();
var account = accounts.FirstOrDefault(a => a.Username.Equals("<INTENDED_UPN>", StringComparison.OrdinalIgnoreCase));
var resultSilent = await pca.AcquireTokenSilent(scopes, account)
.WithTenantId(tenantId)
.ExecuteAsync();
// On Windows WAM, resultSilent may carry claims for a *different* identityExpected Behavior
On Windows (WAM), when the tenant is pinned and a specific IAccount is provided to AcquireTokenSilent, MSAL/WAM should return a token for that exact account—parity with the observed behavior on Android broker.
Actual Behavior
On Windows (WAM), the returned token’s identity sometimes corresponds to a different OS-known account (e.g., a technician/guest identity), even though:
- The authority/tenant is pinned, and
- The explicit
IAccountpassed toAcquireTokenSilentmatches the intended user, and Prompt.SelectAccountwas used during interactive acquisition.
Workarounds Tried
- Tenant pinning at PCA build and per-request
.WithTenantId(tenantId)→ still repro. - Passing explicit
IAccounttoAcquireTokenSilent(scopes, account)→ still repro. Prompt.SelectAccount+WithLoginHintduring interactive → still repro.- Removing the unwanted account from MSAL cache → still repro when that account remains known to the OS/WAM.
- Disabling broker (browser fallback) → no repro (correct account is used consistently).
Logs
Verbose MSAL logs with PII enabled show the requested HomeAccountId/Username versus the identity that WAM ultimately resolves for the silent call. Redacted logs can be attached privately if needed.
Why This Seems Like a Bug
Documentation indicates that apps can deterministically control which tenant/account is used via tenant pinning and by passing the desired IAccount to AcquireTokenSilent. Returning a token for a different identity under WAM contradicts these expectations, especially given that Android broker behaves correctly with the same inputs.
Related Docs / References (context)
- Using MSAL.NET with the Windows broker (WAM): https://learn.microsoft.com/entra/msal/dotnet/acquiring-tokens/desktop-mobile/wam
- Acquire tokens interactively (Prompt and account selection): https://learn.microsoft.com/entra/msal/dotnet/acquiring-tokens/desktop-mobile/acquiring-tokens-interactively
- Interactive builder authority deprecations; use
WithTenantId(...)at request level: https://learn.microsoft.com/dotnet/api/microsoft.identity.client.acquiretokeninteractiveparameterbuilder - Recently addressed broker item (force refresh support for silent broker flows): Add .WithForceRefresh support for silent broker flows #4457
Ask
- Please confirm whether WAM is expected to always honor the explicit
IAccountand tenant pinning during silent acquisition. - If yes, this appears to be a bug; guidance/workaround or a fix would be appreciated.
- If by design, could documentation clarify how WAM resolves accounts when multiple identities are present and how apps can reliably override that to achieve parity with Android broker?
Scenario
PublicClient - desktop app
Is this a new or an existing app?
This is a new app or experiment
Issue description and reproduction steps
Steps to Reproduce
- Build a public client with WAM broker enabled and a "organizations" authority.
- Perform an interactive acquisition and force account selection
- Use
.WithTenantId(tenantId)on requests - Call
AcquireTokenSilent(scopes, account)with the exactIAccountreturned byGetAccountsAsync(). - Inspect the access token claims (
email,unique_name,name). - On Windows (WAM), the token occasionally belongs to a different identity (another OS-known account) than the one passed to
AcquireTokenSilent. - On Android broker, the same code returns the correct identity consistently.
Relevant code snippets
Expected behavior
No response
Identity provider
Microsoft Entra ID (Work and School accounts and Personal Microsoft accounts)
Regression
No response
Solution and workarounds
No response