‫So, over the last few videos,
‫we allowed a user to reset his password
‫and then create a new one,
‫but now we also want to allow
‫a logged-in user to simply update his password
‫without having to forget it,
‫and so without that whole reset process.
‫So, let's build that now.
‫And, just like before,
‫let's do that in our authentication controller.
‫So, export.updatePassword.
‫All right, and so, just like always,
‫our three Middleware parameters here, and okay.
‫Now remember that this password updating functionality is
‫only for logged-in users,
‫but still we need the user to pass in his current password,
‫so in order to confirm
‫that user actually is who he says he is.
‫So, just as a security measure
‫because imagine that someone would find your computer open
‫and then be able to change passwords on the sites
‫that you have currently open
‫without being prompted for a password again.
‫And so that would basically log you out
‫of all your existing applications,
‫which would, of course, be a terrible experience.
‫And so, as a security measure, we always need to ask
‫for the current password before updating it, all right.
‫And, with that in mind, let's lay out all the steps
‫that we need to take in order to implement
‫this functionality just like before.
‫So, first up, we need to get the user
‫from the collection, basically.
‫Then second, we need to check
‫if the posted password is correct.
‫Right.
‫Then, third, so if the password is correct,
‫then update the password.
‫And finally, we need to again log the user in,
‫so basically to send the jsonwebtoken back to the user,
‫now logged in with the new password that was just updated.
‫Okay, and this is actually all very similar to
‫what we did already before,
‫and so I'm leaving this one for you
‫as a challenge, okay?
‫So, please try to go ahead and implement this on your own,
‫and if you need, you can of course take a look at the code
‫that we wrote before,
‫but really try to write the code on your own
‫without copying too much, okay?
‫So, you can take a look at the rest of the code to see
‫how it works, but then don't really just copy it, okay?
‫Because then you're not really gonna learn, all right.
‫So, pause the video here, and I'll see you in a second
‫with my solution.
‫Okay, so I hoped you managed to implement this
‫and to get it working, this is how I did it.
‫So, as always, we create a new user variable,
‫and in there we await the result of doing User.findById,
‫and now where is this ID actually coming from?
‫Well, remember again that this update password is only
‫for authenticated, so for logged in users,
‫and so therefore, at this point, we will already have
‫the current user on our request object.
‫Okay, so that's coming from the protect Middleware.
‫So, req.user.id, and then remember
‫that we need to explicitly ask for the password, okay?
‫Because it is, by default, not included in the output.
‫So, we defined that on the schema, remember?
‫And, we actually need that password
‫because now we want to compare it with the one
‫that's stored in the database,
‫and for that, just like before,
‫we're gonna use this instance object
‫that we have somewhere here.
‫Yeah, so correctPassword, which is available
‫on all the user documents,
‫so it takes in the candidate password first,
‫and then the actual user password, all right.
‫Oh, and now it's giving me this error
‫because, of course, I didn't declare this
‫as an async function just yet.
‫So, async, and before we forget it,
‫let's wrap it into the catchAsync function here as well.
‫Anyway, just like before,
‫we basically want to create an error here
‫if the current password is not correct,
‫and so, let's write that in code.
‫So, if not user.correctPassword,
‫and then the candidate password remember,
‫and so that one is gonna be in a body,
‫in a property that we're gonna call the passwordConfirm.
‫Okay, and then as a second argument the actual password,
‫so that's a user.password.
‫And then, remember that this is an asynchronous function,
‫and so we need to also await it here.
‫Good, so in case that the password is not correct,
‫just like always, we create a new error here.
‫So, new AppError, and this time we're saying
‫your current password is wrong,
‫and then status code 401 for unauthorized.
‫All right, great.
‫Now, if we make it to this point in code,
‫so basically if the password is also correct,
‫well then we can actually update the password,
‫and how do we do that?
‫Well, very simple, we did that before.
‫All we say is user.password is equal to req.body.password,
‫and then the same, of course, for the password confirm.
‫Okay, and the validation will be done automatically
‫by the validator that we specified on the schema,
‫and that will be done once we actually save it.
‫So, we await user.save,
‫and so this time we do not turn off the validation
‫because, of course, we want the validation to happen,
‫so just as I said before, we want to check
‫that the password confirm is actually the same
‫as the password, right?
‫Good.
‫And, now just to really make sure that you understand
‫why we didn't do something like user.findByIdAndUpdate.
‫So, why didn't we do it like this?
‫And, I know that I talked about this many times before,
‫but I want you to understand one hundred percent
‫why we cannot use this update,
‫and it is for two reasons,
‫so let me go back again to our model.
‫So, the first one is
‫that this validation here is not going to work, okay?
‫And that's basically because this.password is not defined
‫when we update, so when we use find by ID and update,
‫because internally, behind the scenes,
‫Mongoose does not really keep the current object in memory,
‫and so therefore, this here is not going to work.
‫And, as I said, I already talked about that before,
‫so it's actually written out here as well, okay?
‫But, it's really important to keep in mind not to use update
‫for anything related to passwords, all right?
‫So, this one is not going to work,
‫and also, these two pre-saved
‫Middlewares are also not going to work.
‫So, if we used simply update for updating the password,
‫then that password would not be encrypted,
‫which is this first Middleware,
‫and then also, the passwordChangedAt
‫timestamp would also not be set, okay?
‫So, none of this would work,
‫and so again, we really need to do it like this.
‫Let's just put that here again.
‫And so now, (mumbles), we logged the user in,
‫and sent the token back to the client.
‫Now, that would actually be the fourth time
‫that we did the same code,
‫so basically this piece of code,
‫and so, that's now very quickly refactor this
‫into its own function.
‫Now, this code actually is not the same everywhere.
‫So, here we sent the status code 400,
‫and we do not send the user,
‫but then up here in the signup handler,
‫we actually have a different status code,
‫and we also sent the user to the client, okay?
‫And so, let's make our function actually keep that in mind.
‫So, let's create a function here,
‫create and send token,
‫and then the arguments that we need in here are the user
‫because that's where the ID is stored.
‫Then, we also want the status code,
‫and of course, we need to have access to the response object
‫in order to actually be able to send a response
‫back to the client, okay?
‫And so, basically now what we need is this code.
‫So, let's copy it, put it here,
‫and then replace irrelevant variables.
‫So, the user is simply called user,
‫so just like this, and here, the same.
‫So, not new user,
‫and then here we replace that with the status code,
‫so the one that's coming in into our function,
‫and so I guess that's actually it.
‫So, let's now go ahead and replace it,
‫so createSendToken, and here the user is called the newUser,
‫the status code is 201,
‫and then of course the response object.
‫Okay, now we can get rid of this code,
‫and let's just copy it.
‫All right, so in the log in we of course also sent a token,
‫but this time the user is actually called user
‫and the status code is 200.
‫And now, let's copy this one.
‫So, the next one should be here, and reset password,
‫and here it's actually the same,
‫so the name is user and code 200,
‫and now, finally, here it's also the same.
‫And so, that finishes our update password function.
‫Now, to make this work,
‫we of course need to implement the route here as well
‫in our user router.
‫So, router.patch, and we will do a patch
‫because we're actually changing, so we're manipulating
‫the user document, and so that's what patch is for.
‫And the route is called updateMyPassword.
‫So, my password because it's
‫for the currently logged in user, and then remember, again,
‫this only works for logged in users,
‫and so we need to use authController.protect,
‫which will then also put the user object
‫on a request object, okay?
‫So, protect, and then authController update password
‫that we just created, all right.
‫And so, let's now actually go ahead and test this, okay?
‫So, let's copy this route here,
‫so UpdateMyPassword,
‫and now what we need to send in the body is
‫these three passwords actually,
‫so it's basically the passwordCurrent,
‫and for now I'm leaving them empty,
‫I simply want to put the field names here for now.
‫So, passwordCurrent then just password,
‫which is basically the new one,
‫and then, of course, passwordConfirm.
‫Okay, and now we actually need to log in as a user
‫because remember, this only works
‫if the user is already logged in, all right.
‫And so, let's actually do it with the administrator here.
‫And this here is, should be still the current password,
‫and indeed, we are now logged in.
‫And remember that this token now gets stored
‫into the JWT environment variable,
‫and so, here, in order to authenticate,
‫let's then actually use that just like we did before.
‫So, in this authorization tab, we select Bearer Token,
‫and then it will actually automatically pre-fill
‫this JWT variable.
‫All right, and so that's then where actually
‫the user ID is gonna come from, remember?
‫Anyway, let's now specify the current password, so pass1234,
‫and then let's say newpassword, okay?
‫Copy it and paste it here,
‫but actually again, I want to start by testing it
‫with a wrong password confirm,
‫just to see if our validation is still working,
‫and now the route is not defined,
‫but that's simply because we're using the wrong verb here.
‫Of course, it needs to be patch.
‫Let's try that again,
‫but now we get your current password is wrong,
‫but actually it's not, so it's actually correct.
‫So, something must be wrong with our code,
‫so let's try to take a look here.
‫And yeah, so here is actually the problem
‫because we do not want to compare or confirm password,
‫of course, but with the current password.
‫Okay, so that's just a stupid bug, all right,
‫and so now it should be working.
‫So, of course, we want to compare the current password
‫with the one that is currently stored
‫in the database, all right.
‫So, let's try that again,
‫and so that's the validation error that we were looking for,
‫so the passwords are not the same
‫because, indeed, they are not.
‫And now, before actually updating the password,
‫let's just take a look at Compass here.
‫Let's just update it here quickly,
‫and so, right now, this is the password.
‫So, ending here is pW1i, okay?
‫And so, let's update the password now
‫and see what it's gonna look like afterwards, okay?
‫So, now everything should be correct.
‫And, indeed, we get our success and our token, all right.
‫So, let's confirm that here quickly,
‫and, indeed, you see that the password changed
‫and also the current timestamp,
‫so the time at which basically I'm recording this video.
‫All right, and now, just like before,
‫let's actually get this test here.
‫So, basically storing the token as an environment variable.
‫So, just so that everything really works here in Postman.
‫Okay, let's save that actually,
‫update current user password to make it really explicit,
‫and yeah, I think that's it.
‫I think this is all we need to do
‫in order to update a user's password .
‫Next up, we will then implement updating of other user data,
‫so stuff like email or passwords.