Can this workaround section be expanded please? This appears to be my exact issue but I don't understand how to rectify it.
⚠Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.
@RhomGit
Thanks for your feedback! We will investigate and update as appropriate.
Hi @RhomGit, it seems that the link currently specified in the Mitigation for "Missing from the token response" section is out of date:
The article that it _should_ point to is Tutorial: Create user flows in Azure Active Directory B2C, where step 8 in the Create a sign-up and sign-in user flow section says:
- For User attributes and claims, choose the claims and attributes that you want to collect and send from the user during sign-up. For example, select Show more, and then choose attributes and claims for Country/Region, Display Name, and Postal Code. Click OK.
In Application claims in your user flow, select Display Name:
This returns the name
claim in the ID token, which you can then use in the place of preferred_username
.
For example (from MainWindow.xaml.cs#L238):
private void DisplayUserInfo(AuthenticationResult authResult)
{
TokenInfoText.Text = "";
if (authResult != null)
{
JObject user = ParseIdToken(authResult.IdToken);
TokenInfoText.Text += $"Name: {user["name"]?.ToString()}" + Environment.NewLine;
}
}
Please review Tutorial: Create user flows in Azure Active Directory B2C and let us know if that helps. I'll update this article with the new link, as well.
Cc: @jmprieur @jennyf19
Hi @RhomGit, an update to this article has been merged and should be live sometime after 0300 Pacific time.
Hi, great to hear that this has been fixed, it was a touch confusing. That being said I had got this far myself. I already have Display Name checked and returning, what I was hoping to resolve is this:
This is when calling:
var accounts = await pca.GetAccountsAsync();
var firstAccount = accounts.FirstOrDefault();
authResult = await pca.AcquireTokenInteractive(AuthB2C.scopes)
.WithUseEmbeddedWebView(true)
.WithAccount(firstAccount)
.WithParentActivityOrWindow(parentActivity)
.WithPrompt(Prompt.SelectAccount)
.ExecuteAsync();
on a device that hasn't run the app in a while. I presume the token is expired and the webview is trying to repopulate the window with the previous account name (which would be great).
@RhomGit so this is coming from MSAL and the cache. B2C does not return a preferred_username, so we have no value to display there for B2C. And the webview is outside of the control of MSAL, it's presented by AAD B2C.
The way around this is to not send the account w/the request, as that's prepopulating the user name that you don't want, because that's the replacement username MSAL is using.
But, you can send in .WithLoginHint()
and pass in any value that you parsed from the id_token (this only works if there is a token in the cache).
Your code above would be:
string email;
authResult = await pca.AcquireTokenInteractive(AuthB2C.scopes)
.WithUseEmbeddedWebView(true)
.WithLoginHint(email)
.WithParentActivityOrWindow(parentActivity)
.ExecuteAsync();
I got the email value when i parsed the id_token from the initial sign-in, and now it displays in the box, as you can see above.
Does that unblock you?
I'm not sure if LoginHint will work with non-AAD B2C accounts (ex. facebook, google), but if you are using system browser, it works really nice with the other IdPs as the user will sign in automatically if they have already signed in on their browser.
Hope this helps.
Thanks @jennyf19 that explained it perfectly.
I have done as you suggested and it worked, exactly what I was hoping for!
This was very painful. I'm using Azure AD B2C with a local account and I was also getting the "missing from the token response" -- and I had the "Display Name" as a claim. It would be helpful to change the documentation to use the solution you have provided here. I'm thankful to have found it.
Now, is there any way to put the email--or any other claim--into the cache being used by MSAL?
@lorne-olo Thanks for the feedback and apologies for the difficulties in finding the solution. It is not very well documented. will work on getting this fixed. thanks
From @lorne-olo
Now, is there any way to put the email--or any other claim--into the cache being used by MSAL?
Yes, this is the bit that is not covered I believe - would be great if the IAccount that goes into the token cache could be extended to include other claims.
My (not pretty) workaround down @mmacy 's recommendation: context is B2C in a WPF application using an MsalAuthHelper and TokenCacheHelper. After sign in, I silently pull another token, simply to get those other attributes (like the user name or the email).
//using System.IdentityModel.Tokens.Jwt;
var handler = new JwtSecurityTokenHandler();
var tokenContent = (JwtSecurityToken)handler.ReadToken(await GetTokenAsync());
var email = tokenContent.Claims.FirstOrDefault(x => x.Type == "emails")?.Value;
var name = tokenContent.Claims.FirstOrDefault(x => x.Type == "name")?.Value;
Most helpful comment
Hi @RhomGit, it seems that the link currently specified in the Mitigation for "Missing from the token response" section is out of date:
The article that it _should_ point to is Tutorial: Create user flows in Azure Active Directory B2C, where step 8 in the Create a sign-up and sign-in user flow section says:
In Application claims in your user flow, select Display Name:
This returns the
name
claim in the ID token, which you can then use in the place ofpreferred_username
.For example (from MainWindow.xaml.cs#L238):
Please review Tutorial: Create user flows in Azure Active Directory B2C and let us know if that helps. I'll update this article with the new link, as well.
Cc: @jmprieur @jennyf19