UseJwtBearerAuthentication does not get User.Identity.Name populated

11,060

Solution 1

in your claims (second code snippet) I can only see this:

new Claim(ClaimTypes.NameIdentifier, applicationUser.UserName),

but you need to add this:

new Claim(ClaimTypes.Name, applicationUser.UserName),

then User.Identity.Name should contain the username.

Solution 2

Another option is to set the namespace for the JwtRegisteredClaimNames.Sub in the tokenValidationParameters. This will let you continue to use the standard:

var tokenValidationParameters = new TokenValidationParameters
{
    // Ensure that User.Identity.Name is set correctly after login
    NameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",

    ... existing code ...
}

Update: Diogo Barros left a comment on my blog about this topic:

"Hello,

Thank you for your help. This worked for me. For more consistency and safety, you can use the ClaimTypes.NameIdentifier (in the System.Security.Claims namespace), instead of the hardcoded string."

I've changed our code to use the built-in ClaimTypes enumeration as it is a bit more elegant than using the namespace string.

Solution 3

Adding app.UseAuthentication(); to

public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 

fixed my issue.

Share:
11,060

Related videos on Youtube

Afshar Mohebi
Author by

Afshar Mohebi

I am Afshar Mohebi, a software engineer. I have worked in many companies since 2002. In specific periods of time I have been freelancer, remote worker or company founder. My main platform has been .Net but also interested to try Linux related platforms. I love to develop software to help people in their life and business. I like projects that are following best practices of software development. Please see my English blog here

Updated on June 07, 2022

Comments

  • Afshar Mohebi
    Afshar Mohebi almost 2 years

    I am trying to use JWT for authentication mechanism in ASP.NET Core Web API project. Suppose this project has not MVC part and does not use cookie authentication. I have created my code based on this guide.

    Login works good and protection with [Authorize] attribute works ok but User.Identity.Name is null. How can I fix this?

    My code:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));
        var tokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)],
    
            ValidateAudience = true,
            ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)],
    
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = _signingKey,
    
            RequireExpirationTime = true,
            ValidateLifetime = true,
    
            ClockSkew = TimeSpan.Zero
        };
    
        app.UseJwtBearerAuthentication(new JwtBearerOptions
        {
            AutomaticAuthenticate = true,
            AutomaticChallenge = true,
            TokenValidationParameters = tokenValidationParameters,
            AuthenticationScheme = JwtBearerDefaults.AuthenticationScheme
        });
    
        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }
    

        [HttpPost]
        [AllowAnonymous]
        [Route("Login")]
        public async Task<IActionResult> Login([FromForm] ApplicationUser applicationUser)
        {
            //assume user/pass are checked and are ok
    
            _logger.LogInformation(1, "API User logged in.");
            var user = await _userManager.FindByNameAsync(applicationUser.UserName);
            var roles = await _userManager.GetRolesAsync(user);
    
            var claims = new List<Claim>
            {
                new Claim(JwtRegisteredClaimNames.Sub, applicationUser.UserName),
                new Claim(ClaimTypes.NameIdentifier, applicationUser.UserName),
                new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
                new Claim(JwtRegisteredClaimNames.Iat,
                        ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(),
                        ClaimValueTypes.Integer64),
                        new Claim("Claim", "Value")
            };
    
            if (roles != null)
                foreach (var role in roles)
                    claims.Add(new Claim("role", role));
    
            // Create the JWT security token and encode it.
            var jwt = new JwtSecurityToken(
                issuer: _jwtOptions.Issuer,
                audience: _jwtOptions.Audience,
                claims: claims,
                notBefore: _jwtOptions.NotBefore,
                expires: _jwtOptions.Expiration,
                signingCredentials: _jwtOptions.SigningCredentials);
    
            var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
    
            // Serialize and return the response
            var response = new
            {
                access_token = encodedJwt,
                expires_in = (int)_jwtOptions.ValidFor.TotalSeconds
            };
    
            var json = JsonConvert.SerializeObject(response, _serializerSettings);
            return new OkObjectResult(json);
        }
    
  • youen
    youen over 6 years
    Using the "sub" field of the token looks more standard than the accepted answer, and also reduces the token size a little :-)
  • Telmo Marques
    Telmo Marques almost 2 years
    To use the constant: NameClaimType = ClaimTypes.NameIdentifier. ClaimTypes comes from System.Security.Claims