MSAL authentication request not completing in Xamarin application

John McConnell 21 Reputation points
2020-05-28T15:56:43.153+00:00

I'm trying to get my feet wet with Xamarin and I'm having trouble adding in my organization's login. The screen shot below is as far as I can get attempting to login. When I click "Continue" the same page just loads again. Not really sure what's going on.

The image is the screen I'm stuck on.

I've added code that represents the app class and the code behind for the XAML page attempting to login, leaving out what I "think" is irrelvant.

Any suggestions?

8789-xamarin.png

App class...

public partial class App : Application  
    {  
        public static string AzureBackendUrl =  
            DeviceInfo.Platform == DevicePlatform.Android ? "http://10.0.2.2:5000" : "http://localhost:5000";  
        public static bool UseMockDataStore = true;  
        public static IPublicClientApplication PCA = null;  
        public static string ClientID = "CLIENT_ID";  
  
        public static string[] Scopes = { "User.Read" };  
        public static string Username = string.Empty;  
  
        public static object ParentWindow { get; set; }  
  
        public App()  
        {  
            InitializeComponent();  
  
            if (UseMockDataStore)  
                DependencyService.Register<MockDataStore>();  
            else  
                DependencyService.Register<AzureDataStore>();  
  
            PCA = PublicClientApplicationBuilder.Create(ClientID)  
                .WithRedirectUri($"msal{App.ClientID}://auth")  
                //.WithParentActivityOrWindow(() => App.ParentWindow)  
                .Build();  
  
  
            MainPage = new MSAL_Example();  
        }  
    }  

MSAL_Example class...

public partial class MSAL_Example : ContentPage  
{  
    public static string tenant_name = "MY_TENANT_NAME";   
  
    public MSAL_Example()  
    {  
        InitializeComponent();  
        App.ParentWindow = this;  
    }  
  
    public async Task SignOutAsync()  
    {  
        IEnumerable<IAccount> accounts = await App.PCA.GetAccountsAsync();  
  
        try  
        {  
            while (accounts.Any())  
            {  
                await App.PCA.RemoveAsync(accounts.FirstOrDefault());  
                accounts = await App.PCA.GetAccountsAsync();  
            }  
  
            slUser.IsVisible = false;  
            Device.BeginInvokeOnMainThread(() => { btnSignInSignOut.Text = "Sign in"; });  
  
        }  
        catch (Exception ex)  
        {  
            Debug.WriteLine("\tERROR {0}", ex.Message);  
        }  
    }  
  
    public async Task SignInAsync()  
    {  
        AuthenticationResult authResult = null;  
        IEnumerable<IAccount> accounts = await App.PCA.GetAccountsAsync();  
  
  
        // let's see if we have a user in our belly already  
        try  
        {  
            IAccount firstAccount = accounts.FirstOrDefault();  
            authResult = await App.PCA.AcquireTokenSilent(App.Scopes, firstAccount)  
                                  .ExecuteAsync();  
            await RefreshUserDataAsync(authResult.AccessToken).ConfigureAwait(false);  
            Device.BeginInvokeOnMainThread(() => { btnSignInSignOut.Text = "Sign out"; });  
        }  
        catch (MsalUiRequiredException ex)  
        {  
            try  
            {  
                authResult = await App.PCA.AcquireTokenInteractive(App.Scopes)  
                                          .WithParentActivityOrWindow(App.ParentWindow)  
                                          .WithAuthority("https://login.microsoftonline.com/" + tenant_name)  
                                          .ExecuteAsync();  
  
                await RefreshUserDataAsync(authResult.AccessToken);  
                Device.BeginInvokeOnMainThread(() => { btnSignInSignOut.Text = "Sign out"; });  
            }  
            catch (Exception ex2)  
            {  
                Debug.WriteLine("\tERROR {0}", ex2.Message);  
            }  
        }  
    }  
  
    public async Task RefreshUserDataAsync(string token)  
    {  
        //get data from API  
        HttpClient client = new HttpClient();  
        HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/me");  
        message.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", token);  
        HttpResponseMessage response = await client.SendAsync(message);  
        string responseString = await response.Content.ReadAsStringAsync();  
        if (response.IsSuccessStatusCode)  
        {  
            JObject user = JObject.Parse(responseString);  
  
            slUser.IsVisible = true;  
  
            Device.BeginInvokeOnMainThread(() =>  
            {  
  
                lblDisplayName.Text = user["displayName"].ToString();  
                lblGivenName.Text = user["givenName"].ToString();  
                lblId.Text = user["id"].ToString();  
                lblSurname.Text = user["surname"].ToString();  
                lblUserPrincipalName.Text = user["userPrincipalName"].ToString();  
  
                // just in case  
                btnSignInSignOut.Text = "Sign out";  
            });  
        }  
        else  
        {  
            await DisplayAlert("Something went wrong with the API call", responseString, "Dismiss");  
        }  
    }  
  
}  
Not Monitored
Not Monitored
Tag not monitored by Microsoft.
38,769 questions
0 comments No comments
{count} votes

Accepted answer
  1. Anonymous
    2020-05-28T15:58:14.267+00:00

    Xamarin is not supported here on QnA. I'd try asking for help in dedicated forums here.

    https://forums.xamarin.com/

    --please don't forget to Accept as answer if the reply is helpful--


    Regards, Dave Patrick ....
    Microsoft Certified Professional
    Microsoft MVP [Windows Server] Datacenter Management

    Disclaimer: This posting is provided "AS IS" with no warranties or guarantees, and confers no rights.

    0 comments No comments

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.