Enable WAM Broker support for Entra ID Auth modes#4288
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds WAM broker support to the Azure extension authentication provider for Entra ID public-client authentication flows on Windows.
Changes:
- Adds
Microsoft.Identity.Client.Brokerdependency and broker configuration during PCA creation. - Adds parent-window callback API and Windows interop helpers for WAM prompt parenting.
- Adds basic tests and a draft feature spec for WAM broker support.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
Directory.Packages.props |
Adds centralized MSAL broker package version. |
src/Microsoft.Data.SqlClient.Extensions/Azure/src/Azure.csproj |
References the broker package from the Azure extension. |
src/Microsoft.Data.SqlClient.Extensions/Azure/src/ActiveDirectoryAuthenticationProvider.cs |
Makes the provider partial, adds parent-window callback API, and configures WAM broker on Windows. |
src/Microsoft.Data.SqlClient.Extensions/Azure/src/ActiveDirectoryAuthenticationProvider.Windows.cs |
Adds Windows-specific parent-window discovery for broker UI. |
src/Microsoft.Data.SqlClient.Extensions/Azure/src/Interop/Interop.GetAncestor.cs |
Adds user32.GetAncestor interop helper. |
src/Microsoft.Data.SqlClient.Extensions/Azure/src/Interop/Interop.GetConsoleWindow.cs |
Adds kernel32.GetConsoleWindow interop helper. |
src/Microsoft.Data.SqlClient.Extensions/Azure/test/WamBrokerTests.cs |
Adds basic tests for the new parent-window setter. |
specs/002-wam-broker/spec.md |
Adds the draft WAM broker feature specification. |
Comments suppressed due to low confidence (5)
src/Microsoft.Data.SqlClient.Extensions/Azure/src/ActiveDirectoryAuthenticationProvider.cs:766
- The parent-window delegate is captured on the cached PublicClientApplication, but the static PCA cache key does not include the new SetParentActivityOrWindow callback. A later provider instance with the same authority/client/redirect can reuse an app built with an earlier provider's delegate, causing WAM prompts to be parented to the wrong window (or to ignore the later callback). Include the callback identity in the cache key or avoid capturing provider instance state in the cached app.
builder.WithParentActivityOrWindow(GetBrokerParentWindow);
}
#else
builder.WithParentActivityOrWindow(GetBrokerParentWindow);
src/Microsoft.Data.SqlClient.Extensions/Azure/src/ActiveDirectoryAuthenticationProvider.cs:752
- The tests added for this feature only exercise the setter and do not verify that Windows PCA construction actually enables the broker or wires the parent-window callback. Please add unit coverage around CreateClientAppInstance (or an observable wrapper) so regressions in the WAM configuration are caught without relying solely on manual integration testing.
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
builder.WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows));
specs/002-wam-broker/spec.md:70
- This API description says Func can return IWin32Window, but the implementation only accepts IntPtr from this callback and silently ignores any other object type before falling back to console detection. Please either document only the supported return type or handle IWin32Window here as described.
// Cross-platform API to set the parent window/activity for WAM dialog // On Windows: accepts IntPtr (window handle) or IWin32Window via Func<object> // On Unix: no-op (WAM not available) public void SetParentActivityOrWindow(Func<object> parentActivityOrWindowFunc);specs/002-wam-broker/spec.md:131
- This rollout note is inaccurate: SetIWin32WindowFunc is not changed to delegate to SetParentActivityOrWindow; it still stores a separate _iWin32WindowFunc and the new callback is independent. Please update the spec or implementation so consumers and maintainers do not rely on a delegation behavior that is not present.
- WAM broker is **always enabled** on Windows when using PCA flows - No opt-in connection string keyword needed (aligns with MSAL PCA compliance requirements) - Existing `SetIWin32WindowFunc` remains as a backward-compatible API on .NET Framework, delegating to `SetParentActivityOrWindow`src/Microsoft.Data.SqlClient.Extensions/Azure/src/ActiveDirectoryAuthenticationProvider.cs:749
- This comment overstates the behavior: the code still uses AcquireTokenByIntegratedWindowsAuth, AcquireTokenByUsernamePassword, and AcquireTokenWithDeviceCode for those modes, so broker configuration does not make every supported authentication mode a WAM flow. Please narrow the comment to the modes MSAL will actually broker or update the acquisition paths accordingly.
// Enable WAM broker on Windows for all supported authentication modes. // The broker provides enhanced security by enabling device-based Conditional Access // policies through the Windows Account Manager (WAM).
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 18 changed files in this pull request and generated 3 comments.
Files not reviewed (1)
- doc/apps/AzureSqlConnector/MainForm.Designer.cs: Language not supported
Comments suppressed due to low confidence (1)
doc/apps/AzureSqlConnector/README.md:110
- The last two
dotnet runlines appear duplicated and are not formatted as part of the Notes list or a code block. This looks like leftover copy/paste noise and should be removed (or moved into the earlier Build & Run section as a single example).
developer overrides).
- This is a sample / diagnostic tool, **not** a product. It does not persist credentials.
dotnet run --project .\doc\apps\AzureSqlConnector\AzureSqlConnector.csproj
dotnet run --project .\doc\apps\AzureSqlConnector\AzureSqlConnector.csproj
…et/SqlClient into dev/cheena/entra-wam-broker
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 18 changed files in this pull request and generated 6 comments.
Files not reviewed (1)
- doc/apps/AzureSqlConnector/MainForm.Designer.cs: Language not supported
Comments suppressed due to low confidence (2)
doc/apps/AzureSqlConnector/README.md:109
- These two trailing
dotnet runlines are duplicated and not formatted as a code block; the build/run instructions already appear earlier in the README.
dotnet run --project .\doc\apps\AzureSqlConnector\AzureSqlConnector.csproj
specs/002-wam-broker/spec.md:132
- The spec claims
SetIWin32WindowFuncdelegates toSetParentActivityOrWindow, but the current code keepsSetIWin32WindowFuncas a separate setting. Either implement that delegation or update this statement to avoid promising behavior that doesn't exist.
- WAM broker is **always enabled** on Windows when using PCA flows
- No opt-in connection string keyword needed (aligns with MSAL PCA compliance requirements)
- Existing `SetIWin32WindowFunc` remains as a backward-compatible API on .NET Framework, delegating to `SetParentActivityOrWindow`
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 24 out of 26 changed files in this pull request and generated 2 comments.
Files not reviewed (2)
- doc/apps/AzureSqlConnector/MainForm.Designer.cs: Generated file
- doc/apps/AzureSqlConnector/MainFormWorker.Designer.cs: Generated file
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 28 out of 31 changed files in this pull request and generated 5 comments.
Files not reviewed (3)
- doc/apps/AzureSqlConnector/MainForm.Designer.cs: Generated file
- doc/apps/AzureSqlConnector/MainFormWorker.Designer.cs: Generated file
- src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs: Generated file
mdaigle
left a comment
There was a problem hiding this comment.
I don't love what we have to do in the SqlAuthProviderManager, but don't see another easy option right now.
…er is signed in interactively)
paulmedynski
left a comment
There was a problem hiding this comment.
Approving on the condition that all of my open feedback is captured for a followup PR.
I'm a bit nervous about the new reflection in the Azure provider - will that affect AOT apps?
…nless user is signed in interactively)" This reverts commit b802a2e.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 30 out of 33 changed files in this pull request and generated 2 comments.
Files not reviewed (3)
- doc/apps/AzureSqlConnector/MainForm.Designer.cs: Generated file
- doc/apps/AzureSqlConnector/MainFormWorker.Designer.cs: Generated file
- src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs: Generated file
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 30 out of 33 changed files in this pull request and generated 1 comment.
Files not reviewed (3)
- doc/apps/AzureSqlConnector/MainForm.Designer.cs: Generated file
- doc/apps/AzureSqlConnector/MainFormWorker.Designer.cs: Generated file
- src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs: Generated file
Enable WAM Broker support for Entra ID Auth modes
Summary
Enables Windows Account Manager (WAM) broker for interactive Entra ID auth in
Microsoft.Data.SqlClient.Extensions.Azure(Integrated,Password[deprecated],Interactive,DeviceCodeFlow). WAM gives Windows users SSO, Windows Hello and conditional-access support.Behavior
ActiveDirectoryAuthenticationProviderOptions.UseWamBroker(default off, backward compatible) or via the newuseWamBrokerattribute on the<SqlClientAuthenticationProviders>config section (parsed asbool; unset/invalid leaves the default untouched).SetParentActivityOrWindowFuncis now forwarded to MSAL on all platforms so Android/iOS/MAUI callers can supply a parentActivity/UIViewController.CancellationTokenSource(capped at the typical AAD user-code lifetime of 3 mins) instead of inheritingConnect Timeout, fixing the"The operation was canceled."failure when the user takes longer than 15s to enter the code._fedAuthTokenand_newDbConnectionPoolAuthenticationContextare now cleared along with_dbConnectionPoolAuthenticationContextKey; otherwise the secondOnFedAuthInfocall tripsDebug.Assert(_fedAuthToken == null). WAM Interactive surfaces this easily because the broker prompt routinely outlivesConnect Timeout.New Public APIs
In
Microsoft.Data.SqlClient.Extensions.Azure:Existing constructors (
(),(string applicationClientId),(Func<DeviceCodeResult, Task>, string? applicationClientId = null)) are unchanged and remain source- and binary-compatible.Configuration
Usage
Changes
ActiveDirectoryAuthenticationProvider.Windows.cs, newInterop.GetAncestor/Interop.GetConsoleWindow). Updated WAM (Windows) and system-browser (Unix) redirect-URI handling.ActiveDirectoryAuthenticationProviderOptionstype and matching constructor overload. All new knobs live on the options bag so future additions don't require new overloads.SetParentActivityOrWindowFuncis now forwarded to MSAL on non-Windows targets (Android/iOS/MAUI) in addition to Windows.useWamBrokerconfig attribute on<SqlClientAuthenticationProviders>for declarative opt-in.SqlAuthenticationProviderManager's static initializer:applicationClientIdand nouseWamBrokerare configured, calls the parameterless constructor; otherwise explicitly resolves the(ActiveDirectoryAuthenticationProviderOptions)constructor viaType.GetConstructorand reflectively sets only the properties the app actually configured. This avoids theAmbiguousMatchExceptionthatActivator.CreateInstance(type, new object?[] { null })previously raised once the type had two 1-arg constructors ((string)and(ActiveDirectoryAuthenticationProviderOptions)) that both acceptnull.AmbiguousMatchExceptionandTypeInitializationExceptionso a broken/older Azure extension never throwsTypeInitializationExceptionout ofGetProviderand bricks every SqlClient connection (including non-AD ones).SqlConnectionInternal.AttemptRetryADAuthWithTimeoutErrornow clears_fedAuthTokenand_newDbConnectionPoolAuthenticationContextbefore retrying; dropped the unusedconnectionOptionsparameter while in there.AcquireTokenInteractiveDeviceFlowAsyncallocates its ownCancellationTokenSourcefor the DCF branch instead of inheriting the outer per-request CTS — fixes theConnect Timeout-cancels-DCF bug.Microsoft.Identity.Clientto4.84.2and addedMicrosoft.Identity.Client.Broker4.84.2on the Azure extension so MSAL can light up WAM.WamBrokerTests.cs(16 tests) covering built-in vs. custom client id,UseWamBrokertrue/false, options-bag precedence, and the new constructor path; plus aGetProvider_ForActiveDirectoryMethod_DoesNotThrowregression test inSqlAuthenticationProviderManagerTestspinning the static-initializer fix.doc/apps/AzureSqlConnector(multi-targetsnet481andnet10.0-windows) with a mode selector that launches eitherMainForm(OpenAsync()on the UI thread) orMainFormWorker(syncOpen()on a worker, parent HWND captured up-front on the UI thread). The sample's DCF callback surfaces the user code three ways — log textbox viaBeginInvoke, default browser viaProcess.Start, and a modalMessageBoxon the MSAL callback thread — so the code is visible even when a syncOpen()blocks the UI thread.Testing
WamBrokerTests.cs+SqlAuthenticationProviderManagerbootstrap regression test)ClearUserTokenCache()behavior is unchangedConnect Timeout)Open()on a worker) and async (OpenAsync()on the UI thread) via the sample's mode selector