I have a React SPA that communicates with the backend API (Azure Function App). I've created an app registration for both the SPA and the Azure Function App following the steps outlined here. Both app registrations are hosted in a separate directory from the Azure Function app since I'm using AD B2C. I'm able to successfully authenticate the user and make requests to the backend. I'm using PKCE as the auth protocol and MSAL.js to manage the authentication flow.
I've configured a standard signup/signin policy for which I'm using Local Account as the Identity provider and username as the user id.
Here's what the login screen looks like:

Here's the relevant code from the SPA which handles auth:
const { instance, accounts, inProgress,} = useMsal();
if (accounts.length > 0) {
msalInstance
.acquireTokenSilent({
account: accounts[0],
scopes: [
"https://APP_URI/user_impersonation",
],
})
.then((token) => {
console.log("token res is", token);
console.log("access token is", token);
})
.catch((err) => {
console.log("err is", err);
});
Here's the return value from calling acquireTokenSilent:
{
"authority":"https://APP_NAMEb2c.b2clogin.com/APP_NAMEb2c.onmicrosoft.com/b2c_1_flow/",
"uniqueId":"581776f4-6e16-454a-a6ae-ecb49f7f04aa",
"tenantId":"",
"scopes":[
"https://APP_NAMEb2c.onmicrosoft.com/reg_api/user_impersonation"
],
"account":{
"homeAccountId":"581776f4-6e16-454a-a6ae-ecb49f7f04aa-b2c_1_flow.07232d62-7285-4737-97eb-87f0f9b7c38e",
"environment":"APP_NAMEb2c.b2clogin.com",
"tenantId":"",
"username":"testUser@gmail.com",
"localAccountId":"581776f4-6e16-454a-a6ae-ecb49f7f04aa",
"name":"unknown",
"idTokenClaims":{
"exp":1663191498,
"nbf":1663187898,
"ver":"1.0",
"iss":"https://APP_NAMEb2c.b2clogin.com/07232d62-7285-4737-97eb-87f0f9b7c38e/v2.0/",
"sub":"581776f4-6e16-454a-a6ae-ecb49f7f04aa",
"aud":"473fe4d9-260b-46ad-9ad1-f4c4a4f211e6",
"nonce":"65c7ec69-2837-4bdf-b9e3-ae38dbb19c48",
"iat":1663187898,
"auth_time":1663187896,
"name":"unknown",
"emails":[
"testUser@gmail.com"
],
"tfp":"B2C_1_flow",
"at_hash":"qOHPceVj3fEhGGlRq6xh4g"
}
},
"idToken":"TD_TOKEN",
"idTokenClaims":{
"exp":1663191498,
"nbf":1663187898,
"ver":"1.0",
"iss":"https://APP_NAMEb2c.b2clogin.com/07232d62-7285-4737-97eb-87f0f9b7c38e/v2.0/",
"sub":"581776f4-6e16-454a-a6ae-ecb49f7f04aa",
"aud":"473fe4d9-260b-46ad-9ad1-f4c4a4f211e6",
"nonce":"65c7ec69-2837-4bdf-b9e3-ae38dbb19c48",
"iat":1663187898,
"auth_time":1663187896,
"name":"unknown",
"emails":[
"testUser@gmail.com"
],
"tfp":"B2C_1_flow",
"at_hash":"qOHPceVj3fEhGGlRq6xh4g"
},
"accessToken":"ACCESS_TOKEN",
"fromCache":true,
"expiresOn":"2022-09-14T21:38:18.000Z",
"correlationId":"9c71acbb-7ed4-4beb-a282-71ec7d924bd8",
"extExpiresOn":"2022-09-14T21:38:18.000Z",
"familyId":"",
"tokenType":"Bearer",
"state":"",
"cloudGraphHostName":"",
"msGraphHost":"",
"fromNativeBroker":false
}
As you can see, the username property has the emailAddress as it's value and not the actual username.
I've not been able to find concrete guidance on how to get the username. The one resource I found said that UserPrincipleName(UPN) is an optional claim and to add this value in the authToken I should add UPN as an optional claim in the token configuration tab, which is not available in B2C AD. I would love to get some guidance on what I'm doing wrong as getting the username should not be this hard, right ?
Edit 1: I can confirm that the username has been set; in the image below the username is denoted by User Principle Name:
