'In ASPNET 6 running on Azure App Services, User.Identity.Name is null because the claim uses the wrong name
After migrating a Blazor Server App project from dotnet 5 to dotnet 6, I'm encountering a weird problem with authentication.
The app is using local username and password for authentication.
In ConfigureServices(), we have
services.AddDefaultIdentity<IdentityUser>
(options =>
{
options.SignIn.RequireConfirmedAccount = true;
// attempt to force name claim to "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
options.ClaimsIdentity.UserNameClaimType = System.Security.Claims.ClaimTypes.Name;
})
.AddRoles<IdentityRole>()
.AddUserManager<UserManager<IdentityUser>>()
.AddRoleManager<AspNetRoleManager<IdentityRole>>()
.AddEntityFrameworkStores<ApplicationDbContext>();
Now, this has been working fine in .net 5, both in the dev environment, and also in Azure App Services (windows / iis )
After upgrading to .net 6, the following is observed:
- Dev environment (launched using "Project" ): Everything works as before (including authentication)
- Prod environment (Azure App Service) : Authentication is broken. When someone logs in, 'Identity.IsAuthenticated' is true, but 'Identity.Name' is null.
I traced the problem to the following:
- in Dev, the claims are as follows:
2022-05-17 12:46:54.190 +12:00 [INF] Claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier = 7f041757-3aad-4221-971a-729598c1d81e
2022-05-17 12:46:54.190 +12:00 [INF] Claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name = superadmin@local
2022-05-17 12:46:54.190 +12:00 [INF] Claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress = [email protected]
2022-05-17 12:46:54.190 +12:00 [INF] Claim AspNet.Identity.SecurityStamp = OJLEYFWG4JE4ND5NRPTRT4JVCVEE2ANR
2022-05-17 12:46:54.191 +12:00 [INF] Claim http://schemas.microsoft.com/ws/2008/06/identity/claims/role = SuperAdmin
2022-05-17 12:46:54.191 +12:00 [INF] Claim amr = pwd
But in Prod (Azure App services), the claims are as follows
2022-05-17 01:16:12.467 +00:00 [INF] Claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier = 7f041757-3aad-4221-971a-729598c1d81e
2022-05-17 01:16:12.468 +00:00 [INF] **Claim name = superadmin@local**
2022-05-17 01:16:12.471 +00:00 [INF] Claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress = [email protected]
2022-05-17 01:16:12.472 +00:00 [INF] Claim AspNet.Identity.SecurityStamp = OJLEYFWG4JE4ND5NRPTRT4JVCVEE2ANR
2022-05-17 01:16:12.473 +00:00 [INF] Claim http://schemas.microsoft.com/ws/2008/06/identity/claims/role = SuperAdmin
2022-05-17 01:16:12.475 +00:00 [INF] Claim http://schemas.microsoft.com/claims/authnmethodsreferences = pwd
2022-05-17 01:16:12.477 +00:00 [INF] Claim nameid = 7f041757-3aad-4221-971a-729598c1d81e
2022-05-17 01:16:12.478 +00:00 [INF] Claim email = [email protected]
2022-05-17 01:16:12.480 +00:00 [INF] Claim role = SuperAdmin
2022-05-17 01:16:12.481 +00:00 [INF] Claim amr = pwd
The claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name is MISSING. Instead we can see the claim called name holding the username value.
I tried to force the app to use the correct claim name
options.ClaimsIdentity.UserNameClaimType = System.Security.Claims.ClaimTypes.Name;
but that didn't work. Its still using the wrong name.
Pretty sure it is a simple configuration missing somewhere - if someone can point it out?
UPDATE 1
I updated the code as follows
if (IsProduction)
{
options.ClaimsIdentity.UserNameClaimType = 'name';
}
This actually worked and allowed the user to log in. Identity.IsAuthenticated == true and Identity.Name != null. Hooray! ... But.. why??
Also, the following works in DEV on ASPNET 6 :
[Inject]
IHttpContextAccessor HCA { get; set; }
if (HCA?.HttpContext?.User?.Claims?.Any() == true)
{
foreach (var claim in HCA.HttpContext.User.Claims)
{
Logger.Log("HCA Type = {t} Value = {v}", claim.Type, claim.Value);
}
}
But in Prod, on Azure App Services, the check HCA?.HttpContext?.User?.Claims?.Any() == true FAILS. Meaning that there are no claims in HttpContext. How is that possible???
ALSO
I installed the ASP.NET core 6.0 (x64) Extension to Azure Web App. It installed fine, but did not make a difference to authentication error.
UPDATE 2
I found the source of the problem, but not the solution, yet. It turns out that Azure Signal R is messing things up.
In Startup.cs I have this code:
if (IsProduction)
{
services.AddSignalR().AddAzureSignalR(options =>
{
options.ServerStickyMode = Microsoft.Azure.SignalR.ServerStickyMode.Required;
});
}
If I remove this, then the claims go back to normal, meaning:
- Name claim is now
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name - HttpContext works again
But of course I lose Azure SignalR which is no good.
What is even weirder is this: I created a fresh ASPNET 6 Blazor Server App project using the "Local Authentication" template, and deployed that to Azure App Services. Now, the claims behaviour is slightly different:
- Name claim is correct
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name - A new claim called
unique_nameis added to the ClaimsPrincipal - HttpContext is broken.
| State | Name Claim | HttpContext |
|---|---|---|
| Upgraded ASPNET 5 Project; No Azure Signal R | OK | Working |
| Upgraded ASPNET 5 Project; with Azure Signal R | Broken | Broken |
| Fresh ASPNET 6 Project; with Azure Signal R | Working | Broken |
So, the upshot is: Azure SignalR is definitely screwing up authentication for me. But why? And how do I fix it?
Update 3
So, it turns out that the version of System.IdentityModel.Tokens.Jwt matters when using Azure Signal R.
In the experiments above,
- the upgraded NET5>NET6 project was using System.IdentityModel.Tokens.Jwt 6.10.0.20330 (name claim wrong, unique_name claim missing)
- the Fresh NET 6 project was using System.IdentityModel.Tokens.Jwt 6.8.0.11012 (a lower version - strangely enough) (name claim OK, unique_name claim exists)
To fix my problem, I simply upgraded to the latest System.IdentityModel.Tokens.Jwt 6.18 and now authentication for my upgraded NET5 project works again.
To understand more, see the github issue
PS. Kudos to the Azure SignalR team for pointing me in the right direction
Solution 1:[1]
Thank you @Clueless.PS1 for your question about , User.Identity.Name is null because the claim uses the wrong name while upgrading .NET 5 to .NET6. It will surely be a valuable addition to the SO community. For the same purpose as you have stated posting your comment as an answer as it will be easier for other people with same issue to find it.
Workaround:-
When upgrading .NET5 to .NET6 project was using System.IdentityModel.Tokens.Jwt 6.10.0.20330 (name claim wrong, unique_name claim missing).
To resolve this upgrade to the latest version of System.IdentityModel.Tokens.Jwt 6.18 and then authentication for your upgraded .NET5 project will works again.
P.S:- As version 6.10 does not work properly with Azure Signal R.
For more information please refer this MICROSOFT DOCUMENTATION & GitHub issue
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
