P.Laurie
P.Laurie

Reputation: 21

Web API ChangePasswordAsync controller returning Failed : PasswordMismatch C#

I am building a .net core 2 Identity application. It uses JWT token for a Vuejs front end.

I am writing the update password controller that checks the token first then changes the password using ChangePasswordAsync but I keep getting the response:

{Failed : PasswordMismatch}.

My controller code is below. I have successfully written the login and register controllers but having no luck with this. The logged in user, ctrustUser is successfully returned, so then I am using that data to pass into ChangePasswordAsync the logged in user data. Please can you help me.

  [Authorize(Policy = "ApiUser")]
  [Route("api/[controller]/[action]")]
  public class AccountsEditController : Controller
  {
    private readonly ClaimsPrincipal _caller;
    private readonly ApplicationCtrustUsersDbContext _appDbContext;
    private readonly UserManager<AppAdminUser> _userManager;
    private readonly IMapper _mapper;

    public AccountsEditController(UserManager<AppAdminUser> userManager, ApplicationCtrustUsersDbContext appDbContext, IHttpContextAccessor httpContextAccessor, IMapper mapper)
    {
      _userManager = userManager;
      _caller = httpContextAccessor.HttpContext.User;
      _appDbContext = appDbContext;
      _mapper = mapper;
    }

    // POST api/accountsedit/updatepassword
    [HttpPost]
    public async Task<IActionResult>UpdatePassword([FromBody]UpdatePasswordViewModel model)
    {
      // simulate slightly longer running operation to show UI state change
      await Task.Delay(250);

      if (!ModelState.IsValid)
      {
        return BadRequest(ModelState);
      }

      // retrieve the user info
      var userId = _caller.Claims.Single(c => c.Type == "id");
      var ctrustUser = await _appDbContext.CtrustUser.Include(c => c.Identity).SingleAsync(c => c.Identity.Id == userId.Value);

      AppAdminUser userIdentity = new AppAdminUser();

      userIdentity.Id = ctrustUser.IdentityId;
      userIdentity.UserName = ctrustUser.Identity.UserName;
      userIdentity.Email = ctrustUser.Identity.Email;

      //AppAdminUser user = _mapper.Map<AppAdminUser>(model);

      var result = await _userManager.ChangePasswordAsync(userIdentity, model.Password, model.NewPassword);

      if (!result.Succeeded) return new BadRequestObjectResult(Errors.AddErrorsToModelState(result, ModelState));

      return new OkObjectResult("Password updated");
    }
  }

Upvotes: 0

Views: 1557

Answers (2)

P.Laurie
P.Laurie

Reputation: 21

Solved it, by using:

var user = await _userManager.FindByNameAsync(...);

then passing that into ChangePasswordAsync

var result = await _userManager.ChangePasswordAsync(user, model.Password, model.NewPassword); 

Upvotes: 1

John
John

Reputation: 26

The error {Failed : PasswordMismatch} is due to the "currentPassword" parameter your passing in not matching the existing password against that user (the second parameter in the method) which you're sending in as "model.Password". The method validates this value to ensure the user is who they say they are.

public virtual Task<IdentityResult> ChangePasswordAsync(TUser user, string 
    currentPassword, string newPassword);

I'd suggest debugging that to ensure that you're passing in the users current password, not their new password, and ensure you're retrieving the correct user.

Upvotes: 1

Related Questions