3

I have created a method where a user can log into my application and then a Token is sent to the user so it can be used to view any other views in the application.When i test the login method on postman i get the 500 server error as below instead of the token. I have seen similar questions/posts but haven't seen one that is related to JWT

Below is the output

System.ArgumentNullException: Value cannot be null. (Parameter 'value') at System.Security.Claims.Claim..ctor(String type, String value, String valueType, String issuer, String originalIssuer, ClaimsIdentity subject, String propertyKey, String propertyValue) at System.Security.Claims.Claim..ctor(String type, String value) at Coop_Marketing.Controllers.AccountController.Login(LoginViewModel formdata) in /Users/Ken/Desktop/Coop_Marketing/Coop_Marketing/Coop_Marketing/Controllers/AccountController.cs:line 101 at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

The Account controller with the login method is below

   public async Task<IActionResult> Login([FromBody] LoginViewModel formdata)
    {
        // Get the User from database
         var user = await _userManager.FindByNameAsync(formdata.Username);

         var roles = await _userManager.GetRolesAsync(user);

        

        var key = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_appSettings.Secret));
        double tokenExpiryTime = Convert.ToDouble(_appSettings.ExpireTime);

        if(user !=null && await _userManager.CheckPasswordAsync(user,formdata.Password))
        {

            
            var tokenhandler = new JwtSecurityTokenHandler();

            // Describe the token used by the user to log in

            var tokenDescriptor = new SecurityTokenDescriptor
                          
            {
               
                Subject = new ClaimsIdentity(new Claim[]
                {
                    
                    new Claim(JwtRegisteredClaimNames.Sub, formdata.Username),
                    new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                    new Claim(ClaimTypes.NameIdentifier, user.Id),
                    new Claim(ClaimTypes.Role, roles.FirstOrDefault()),
                    new Claim("LoggedOn", DateTime.Now.ToString()),

                    
                }),
                

                SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256Signature),
                Issuer = _appSettings.Site,
                Audience = _appSettings.Audience,
                Expires = DateTime.UtcNow.AddMinutes(tokenExpiryTime)
            };
            // Generate the token
            var token = tokenhandler.CreateToken(tokenDescriptor);
            return Ok(new {token= tokenhandler.WriteToken(token), expiration = token.ValidTo,username = user.UserName,userRole = roles.FirstOrDefault()});


        }

        
        // Return error
        ModelState.AddModelError("","Username/Password was not Found");
        return Unauthorized(new { LoginError = "Please check the Login Credentials - Invalid Username/Password was entered" });
    }
}

}

And the LoginViewModel

public class LoginViewModel
{
    [Required]
    [Display(Name = "User Name")]

    public string Username { get; set; }

    [Required]
    [DataType(DataType.Password)]
    public string Password { get; set; }
} 

The problem is with > var tokenDescriptor = new SecurityTokenDescriptor as per line 101 in the code which is mentioned in the output. However,I have failed to figure out why I am getting the error.

1
  • The error shows the constructor for Claim has a null parameter for value... System.Security.Claims.Claim..ctor(String type, String value). To help debug, move the array out of the "one-line-new" nesting so you can step through with the debugger and determine which Claim is failing. Commented Aug 10, 2021 at 0:04

2 Answers 2

3

So it is like Claim has a null parameter. for that, you found this issue.

Update your code like below:-

.....

 Subject = new ClaimsIdentity(new Claim[]
                {
                   
                    new Claim(JwtRegisteredClaimNames.NameId,formdata.UserName), //modified
                    new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                    new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()), //modified
                    new Claim(ClaimTypes.Role, roles.FirstOrDefault()),
                    new Claim("LoggedOn", DateTime.Now.ToString()),

                    
                }),

.....

Hope it will resolve your issue.

Sign up to request clarification or add additional context in comments.

1 Comment

This Enum is working JwtRegisteredClaimNames
1

As you can see in the official documentation, the constructor will throw an argument null exception when the claim type/value is null. So it seems you are passing a null value(s) to the Claim constructor when creating the Claim object array.

As @Jasen mentioned to make the debugging easier change the one-line Claims array creation just for debugging and put a breakpoint to identify which claim is the culprit.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.