Skip to content

[Bug] Issue: App stuck on login (shows black screen) after token expiry on Azure AD for (Android) – error reported on Firebase analytics - MSAL User canceled authentication #5628

@Nandulucky

Description

@Nandulucky

Library version used

4.77.0

.NET version

.Net 8.0 framework
.Net MAUI

Scenario

PublicClient - mobile app

Is this a new or an existing app?

The app is in production, I haven't upgraded MSAL, but started seeing this issue

Issue description and reproduction steps

App is using in app browser for login and custom tabs on landing home page.
When the app is freshly installed, login works without any issues.
If the user opens the app daily, biometric authentication is prompted and works as expected.

However, after 5 days (when session is expired on Azure AD), the user session expires and opening app -

Biometric authentication is shown, post that
A white screen with loading indicator appears for ~2 seconds
After that, the app shows a black screen. It stays on black screen only after multiple attempts by trying Force close app then open / clear storage and then open.

The app becomes usable only after restarting the device.
Force closing the app or clearing app storage does not resolve the issue.

Reproduction Steps

Install the app freshly on an Android device
Login successfully
Open the app daily → biometric authentication works
Wait for 5 days(configured on Azure AD), so that login/token expires
Open the app again
Authenticate using biometrics - code used to fetch refresh token or Acquire token interactive -
Observe loading screen → black screen

Relevant code snippets

public async Task<bool> GetApiAccessToken()
{
    try
    {
        if (Common.Account == null)
        {
            var accounts = await _pca.GetAccountsAsync();
            Common.Account = accounts.FirstOrDefault();
        }

        var apiAuthResult = await _pca
            .AcquireTokenSilent(Configurations.APIScope, Common.Account)
            .ExecuteAsync();

        AppConstants.APIAccessToken = apiAuthResult.AccessToken;
        return true;
    }
    catch (MsalUiRequiredException)
    {
        try
        {
            var authResult = await AcquireTokenInteractive(Configurations.APIScope);
            AppConstants.APIAccessToken = authResult.AccessToken;
            return true;
        }
        catch (Exception ex2)
        {
            if (Common.MSAuthService != null && Common.DataService != null)
            {
                await Common.DataService.LogToAzureStorage(
                    Common.MSAuthService,
                    Common.LogException("GetApiAccessToken", ex2.Message, ex2.StackTrace));
            }

            CrashlyticsLogger.LogException("GetApiAccessToken", ex2);
            return false;
        }
    }
}


private Task<AuthenticationResult> AcquireTokenInteractive(string[] scopes)
{
    var tcs = new TaskCompletionSource<AuthenticationResult>();

    Device.BeginInvokeOnMainThread(async () =>
    {
        try
        {
            var authResult = await _pca
                .AcquireTokenInteractive(scopes)
                .WithParentActivityOrWindow(App.RootViewController)
                .WithUseEmbeddedWebView(true)
                .ExecuteAsync();

            tcs.TrySetResult(authResult);
        }
        catch (Exception ex)
        {
            if (Common.MSAuthService != null && Common.DataService != null)
            {
                await Common.DataService.LogToAzureStorage(
                    Common.MSAuthService,
                    Common.LogException("AcquireTokenInteractive", ex.Message, ex.StackTrace));
            }

            CrashlyticsLogger.LogException("AcquireTokenInteractive", ex);
            tcs.TrySetException(ex);
        }
    });

    return tcs.Task;
}

Expected behavior

When the token expires, the app should:
Either prompt the user to re-login and navigate to the login screen

Identity provider

No response

Regression

No response

Solution and workarounds

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions