microsoft-authentication-library-for-dotnet: [Bug] Edit Profile is asking user to log in

Which Version of MSAL are you using ? Microsoft.Identity.Client 4.18.0

Platform .NET Standard 2.0, .NET Framework 4.6.1, WPF

What authentication flow has the issue?

  • Desktop / Mobile
    • Interactive B2C

Is this a new or existing app? The app is in production but updated MSAL version and changed areas of code and are now re-testing.

Repro

var ar = await pca.AcquireTokenInteractive(this.scopes)
    .WithAccount(account)
    .WithB2CAuthority(AuthB2C.AuthorityEditProfile)
    .WithParentActivityOrWindow(parentActivity)
    .WithPrompt(Prompt.NoPrompt)
    .ExecuteAsync();

Expected behavior If the existing token has been acquired silently then the Window should go directly to the Edit Profile section.

Actual behavior If the existing token has been acquired silently then the UI asks for user to authenticate before proceeding to the Edit Profile section. Note: it works correctly if the current token has been retrieved via AcquireTokenInteractive (i.e. does not ask the user to authenticate).

Additional context/ Logs / Screenshots Previous similar issue: https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/505

image

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 21 (1 by maintainers)

Most upvoted comments

@Coder-RKV you can open a new issue w/exactly what the issue is & provide a repro. thanks.

@RhomGit not a waste of time at all. we recently did work in a related area, so it was good to triple check we didn’t have any issues there. I really appreciate the repro and quick responses from you. very helpful. if anything else comes up, let us know.

Also, @jmprieur and I realized this is not very well documented, not from us, nor B2C, so something we can improve for sure.

There was no sign out function and silent failure wasn’t handled nicely so I have pushed an update.

So the steps for repro would be:

  • Create Auth object
  • Interactive sign in (using your own B2C values)
  • Edit Profile (should work)
  • Close and reopen the App
  • Create Auth object
  • Silently sign in
  • Edit Profile (should require additional authentication)

Hi Jenny, I have quickly thrown together a repro here: https://github.com/RhomGit/MSALDesktopRepro Its really rough, sorry.

The buttons on the right, click in this order: Create Auth, Silent and then Edit Profile. image

Hi Jenny,

the original code used a Helpers class for “GetAccountByPolicy”. Please find it all below:

    public static class Helpers
    { 
        public static IAccount GetAccountByPolicy(IEnumerable<IAccount> accounts, string policy)
        {
            foreach (var account in accounts)
            {
                string userIdentifier = account.HomeAccountId.ObjectId.Split('.')[0];
                if (userIdentifier.EndsWith(policy.ToLower())) return account;
            }

            return null;
        }
        public static JObject ParseIdToken(string idToken)
        {
            // Get the piece with actual user info
            idToken = idToken.Split('.')[1];
            idToken = Base64UrlDecode(idToken);
            return JObject.Parse(idToken);
        }
        public static string Base64UrlDecode(string s)
        {
            s = s.Replace('-', '+').Replace('_', '/');
            s = s.PadRight(s.Length + (4 - s.Length % 4) % 4, '=');
            var byteArray = Convert.FromBase64String(s);
            var decoded = Encoding.UTF8.GetString(byteArray, 0, byteArray.Count());
            return decoded;
        }
    }
        public async Task EditProfile()
        {   
            try
            {
                // var accounts = await pca.GetAccountsAsync(AuthB2C.PolicyEditProfile);
                // var account = accounts.FirstOrDefault();

                var accounts = await pca.GetAccountsAsync();
                var account = Helpers.GetAccountByPolicy(accounts, AuthB2C.PolicyEditProfile);
                
                var ar = await pca.AcquireTokenInteractive(this.scopes)
                    .WithAccount(account)
                    .WithB2CAuthority(AuthB2C.AuthorityEditProfile)
                    .WithParentActivityOrWindow(parentActivity)
                    .WithPrompt(Prompt.NoPrompt)
                    .ExecuteAsync();
            }
            catch (Exception ex)
            {
                // Alert if any exception excluding user cancelling sign-in dialog
                if (((ex as MsalException)?.ErrorCode != "authentication_canceled"))
                    throw ex;
            }
        }


            var accounts = await pca.GetAccountsAsync();
            var firstAccount = accounts.FirstOrDefault();
           
            try
            {
                if (isSilent)
                {
                    authResult = await pca.AcquireTokenSilent(this.scopes, firstAccount).ExecuteAsync(); 
                }
                else
                {
                    await SignOut();

                    authResult = await pca.AcquireTokenInteractive(this.scopes)
                        .WithUseEmbeddedWebView(true)
                        .WithLoginHint(previousSignInName)
                        .WithParentActivityOrWindow(parentActivity)
                        .WithPrompt(Prompt.SelectAccount)
                        .ExecuteAsync();
                }
            }
            catch (MsalUiRequiredException exMsal)
            {
                throw exMsal;
            }
            catch (Microsoft.Identity.Client.MsalServiceException exMsal2)
            {
                if (exMsal2.Message.Contains("AADB2C90118") == true) //The user has forgotten their password.
                    await ResetPassword();
                else if (exMsal2.Message.Contains("AADB2C90091") == true) //The user has cancelled entering self-asserted information.
                    return false;
                else
                    throw exMsal2;
            }
            catch (Microsoft.Identity.Client.MsalClientException exMsal3)
            {
                // just cancelled, ignore?
                return false;
            }
            catch (Exception ex)
            {
                throw ex;
            }