Reputation: 11187
I have a .Net Core 2 Web API project that is using JwtBearer Authentication. However, while this works in regards to Authenticating my user and respecting the [Authorize]
attribute on my controller, the User Identity and Claims are never populated. Is there something more I have to do to create ensure that a ClaimsIdentity is created for my authenticated user?
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
...
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = "https://myTenant.auth0.com";
options.Audience = "https://localhost:5001/api/v1";
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "myTenant.auth0.com",
ValidAudience = "https://localhost:5001/api/v1"
};
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, SystemModelBuilder modelBuilder)
{
...
app.UseHttpsRedirection();
app.UseAuthentication();
}
My token looks like this on jwt.ms:
{
"typ": "JWT",
"alg": "RS256",
"kid": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
.{
"profileData": {
"given_name": "Rodd",
"family_name": "Harris"
},
"iss": "https://myTenant.auth0.com/",
"sub": "auth0|37b5f5c54fdac",
"aud": [
"https://localhost:5050/api/v1/",
"https://myTenant.auth0.com/userinfo"
],
"iat": 1532628090,
"exp": 1532629290,
"azp": "2RdsNtKpUgh_wgB3NI6gxd-OAl",
"scope": "openid profile email app.client.read"
}.[Signature]
In my controller, I have something like this:
[ApiController]
[Route("api/v1/[controller]")]
[Authorize]
public class TestController : ControllerBase
{
[HttpGet("clients")]
public async Task<IActionResult> ClientsList()
{
//Debugger gets here -- user is authenticated
var user = HttpContext.User.Identity.Name; //Always null
var count = HttpContext.User.Claims.Count(); //Always 0
var allowed = HttpContext.User.IsAuthenticated; //Always true
var type = HttpContext.User.AuthenticationType; //AuthenticationTypes.Federated
...
}
What keeps the user's name and claims from being created?
Update
So I just realized I AM actually getting the claims mapped into HttpContext.User.Identity.Claims
. Also realized that my token doesn't have a name value to automagically map to the Identity. So, I guess my real question is, how do I override the custom mapping and do my own mapping of the token into an Identity?
Upvotes: 4
Views: 3571
Reputation: 11187
Thanks to the information here and here, I was able to figure out what was going on.
First, .Net apparently tries to automap from the token claims by looking for the claim identified by the key: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
. Of course, I didn't have this in my token -- so no default name mapping.
In fact, I realized I didn't have ANY name being passed in my token -- so I had to set up a Rule on Auth0 to include something to use as a name. (I did have a name in app_metadata, but I needed to flatten that out into separate values).
Once that was done, I simply needed to tell .Net to use a different key to find the name claim in the list of token claims. I did this in Startup.cs like so:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
...
//There is no magic to this string -- it is whatever claim key is being
//issued by the Auth Provider
NameClaimType = "https://myshcemadefinedkey/preferred_username"
}
}
With that in place, .Net began populating the User.Identity.Name value with the value associated with the token claim that had the corresponding key value.
Upvotes: 1
Reputation: 326
Maybe correct your Configure to get this :
app.UseIdentity();
app.UseJwtBearerAuthentication(new JwtBearerOptions()
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
TokenValidationParameters = new TokenValidationParameters()
{
ValidIssuer = _config["Tokens:Issuer"],
ValidAudience = _config["Tokens:Audience"],
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Tokens:Key"])),
ValidateLifetime = true
}
});
And be carefull to put this before your UseMvc();
Upvotes: 0