public async Task ATI_RequiresSyncContext_Async() { var wamBroker = new WamBroker( new CoreUIParent(), // no sync context here _logger, _aadPlugin, _msaPlugin, _wamProxy, _webAccountProviderFactory, _accountPickerFactory); using (var harness = CreateTestHarness()) { var requestParams = harness.CreateAuthenticationRequestParameters(TestConstants.AuthorityHomeTenant); // AAD var atiParams = new AcquireTokenInteractiveParameters(); // Act var ex = await AssertException.TaskThrowsAsync <MsalClientException>( () => wamBroker.AcquireTokenInteractiveAsync(requestParams, atiParams)).ConfigureAwait(false); // Assert Assert.AreEqual(MsalError.WamUiThread, ex.ErrorCode); } }
public void RedirectUriContainsFragmentErrorTest() { try { using (var harness = CreateTestHarness()) { AuthenticationRequestParameters parameters = harness.CreateAuthenticationRequestParameters( TestConstants.AuthorityHomeTenant, TestConstants.s_scope, new TokenCache(harness.ServiceBundle), extraQueryParameters: new Dictionary <string, string> { { "extra", "qp" } }); parameters.RedirectUri = new Uri("some://uri#fragment=not-so-good"); parameters.LoginHint = TestConstants.DisplayableId; var interactiveParameters = new AcquireTokenInteractiveParameters { Prompt = Prompt.ForceLogin, ExtraScopesToConsent = TestConstants.s_scopeForAnotherResource.ToArray(), }; new InteractiveRequest( harness.ServiceBundle, parameters, interactiveParameters, new MockWebUI()); Assert.Fail("ArgumentException should be thrown here"); } } catch (ArgumentException ae) { Assert.IsTrue(ae.Message.Contains(MsalErrorMessage.RedirectUriContainsFragment)); } }
private void CreateBrokerHelper() { using (MockHttpAndServiceBundle harness = CreateTestHarness()) { AuthenticationRequestParameters parameters = harness.CreateAuthenticationRequestParameters( MsalTestConstants.AuthorityHomeTenant, MsalTestConstants.Scope, new TokenCache(harness.ServiceBundle), extraQueryParameters: MsalTestConstants.ExtraQueryParams, claims: MsalTestConstants.Claims); parameters.IsBrokerEnabled = true; AcquireTokenInteractiveParameters interactiveParameters = new AcquireTokenInteractiveParameters(); InteractiveRequest request = new InteractiveRequest( harness.ServiceBundle, parameters, interactiveParameters, new MockWebUI()); _brokerInteractiveRequest = new BrokerInteractiveRequest(parameters, interactiveParameters, harness.ServiceBundle, null); } }
private IWebUI CreateWebAuthenticationDialog( AcquireTokenInteractiveParameters interactiveParameters, RequestContext requestContext) { if (interactiveParameters.CustomWebUi != null) { return(new CustomWebUiHandler(interactiveParameters.CustomWebUi)); } var coreUiParent = interactiveParameters.UiParent; #if ANDROID || iOS coreUiParent.UseEmbeddedWebview = interactiveParameters.UseEmbeddedWebView; #endif #if WINDOWS_APP || DESKTOP // hidden web view can be used in both WinRT and desktop applications. coreUiParent.UseHiddenBrowser = interactiveParameters.Prompt.Equals(Prompt.Never); #if WINDOWS_APP coreUiParent.UseCorporateNetwork = _publicClientApplication.AppConfig.UseCorporateNetwork; #endif #endif return(ServiceBundle.PlatformProxy.GetWebUiFactory().CreateAuthenticationDialog(coreUiParent, requestContext)); }
private MockHttpAndServiceBundle CreateBrokerHelper() { MockHttpAndServiceBundle harness = CreateTestHarness(); _parameters = harness.CreateAuthenticationRequestParameters( TestConstants.AuthorityHomeTenant, TestConstants.s_scope, new TokenCache(harness.ServiceBundle, false), extraQueryParameters: TestConstants.ExtraQueryParameters, claims: TestConstants.Claims); _parameters.IsBrokerConfigured = true; AcquireTokenInteractiveParameters interactiveParameters = new AcquireTokenInteractiveParameters(); _acquireTokenSilentParameters = new AcquireTokenSilentParameters(); IBroker broker = harness.ServiceBundle.PlatformProxy.CreateBroker(null); _brokerInteractiveRequest = new BrokerInteractiveRequestComponent( _parameters, interactiveParameters, broker, "install_url"); _brokerSilentAuthStrategy = new SilentBrokerAuthStrategy( new SilentRequest(harness.ServiceBundle, _parameters, _acquireTokenSilentParameters), harness.ServiceBundle, _parameters, _acquireTokenSilentParameters, broker); return(harness); }
/// <summary> /// In WAM, AcquireTokenInteractive is always associated to an account. WAM also allows for an "account picker" to be displayed, /// which is similar to the EVO browser experience, allowing the user to add an account or use an existing one. /// /// MSAL does not have a concept of account picker so MSAL.AccquireTokenInteractive will: /// /// 1. Call WAM.AccountPicker if an IAccount (or possibly login_hint) is not configured /// 2. Figure out the WAM.AccountID associated to the MSAL.Account /// 3. Call WAM.AcquireTokenInteractive with the WAM.AccountID /// /// To make matters more complicated, WAM has 2 plugins - AAD and MSA. With AAD plugin, /// it is possible to list all WAM accounts and find the one associated to the MSAL account. /// However, MSA plugin does NOT allow listing of accounts, and the only way to figure out the /// WAM account ID is to use the account picker. This makes AcquireTokenSilent impossible for MSA, /// because we would not be able to map an Msal.Account to a WAM.Account. To overcome this, /// we save the WAM.AccountID in MSAL's cache. /// </summary> public async Task <MsalTokenResponse> AcquireTokenInteractiveAsync( AuthenticationRequestParameters authenticationRequestParameters, AcquireTokenInteractiveParameters acquireTokenInteractiveParameters) { #if WINDOWS_APP if (_synchronizationContext == null) { throw new MsalClientException( MsalError.WamUiThread, "AcquireTokenInteractive with broker must be called from the UI thread when using WAM." + ErrorMessageSuffix); } #endif if (authenticationRequestParameters.Account != null || !string.IsNullOrEmpty(authenticationRequestParameters.LoginHint)) { bool isMsaPassthrough = _wamOptions.MsaPassthrough; bool isMsa = await IsMsaRequestAsync( authenticationRequestParameters.Authority, authenticationRequestParameters?.Account?.HomeAccountId?.TenantId, // TODO: we could further optimize here by searching for an account based on UPN isMsaPassthrough).ConfigureAwait(false); IWamPlugin wamPlugin = isMsa ? _msaPlugin : _aadPlugin; WebAccountProvider provider = await GetProviderAsync( authenticationRequestParameters.Authority.TenantId, isMsa) .ConfigureAwait(false); if (PublicClientApplication.IsOperatingSystemAccount(authenticationRequestParameters.Account)) { var wamResult = await AcquireInteractiveWithWamAccountAsync( authenticationRequestParameters, acquireTokenInteractiveParameters.Prompt, wamPlugin, provider, null) .ConfigureAwait(false); return(WamAdapters.CreateMsalResponseFromWamResponse( wamResult, wamPlugin, authenticationRequestParameters.AppConfig.ClientId, _logger, isInteractive: true)); } var wamAccount = await FindWamAccountForMsalAccountAsync( provider, wamPlugin, authenticationRequestParameters.Account, authenticationRequestParameters.LoginHint, authenticationRequestParameters.AppConfig.ClientId).ConfigureAwait(false); if (wamAccount != null) { var wamResult = await AcquireInteractiveWithWamAccountAsync( authenticationRequestParameters, acquireTokenInteractiveParameters.Prompt, wamPlugin, provider, wamAccount) .ConfigureAwait(false); return(WamAdapters.CreateMsalResponseFromWamResponse( wamResult, wamPlugin, authenticationRequestParameters.AppConfig.ClientId, _logger, isInteractive: true)); } else { if (IsAadOnlyAuthority(authenticationRequestParameters.Authority)) { return(await AcquireInteractiveWithAadBrowserAsync( authenticationRequestParameters, acquireTokenInteractiveParameters.Prompt).ConfigureAwait(false)); } } } return(await AcquireInteractiveWithPickerAsync( authenticationRequestParameters, acquireTokenInteractiveParameters.Prompt) .ConfigureAwait(false)); }
public Task <MsalTokenResponse> AcquireTokenInteractiveAsync(AuthenticationRequestParameters authenticationRequestParameters, AcquireTokenInteractiveParameters acquireTokenInteractiveParameters) { throw new NotImplementedException(); }
/// <summary> /// In WAM, AcquireTokenInteractive is always associated to an account. WAM also allows for an "account picker" to be displayed, /// which is similar to the EVO browser experience, allowing the user to add an account or use an existing one. /// /// MSAL does not have a concept of account picker so MSAL.AccquireTokenInteractive will: /// /// 1. Call WAM.AccountPicker if an IAccount (or possibly login_hint) is not configured /// 2. Figure out the WAM.AccountID associated to the MSAL.Account /// 3. Call WAM.AcquireTokenInteractive with the WAM.AccountID /// /// To make matters more complicated, WAM has 2 plugins - AAD and MSA. With AAD plugin, /// it is possible to list all WAM accounts and find the one associated to the MSAL account. /// However, MSA plugin does NOT allow listing of accounts, and the only way to figure out the /// WAM account ID is to use the account picker. This makes AcquireTokenSilent impossible for MSA, /// because we would not be able to map an Msal.Account to a WAM.Account. To overcome this, /// we save the WAM.AccountID in MSAL's cache. /// </summary> public async Task <MsalTokenResponse> AcquireTokenInteractiveAsync( AuthenticationRequestParameters authenticationRequestParameters, AcquireTokenInteractiveParameters acquireTokenInteractiveParameters) { if (_synchronizationContext == null) { throw new MsalClientException( MsalError.WamUiThread, "AcquireTokenInteractive with broker must be called from the UI thread when using WAM. " + "Note that console applications are not currently supported in conjuction with WAM." + ErrorMessageSuffix); } if (authenticationRequestParameters.Account != null || !string.IsNullOrEmpty(authenticationRequestParameters.LoginHint)) { bool isMsa = await IsMsaRequestAsync( authenticationRequestParameters.Authority, authenticationRequestParameters?.Account?.HomeAccountId?.TenantId, // TODO: we could furher optimize here by searching for an account based on UPN IsMsaPassthrough(authenticationRequestParameters)).ConfigureAwait(false); IWamPlugin wamPlugin = isMsa ? _msaPlugin : _aadPlugin; WebAccountProvider provider; provider = await GetProviderAsync(authenticationRequestParameters.Authority.AuthorityInfo.CanonicalAuthority, isMsa) .ConfigureAwait(false); if (PublicClientApplication.IsOperatingSystemAccount(authenticationRequestParameters.Account)) { var wamResult = await AcquireInteractiveWithoutPickerAsync( authenticationRequestParameters, acquireTokenInteractiveParameters.Prompt, wamPlugin, provider, null) .ConfigureAwait(false); return(CreateMsalTokenResponse(wamResult, wamPlugin, isInteractive: true)); } var wamAccount = await FindWamAccountForMsalAccountAsync( provider, wamPlugin, authenticationRequestParameters.Account, authenticationRequestParameters.LoginHint, authenticationRequestParameters.ClientId).ConfigureAwait(false); if (wamAccount != null) { var wamResult = await AcquireInteractiveWithoutPickerAsync( authenticationRequestParameters, acquireTokenInteractiveParameters.Prompt, wamPlugin, provider, wamAccount) .ConfigureAwait(false); return(CreateMsalTokenResponse(wamResult, wamPlugin, isInteractive: true)); } } return(await AcquireInteractiveWithPickerAsync( authenticationRequestParameters) .ConfigureAwait(false)); }
public void VerifyAuthorizationResultTest() { using (MockHttpAndServiceBundle harness = CreateTestHarness()) { MockInstanceDiscoveryAndOpenIdRequest(harness.HttpManager); MockWebUI webUi = new MockWebUI() { MockResult = AuthorizationResult.FromUri(TestConstants.AuthorityHomeTenant + "?error=" + OAuth2Error.LoginRequired), }; AuthenticationRequestParameters parameters = harness.CreateAuthenticationRequestParameters( TestConstants.AuthorityHomeTenant, TestConstants.s_scope, new TokenCache(harness.ServiceBundle, false), extraQueryParameters: new Dictionary <string, string> { { "extra", "qp" } }); parameters.RedirectUri = new Uri("some://uri"); parameters.LoginHint = TestConstants.DisplayableId; AcquireTokenInteractiveParameters interactiveParameters = new AcquireTokenInteractiveParameters { Prompt = Prompt.ForceLogin, ExtraScopesToConsent = TestConstants.s_scopeForAnotherResource.ToArray(), }; InteractiveRequest request = new InteractiveRequest( harness.ServiceBundle, parameters, interactiveParameters, webUi); try { request.ExecuteAsync(CancellationToken.None).Wait(); Assert.Fail("MsalException should have been thrown here"); } catch (Exception exc) { Assert.IsTrue(exc.InnerException is MsalUiRequiredException); Assert.AreEqual( MsalError.NoPromptFailedError, ((MsalUiRequiredException)exc.InnerException).ErrorCode); Assert.AreEqual( UiRequiredExceptionClassification.PromptNeverFailed, ((MsalUiRequiredException)exc.InnerException).Classification); } webUi = new MockWebUI { MockResult = AuthorizationResult.FromUri( TestConstants.AuthorityHomeTenant + "?error=invalid_request&error_description=some error description") }; request = new InteractiveRequest( harness.ServiceBundle, parameters, interactiveParameters, webUi); try { request.ExecuteAsync(CancellationToken.None).Wait(CancellationToken.None); Assert.Fail("MsalException should have been thrown here"); } catch (Exception exc) { Assert.IsTrue(exc.InnerException is MsalException); Assert.AreEqual("invalid_request", ((MsalException)exc.InnerException).ErrorCode); Assert.AreEqual("some error description", ((MsalException)exc.InnerException).Message); } } }
public void NoCacheLookup() { MyReceiver myReceiver = new MyReceiver(); using (MockHttpAndServiceBundle harness = CreateTestHarness(telemetryCallback: myReceiver.HandleTelemetryEvents)) { TokenCache cache = new TokenCache(harness.ServiceBundle, false); MsalAccessTokenCacheItem atItem = new MsalAccessTokenCacheItem( TestConstants.ProductionPrefNetworkEnvironment, TestConstants.ClientId, TestConstants.s_scope.AsSingleString(), TestConstants.Utid, null, new DateTimeOffset(DateTime.UtcNow + TimeSpan.FromSeconds(3599)), new DateTimeOffset(DateTime.UtcNow + TimeSpan.FromSeconds(7200)), MockHelpers.CreateClientInfo()); string atKey = atItem.GetKey().ToString(); atItem.Secret = atKey; ((ITokenCacheInternal)cache).Accessor.SaveAccessToken(atItem); MockWebUI ui = new MockWebUI() { MockResult = AuthorizationResult.FromUri(TestConstants.AuthorityHomeTenant + "?code=some-code") }; MockInstanceDiscoveryAndOpenIdRequest(harness.HttpManager); harness.HttpManager.AddSuccessTokenResponseMockHandlerForPost(TestConstants.AuthorityHomeTenant); AuthenticationRequestParameters parameters = harness.CreateAuthenticationRequestParameters( TestConstants.AuthorityHomeTenant, TestConstants.s_scope, cache, extraQueryParameters: new Dictionary <string, string> { { "extra", "qp" } }); parameters.RedirectUri = new Uri("some://uri"); parameters.LoginHint = TestConstants.DisplayableId; AcquireTokenInteractiveParameters interactiveParameters = new AcquireTokenInteractiveParameters { Prompt = Prompt.SelectAccount, ExtraScopesToConsent = TestConstants.s_scopeForAnotherResource.ToArray(), }; InteractiveRequest request = new InteractiveRequest( harness.ServiceBundle, parameters, interactiveParameters, ui); Task <AuthenticationResult> task = request.RunAsync(CancellationToken.None); task.Wait(); AuthenticationResult result = task.Result; Assert.IsNotNull(result); Assert.AreEqual(1, ((ITokenCacheInternal)cache).Accessor.GetAllRefreshTokens().Count()); Assert.AreEqual(2, ((ITokenCacheInternal)cache).Accessor.GetAllAccessTokens().Count()); Assert.AreEqual(result.AccessToken, "some-access-token"); Assert.IsNotNull( myReceiver.EventsReceived.Find( anEvent => // Expect finding such an event anEvent[EventBase.EventNameKey].EndsWith("ui_event") && anEvent[UiEvent.UserCancelledKey] == "false")); Assert.IsNotNull( myReceiver.EventsReceived.Find( anEvent => // Expect finding such an event anEvent[EventBase.EventNameKey].EndsWith("api_event") && anEvent[ApiEvent.PromptKey] == "select_account")); Assert.IsNotNull( myReceiver.EventsReceived.Find( anEvent => // Expect finding such an event anEvent[EventBase.EventNameKey].EndsWith("ui_event") && anEvent[UiEvent.AccessDeniedKey] == "false")); } }
public async Task VerifyAuthorizationResultTestAsync() { using (MockHttpAndServiceBundle harness = CreateTestHarness()) { MockInstanceDiscoveryAndOpenIdRequest(harness.HttpManager); MockWebUI webUi = new MockWebUI() { MockResult = AuthorizationResult.FromUri(TestConstants.AuthorityHomeTenant + "?error=" + OAuth2Error.LoginRequired), }; MsalMockHelpers.ConfigureMockWebUI(harness.ServiceBundle.PlatformProxy, webUi); AuthenticationRequestParameters parameters = harness.CreateAuthenticationRequestParameters( TestConstants.AuthorityHomeTenant, TestConstants.s_scope, new TokenCache(harness.ServiceBundle, false), extraQueryParameters: new Dictionary <string, string> { { "extra", "qp" } }); parameters.RedirectUri = new Uri("some://uri"); parameters.LoginHint = TestConstants.DisplayableId; AcquireTokenInteractiveParameters interactiveParameters = new AcquireTokenInteractiveParameters { Prompt = Prompt.ForceLogin, ExtraScopesToConsent = TestConstants.s_scopeForAnotherResource.ToArray(), }; InteractiveRequest request = new InteractiveRequest( parameters, interactiveParameters); var ex = await AssertException.TaskThrowsAsync <MsalUiRequiredException>( () => request.RunAsync()) .ConfigureAwait(false); Assert.AreEqual( MsalError.NoPromptFailedError, ex.ErrorCode); Assert.AreEqual( UiRequiredExceptionClassification.PromptNeverFailed, ex.Classification); webUi = new MockWebUI { MockResult = AuthorizationResult.FromUri( TestConstants.AuthorityHomeTenant + "?error=invalid_request&error_description=some error description") }; MsalMockHelpers.ConfigureMockWebUI(harness.ServiceBundle.PlatformProxy, webUi); request = new InteractiveRequest( parameters, interactiveParameters); var ex2 = await AssertException.TaskThrowsAsync <MsalServiceException>( () => request.RunAsync()) .ConfigureAwait(false); Assert.AreEqual("invalid_request", ex2.ErrorCode); Assert.AreEqual("some error description", ex2.Message); } }
public async Task WithMultiCloudSupportEnabledAsync(bool multiCloudSupportEnabled) { var expectedQueryParams = TestConstants.ExtraQueryParameters; var authorizationResultUri = TestConstants.AuthorityHomeTenant + "?code=some-code"; if (multiCloudSupportEnabled) { expectedQueryParams.Add("instance_aware", "true"); authorizationResultUri = authorizationResultUri + "&cloud_instance_name=microsoftonline.us&cloud_instance_host_name=login.microsoftonline.us"; } using (MockHttpAndServiceBundle harness = CreateTestHarness(isMultiCloudSupportEnabled: multiCloudSupportEnabled)) { var cache = new TokenCache(harness.ServiceBundle, false); var ui = new MockWebUI() { MockResult = AuthorizationResult.FromUri(authorizationResultUri), QueryParamsToValidate = expectedQueryParams }; MsalMockHelpers.ConfigureMockWebUI(harness.ServiceBundle, ui); MockInstanceDiscoveryAndOpenIdRequest(harness.HttpManager); var tokenResponseHandler = new MockHttpMessageHandler { ExpectedMethod = HttpMethod.Post, ExpectedQueryParams = expectedQueryParams, ExpectedPostData = new Dictionary <string, string>() { { OAuth2Parameter.Claims, TestConstants.Claims } }, ResponseMessage = MockHelpers.CreateSuccessTokenResponseMessage() }; harness.HttpManager.AddMockHandler(tokenResponseHandler); AuthenticationRequestParameters parameters = harness.CreateAuthenticationRequestParameters( TestConstants.AuthorityHomeTenant, TestConstants.s_scope, cache, extraQueryParameters: TestConstants.ExtraQueryParameters, claims: TestConstants.Claims); parameters.RedirectUri = new Uri("some://uri"); parameters.LoginHint = TestConstants.DisplayableId; AcquireTokenInteractiveParameters interactiveParameters = new AcquireTokenInteractiveParameters { Prompt = Prompt.SelectAccount, ExtraScopesToConsent = TestConstants.s_scopeForAnotherResource.ToArray(), }; var request = new InteractiveRequest( parameters, interactiveParameters); AuthenticationResult result = await request.RunAsync().ConfigureAwait(false); Assert.IsNotNull(result); if (multiCloudSupportEnabled) { Assert.AreEqual("https://login.microsoftonline.us/home/oauth2/v2.0/token", result.AuthenticationResultMetadata.TokenEndpoint); } else { Assert.AreEqual("https://login.microsoftonline.com/home/oauth2/v2.0/token", result.AuthenticationResultMetadata.TokenEndpoint); } Assert.AreEqual(1, ((ITokenCacheInternal)cache).Accessor.GetAllRefreshTokens().Count()); Assert.AreEqual(1, ((ITokenCacheInternal)cache).Accessor.GetAllAccessTokens().Count()); Assert.AreEqual(result.AccessToken, "some-access-token"); } }
public async Task NoCacheLookupAsync() { using (MockHttpAndServiceBundle harness = CreateTestHarness()) { TokenCache cache = new TokenCache(harness.ServiceBundle, false); string clientInfo = MockHelpers.CreateClientInfo(); string homeAccountId = ClientInfo.CreateFromJson(clientInfo).ToAccountIdentifier(); MsalAccessTokenCacheItem atItem = new MsalAccessTokenCacheItem( TestConstants.ProductionPrefNetworkEnvironment, TestConstants.ClientId, TestConstants.s_scope.AsSingleString(), TestConstants.Utid, null, new DateTimeOffset(DateTime.UtcNow), new DateTimeOffset(DateTime.UtcNow + TimeSpan.FromSeconds(3599)), new DateTimeOffset(DateTime.UtcNow + TimeSpan.FromSeconds(7200)), clientInfo, homeAccountId); string atKey = atItem.GetKey().ToString(); atItem.Secret = atKey; ((ITokenCacheInternal)cache).Accessor.SaveAccessToken(atItem); MockWebUI ui = new MockWebUI() { MockResult = AuthorizationResult.FromUri(TestConstants.AuthorityHomeTenant + "?code=some-code") }; MsalMockHelpers.ConfigureMockWebUI(harness.ServiceBundle, ui); MockInstanceDiscoveryAndOpenIdRequest(harness.HttpManager); harness.HttpManager.AddSuccessTokenResponseMockHandlerForPost(TestConstants.AuthorityHomeTenant); AuthenticationRequestParameters parameters = harness.CreateAuthenticationRequestParameters( TestConstants.AuthorityHomeTenant, TestConstants.s_scope, cache, extraQueryParameters: new Dictionary <string, string> { { "extra", "qp" } }); parameters.RedirectUri = new Uri("some://uri"); parameters.LoginHint = TestConstants.DisplayableId; AcquireTokenInteractiveParameters interactiveParameters = new AcquireTokenInteractiveParameters { Prompt = Prompt.SelectAccount, ExtraScopesToConsent = TestConstants.s_scopeForAnotherResource.ToArray(), }; InteractiveRequest request = new InteractiveRequest( parameters, interactiveParameters); AuthenticationResult result = await request.RunAsync().ConfigureAwait(false); Assert.AreEqual(1, ((ITokenCacheInternal)cache).Accessor.GetAllRefreshTokens().Count()); Assert.AreEqual(2, ((ITokenCacheInternal)cache).Accessor.GetAllAccessTokens().Count()); Assert.AreEqual(result.AccessToken, "some-access-token"); } }
/// <summary> /// In WAM, AcquireTokenInteractive is always associated to an account. WAM also allows for an "account picker" to be displayed, /// which is similar to the EVO browser experience, allowing the user to add an account or use an existing one. /// /// MSAL does not have a concept of account picker so MSAL.AccquireTokenInteractive will: /// /// 1. Call WAM.AccountPicker if an IAccount (or possibly login_hint) is not configured /// 2. Figure out the WAM.AccountID associated to the MSAL.Account /// 3. Call WAM.AcquireTokenInteractive with the WAM.AccountID /// /// To make matters more complicated, WAM has 2 plugins - AAD and MSA. With AAD plugin, /// it is possible to list all WAM accounts and find the one associated to the MSAL account. /// However, MSA plugin does NOT allow listing of accounts, and the only way to figure out the /// WAM account ID is to use the account picker. This makes AcquireTokenSilent impossible for MSA, /// because we would not be able to map an Msal.Account to a WAM.Account. To overcome this, /// we save the WAM.AccountID in MSAL's cache. /// </summary> public async Task <MsalTokenResponse> AcquireTokenInteractiveAsync( AuthenticationRequestParameters authenticationRequestParameters, AcquireTokenInteractiveParameters acquireTokenInteractiveParameters) { #if WINDOWS_APP if (_synchronizationContext == null) { throw new MsalClientException( MsalError.WamUiThread, "AcquireTokenInteractive with broker must be called from the UI thread when using WAM." + ErrorMessageSuffix); } #endif if (authenticationRequestParameters.Account != null || !string.IsNullOrEmpty(authenticationRequestParameters.LoginHint)) { _logger.Verbose("[WamBroker] AcquireTokenIntractive - account information provided. Trying to find a Windows account that matches."); bool isMsaPassthrough = _wamOptions.MsaPassthrough; bool isMsa = await IsMsaRequestAsync( authenticationRequestParameters.Authority, authenticationRequestParameters?.Account?.HomeAccountId?.TenantId, isMsaPassthrough).ConfigureAwait(false); IWamPlugin wamPlugin = isMsa ? _msaPlugin : _aadPlugin; WebAccountProvider provider = await GetProviderAsync( authenticationRequestParameters.Authority.TenantId, isMsa) .ConfigureAwait(false); if (PublicClientApplication.IsOperatingSystemAccount(authenticationRequestParameters.Account)) { var wamResult = await AcquireInteractiveWithWamAccountAsync( authenticationRequestParameters, acquireTokenInteractiveParameters.Prompt, wamPlugin, provider, null) .ConfigureAwait(false); return(WamAdapters.CreateMsalResponseFromWamResponse( wamResult, wamPlugin, authenticationRequestParameters.AppConfig.ClientId, _logger, isInteractive: true)); } var wamAccount = await FindWamAccountForMsalAccountAsync( provider, wamPlugin, authenticationRequestParameters.Account, authenticationRequestParameters.LoginHint, authenticationRequestParameters.AppConfig.ClientId).ConfigureAwait(false); if (wamAccount != null) { var wamResult = await AcquireInteractiveWithWamAccountAsync( authenticationRequestParameters, acquireTokenInteractiveParameters.Prompt, wamPlugin, provider, wamAccount) .ConfigureAwait(false); return(WamAdapters.CreateMsalResponseFromWamResponse( wamResult, wamPlugin, authenticationRequestParameters.AppConfig.ClientId, _logger, isInteractive: true)); } _logger.Verbose("[WamBroker] AcquireTokenIntractive - account information provided but no matching account was found "); } // no account information available, need an account picker if (CanSkipAccountPicker(authenticationRequestParameters.Authority)) { _logger.Verbose("[WamBroker] Using AAD plugin account picker"); return(await AcquireInteractiveWithAadBrowserAsync( authenticationRequestParameters, acquireTokenInteractiveParameters.Prompt).ConfigureAwait(false)); } _logger.Verbose("[WamBroker] Using Windows account picker (AccountsSettingsPane)"); return(await AcquireInteractiveWithPickerAsync( authenticationRequestParameters, acquireTokenInteractiveParameters.Prompt) .ConfigureAwait(false)); }