2

I am working in Xamarin forms application.

I am using below code snippet to get token for AAD sign-in.

 IEnumerable<IAccount> accounts = await App.PCA.GetAccountsAsync().ConfigureAwait(false);
            try
            {
                if (btnSignInSignOut.Text == "Sign in")
                {
                    try
                    {
                        IAccount firstAccount = accounts.FirstOrDefault();
                        authResult = await App.PCA.AcquireTokenSilent(App.Scopes, firstAccount)
                                              .ExecuteAsync()
                                              .ConfigureAwait(false);
                    }
                    catch (MsalUiRequiredException)
                    {
                        try
                        { 
                            var builder = App.PCA.AcquireTokenInteractive(App.Scopes)
                                                                       .WithParentActivityOrWindow(App.ParentWindow);

                            if (Device.RuntimePlatform != "UWP")
                            {
                                // on Android and iOS, prefer to use the system browser, which does not exist on UWP
                                SystemWebViewOptions systemWebViewOptions = new SystemWebViewOptions()
                                {                            
                                    iOSHidePrivacyPrompt = true,
                                };

                                builder.WithSystemWebViewOptions(systemWebViewOptions);
                                builder.WithUseEmbeddedWebView(false);
                            }

                            authResult = await builder.ExecuteAsync().ConfigureAwait(false);
                        }
                        catch (Exception ex2)
                        {
                            await DisplayAlert("Acquire token interactive failed. See exception message for details: ", ex2.Message, "Dismiss");
                        }
                    }

                    if (authResult != null)
                    {
                        var content = await GetHttpContentWithTokenAsync(authResult.AccessToken);
                        UpdateUserContent(content);
                    }
                }
                else
                {
                    while (accounts.Any())
                    {
                        await App.PCA.RemoveAsync(accounts.FirstOrDefault()).ConfigureAwait(false);
                        accounts = await App.PCA.GetAccountsAsync().ConfigureAwait(false);
                    }

                    
                    Device.BeginInvokeOnMainThread(() => 
                    {
                        slUser.IsVisible = false;
                        btnSignInSignOut.Text = "Sign in"; 
                    });
                }
            }
            catch (Exception ex)
            {
                await DisplayAlert("Authentication failed. See exception message for details: ", ex.Message, "Dismiss");
            }

But after some time, token expires somehow and not refresh. Due to that it always redirect user to MS login page.

My requirement is, It should automatically take the logged in user's details.

You can take reference from this code.

I have also check other options like to directly call api to get refresh token but didn't found anything helpful.

Let me know if anyone have any idea about it.

Thanks in Advance.

Heli
  • 31
  • 1

2 Answers2

1

Just for clarification, MSAL does not return, issue the token, and does not expire the token. When your token expireS then MSAL will automatically refresh your token when calling the AcquireTokenSilentAsync (so you don't have to refresh your token). The reason why your application is redirecting to the login page is because when you call the authenticated API then this API is returning the response 401 (Unauthorized) which means while calling the API you are not sending the token with the request. In return when the server returns 401 (Unauthorized) response, then your application is redirecting the user to the login page.

Read more about MSAL token expiration here.

Update your code accordingly:

await SecureStorage.SetAsync("accessToken", authResult.AccessToken);

Rutha
  • 751
  • 3
  • 7
  • I used same code from https://github.com/Azure-Samples/active-directory-xamarin-native-v2. – Heli Sep 14 '21 at 04:49
  • I checked with this link but in my case sometimes it expires in only 5 mins. I am not understanding what went wrong. If you have any working code then can you please share me? Thanks – Heli Sep 27 '21 at 06:17
  • 1
    Configure the MSAL token lifetime because configuration of MSAL token lifetime only applies to Mobile and desktop applications but does not apply to Web browsers. In this case you must configure the token lifecycle. https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/token-lifetimes.md https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-configurable-token-lifetimes – Rutha Sep 27 '21 at 21:45
  • Thanks for your input but I am using xamarin forms and dont want to show popup/redirect on app. So can we do something from background side? So that user no need to login again and we can directly get current logged in user from browser? – Heli Sep 29 '21 at 11:48
  • You can add this from the background so that the user does not have to login from the browser. For storing the token: await SecureStorage.SetAsync("token", newToken); For getting the token: await SecureStorage.GetAsync("token"); For removing the token: SecureStorage.Remove("token"); https://learn.microsoft.com/en-us/xamarin/essentials/secure-storage?tabs=android – Rutha Sep 29 '21 at 15:47
  • If this technique does not work for you, use user Application properties. Application.Current.Properties["token"] = token More info here: https://learn.microsoft.com/en-us/dotnet/api/xamarin.forms.application.properties?view=xamarin-forms – Rutha Sep 29 '21 at 15:48
1

For now, MSAL already caches your authorization and can log you in silently if it’s still valid. So, as a user, you don’t need to sign in every time you use the app.

You could use SecureStorage.SetAsync to store the access token.

Sign-in:

public async Task<bool> SignInAsync()
{
 try
 {
     var accounts = await _pca.GetAccountsAsync();
    var firstAccount = accounts.FirstOrDefault();
    var authResult = await _pca.AcquireTokenSilent(Scopes, firstAccount).ExecuteAsync();

    // Store the access token securely for later use.
    await SecureStorage.SetAsync("AccessToken", authResult?.AccessToken);

    return true;
 }
 catch (MsalUiRequiredException)
 {
    try
    {
        // This means we need to login again through the MSAL window.
        var authResult = await _pca.AcquireTokenInteractive(Scopes)
                                    .WithParentActivityOrWindow(ParentWindow)
                                    .ExecuteAsync();

        // Store the access token securely for later use.
        await SecureStorage.SetAsync("AccessToken", authResult?.AccessToken);

        return true;
    }
    catch (Exception ex2)
    {
        Debug.WriteLine(ex2.ToString());
        return false;
    }
 }
 catch (Exception ex)
 {
    Debug.WriteLine(ex.ToString());
    return false;
 }
 }
Wendy Zang - MSFT
  • 10,509
  • 1
  • 7
  • 17
  • Zang I tried this but it still behave same. After 2-3 minutes it again starts showing MS login page. – Heli Sep 27 '21 at 05:54