Search code examples
c#xamarinxamarin.formsoffice365api

How to store authenticated state through Office365 API in Xamarin.forms


I'm new to Xamarin and using the Office365 API. I'm attempting to learn through creating a Xamarin.Forms application that reads data from the Office365 server once the user is authenticated.

I've been following a tutorial and ended up with the following login page

namespace CMLender.Pages
{
    public partial class Login
    {
        public IPlatformParameters PlatformParameters { get; set; }
        public Login()
        {
            InitializeComponent();
            LoginButton.Clicked += LoginButton_Clicked;
        }
        protected override void OnAppearing()
        {
            App.ClientApplication.PlatformParameters = PlatformParameters;
            base.OnAppearing();
        }
        private async void LoginButton_Clicked(object sender, EventArgs e)
        {
            try
            {
                AuthenticationResult ar = await App.ClientApplication.AcquireTokenAsync(App.Scopes);
            }
            catch (MsalException ex)
            {
                WelcomeText.Text = ex.Message;
            }
            finally
            {
                await Navigation.PushAsync(new MainTab());
            }
        }
    }
}

Once a user clicks on the login button they are taken through to the Office365 user authentication page. Once they have logged in with a valid username and password, the application then loads the MainTab XAML page.

Now this is where my problem starts. My MainTab page looks like this:

namespace CMLender.Pages
{

    public partial class MainTab : ContentPage
    {
        public MainTab()
        {
            InitializeComponent();
            DisplayMessage();
        }
        private async void DisplayMessage()
        {
            try
            {
                AuthenticationResult ar = await App.ClientApplication.AcquireTokenAsync(App.Scopes);
                WelcomeText.Text = $"Welcome {ar.User.Name}";
            }
            catch (MsalException ex)
            {
                WelcomeText.Text = ex.Message;
            }
            finally
            {
                WelcomeTextTwo.Text = "BlaBlaBlab";
            }
        }

    }
}

I wanted this page to write the logged in users name to a label (which it does) but first the user has to re-authenticate.

I'm pretty sure it's down to the AcquireTokenAsync task but it's the only way I can get it to work. How can I store the information that the user is already authenticated and access their user name?

I've done all the reading I can but the information just seems so far and wide on the subject.


Solution

  • For the most simplistic impllementation you can create a public static property in you App.cs or App.xaml.cs like :

    public static AuthenticationResult LoggedInUser { get; set; }
    

    In your login page add this to your login button click event :

    private async void LoginButton_Clicked(object sender, EventArgs e)
    {
           try
           {
                AuthenticationResult ar = await App.ClientApplication.AcquireTokenAsync(App.Scopes);
                App.LoggedInUser = ar;
           }
           catch (MsalException ex)
           {
                WelcomeText.Text = ex.Message;
           }
           finally
           {
                await Navigation.PushAsync(new MainTab());
           }
     }
    

    And in you main page, get the data from the static property instead of calling the API again :

            private async void DisplayMessage()
            {
                try
                {                    
                    WelcomeText.Text = $"Welcome {App.LoggedInUser.User.Name}";
                }
                catch (MsalException ex)
                {
                    WelcomeText.Text = ex.Message;
                }
                finally
                {
                    WelcomeTextTwo.Text = "BlaBlaBlab";
                }
            }
    

    Also, in your login method, It does not seem right to show the main page in finally because even if an exception occurs finally would get executed. I suggest you to move await Navigation.PushAsync(new MainTab()); to try and show exception to user in catch.