/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/AcquireTokenAsync/*'/> public override Task <SqlAuthenticationToken> AcquireTokenAsync(SqlAuthenticationParameters parameters) => Task.Run(async() => { AuthenticationResult result; string scope = parameters.Resource.EndsWith(s_defaultScopeSuffix) ? parameters.Resource : parameters.Resource + s_defaultScopeSuffix; string[] scopes = new string[] { scope }; if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryServicePrincipal) { IConfidentialClientApplication ccApp = ConfidentialClientApplicationBuilder.Create(parameters.UserId) .WithAuthority(parameters.Authority) .WithClientSecret(parameters.Password) .WithClientName(Common.DbConnectionStringDefaults.ApplicationName) .WithClientVersion(Common.ADP.GetAssemblyVersion().ToString()) .Build(); result = ccApp.AcquireTokenForClient(scopes).ExecuteAsync().Result; SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Active Directory Service Principal auth mode. Expiry Time: {0}", result.ExpiresOn); return(new SqlAuthenticationToken(result.AccessToken, result.ExpiresOn)); } /* * Today, MSAL.NET uses another redirect URI by default in desktop applications that run on Windows * (urn:ietf:wg:oauth:2.0:oob). In the future, we'll want to change this default, so we recommend * that you use https://login.microsoftonline.com/common/oauth2/nativeclient. * * https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-desktop-app-registration#redirect-uris */ string redirectUri = s_nativeClientRedirectUri; #if NETCOREAPP if (parameters.AuthenticationMethod != SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow) { redirectUri = "http://localhost"; } #endif PublicClientAppKey pcaKey = new PublicClientAppKey(parameters.Authority, redirectUri, _applicationClientId #if NETFRAMEWORK , _iWin32WindowFunc #endif #if NETSTANDARD , _parentActivityOrWindowFunc #endif ); IPublicClientApplication app = GetPublicClientAppInstance(pcaKey); if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryIntegrated) { if (!string.IsNullOrEmpty(parameters.UserId)) { result = app.AcquireTokenByIntegratedWindowsAuth(scopes) .WithCorrelationId(parameters.ConnectionId) .WithUsername(parameters.UserId) .ExecuteAsync().Result; } else { result = app.AcquireTokenByIntegratedWindowsAuth(scopes) .WithCorrelationId(parameters.ConnectionId) .ExecuteAsync().Result; } SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Active Directory Integrated auth mode. Expiry Time: {0}", result.ExpiresOn); } else if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryPassword) { SecureString password = new SecureString(); foreach (char c in parameters.Password) { password.AppendChar(c); } password.MakeReadOnly(); result = app.AcquireTokenByUsernamePassword(scopes, parameters.UserId, password) .WithCorrelationId(parameters.ConnectionId) .ExecuteAsync().Result; SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Active Directory Password auth mode. Expiry Time: {0}", result.ExpiresOn); } else if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryInteractive || parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow) { // Fetch available accounts from 'app' instance System.Collections.Generic.IEnumerable <IAccount> accounts = await app.GetAccountsAsync(); IAccount account; if (!string.IsNullOrEmpty(parameters.UserId)) { account = accounts.FirstOrDefault(a => parameters.UserId.Equals(a.Username, System.StringComparison.InvariantCultureIgnoreCase)); } else { account = accounts.FirstOrDefault(); } if (null != account) { try { // If 'account' is available in 'app', we use the same to acquire token silently. // Read More on API docs: https://docs.microsoft.com/dotnet/api/microsoft.identity.client.clientapplicationbase.acquiretokensilent result = await app.AcquireTokenSilent(scopes, account).ExecuteAsync(); SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token (silent) for {0} auth mode. Expiry Time: {1}", parameters.AuthenticationMethod, result.ExpiresOn); } catch (MsalUiRequiredException) { // An 'MsalUiRequiredException' is thrown in the case where an interaction is required with the end user of the application, // for instance, if no refresh token was in the cache, or the user needs to consent, or re-sign-in (for instance if the password expired), // or the user needs to perform two factor authentication. result = await AcquireTokenInteractiveDeviceFlowAsync(app, scopes, parameters.ConnectionId, parameters.UserId, parameters.AuthenticationMethod); SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token (interactive) for {0} auth mode. Expiry Time: {1}", parameters.AuthenticationMethod, result.ExpiresOn); } } else { // If no existing 'account' is found, we request user to sign in interactively. result = await AcquireTokenInteractiveDeviceFlowAsync(app, scopes, parameters.ConnectionId, parameters.UserId, parameters.AuthenticationMethod); SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token (interactive) for {0} auth mode. Expiry Time: {1}", parameters.AuthenticationMethod, result.ExpiresOn); } } else { SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | {0} authentication mode not supported by ActiveDirectoryAuthenticationProvider class.", parameters.AuthenticationMethod); throw SQL.UnsupportedAuthenticationSpecified(parameters.AuthenticationMethod); } return(new SqlAuthenticationToken(result.AccessToken, result.ExpiresOn)); });