‫In this video and the next ones,
‫we are going to implement a user-friendly
‫password reset functionality, which is kind of
‫standard in most web applications.
‫And probably, you have used the password reset
‫on some website before and usually,
‫it works like this.
‫You just have to provide your email address
‫and you will then get an email with a link
‫where you can click and then that's gonna take you
‫to a page where you can put in a new password.
‫This is a very standard procedure and so
‫this is also how we're going to implement it
‫here in this application.
‫Basically there are two steps.
‫For the first one is that the user sends a post request
‫to a forgot password route, only with this email address.
‫This will then create a reset token
‫and sent that to the email address that was provided.
‫Just a simple, random token, not a JSON Web Token.
‫That's a difference here.
‫Then in the second part, which is gonna be the next video,
‫the user then sends that token from his email
‫along with a new password in order to update his password.
‫Basically, we will have exports dot forgot password
‫which is the first step.
‫So request, response and next
‫and then as a second step, we have reset password.
‫Then let's also go ahead and implement these two routes.
‫Okay, and that's, of course, in their user router
‫or user routes file.
‫Let's put them also right up here
‫and actually I can just duplicate these lines here.
‫So we have again forgot password,
‫which will only receive the email address
‫and then reset password,
‫which will receive the token as well as the new password.
‫This is the one that we're gonna start
‫implementing in this lecture.
‫Let's just like before specify our steps here.
‫So first, get user
‫based on posted email
‫then generate the random token.
‫And then basically send it back as an email.
‫This stuff is pretty common for us at this point.
‫So user, so let's await user dot find
‫and now it's find one,
‫not find by id because we don't know the user's id.
‫And user, of course, also doesn't know his own id
‫and so we specified the email address.
‫Basically it's the only piece of data that is known.
‫And that is stand on request dot body dot email address.
‫And of course now we need to say that
‫we're in an async function and then just like before,
‫let's wrap it in catch async.
‫Give it a save and the error should be gone.
‫Then next step, let's verify
‫if the user does exist.
‫So if no user, then return to the next middleware
‫along of course with a new error.
‫Is no user with that email address.
‫And then we can put a 404, which as you already know,
‫means not found.
‫Next up, let's then generate the random token
‫and for that, once more, we're actually gonna create
‫an instant method on the user.
‫Because once more, this really has to do with
‫the user data itself.
‫And we're gonna write a bit of code really,
‫and so, if it was only one line of code,
‫then of course we could just put it right here.
‫But we need a couple of lines of code
‫and so again, it's a bit cleaner
‫to separate it into its own function.
‫And that usually with Mongoose is best as an instant method.
‫So down here, let's just edit here at the end.
‫So user schema dot methods dot create password reset token.
‫Quite a long and descriptive name.
‫I like to do it like that,
‫so that I know exactly what I'm dealing with.
‫The password reset token should basically be a random string
‫but at the same time, it doesn't need
‫to be as cryptographically strong as the password hash
‫that we created before.
‫We can just use the very simple, random bytes function
‫from the built-in crypto module.
‫Let's go ahead and actually add that.
‫Crypto require and again, it is a built-in a node module
‫so no need to install anything.
‫Cool.
‫Now, let's then actually generate our token.
‫And for that, we use crypto dot random bytes
‫and then here we need to specify the number of
‫characters basically.
‫And then we also in the end,
‫convert it to a hexadecimal string.
‫Two string
‫and then we can specify the hex option here.
‫Now if you're wondering why we are
‫actually creating this token,
‫I guess I didn't really explain it just yet.
‫Basically this token is what we're gonna send
‫to the user and so it's like a reset password really
‫that the user can then use to create a new real password.
‫And of course, only the user will have access to this token.
‫And so in fact, it really behaves kind of like a password.
‫Since essentially it is just a password,
‫it means that if a hacker can get access to our database,
‫well then that's gonna allow the hacker to gain access
‫to the account by setting a new password.
‫If we would just simply store this reset token
‫in our database now, then if some attacker gains access
‫to the database, they could then use
‫that token and create a new password using that token
‫instead of you doing it.
‫They would then effectively control your account
‫instead of you doing it.
‫Just like a password, we should never store
‫a plain reset token in the database.
‫Let's actually encrypt it,
‫but such as before with the password,
‫it doesn't need such a cryptographically strong
‫encryption method.
‫Because these reset tokens are a way less dangerous
‫attack vector.
‫Again, we're just gonna use the built-in
‫crypto module.
‫It works in this kind of weird-looking way.
‫We say crypto then create hash
‫with the sha 256 algorithm
‫then we need to say update
‫and then variable where the token is stored.
‫Whatever string we want to encrypt basically.
‫And then we need to say digest and then again
‫store it as a hexadecimal.
‫And now where are we actually gonna save this reset token?
‫Well, we're gonna create a new field in our database schema.
‫'Cause of course, we want to save it in the database,
‫so that we can then compare it
‫with the token that the user provides.
‫Let's do that here at the end.
‫Password reset token,
‫that's the string.
‫And then also password reset expires.
‫Because this reset will actually expire
‫after a certain amount of time as a security measure.
‫You will only have 10 minutes in order to actually
‫reset your password.
‫Let's now go ahead and use these.
‫This dot password reset token is then equal
‫to this encryption.
‫Next up, let's then set password reset expires
‫and let's set that to date dot now
‫and then simply add a couple of seconds to that.
‫We want it to work for 10 minutes
‫and so that's 10 and then we need it in milliseconds.
‫Times 60 for seconds and then times 1000 for milliseconds.
‫And then I also want to return the plain text token
‫because that's actually the one that we're gonna send
‫through the email.
‫Return reset token.
‫We need to send via email
‫the unencrypted reset token because otherwise
‫it wouldn't make much sense to encrypt it at all.
‫If the token that was in the database
‫was the exact same that we could use
‫to actually change the password,
‫well then that wouldn't be any encryption at all.
‫We sent one token via email
‫and then we have the encrypted version in our database.
‫And that encrypted one is then basically useless
‫to change the password.
‫It's just like when we're saving only the
‫encrypted password itself to the database,
‫just like we did up here,
‫So where we encrypted the password using bcrypt.
‫Keep in mind that the only ever save
‫sensitive data in an encrypted form
‫and then compare it with the encrypted version
‫that's in the database.
‫That's just log these two to the console
‫that will make our lives a bit easier down the road.
‫Let's say reset token
‫and I'm logging in here
‫as an object because this way, it will then actually
‫tell me the variable name along with its value.
‫And then the same with this dot password reset token.
‫This one doesn't really work
‫with writing object, this new ES6 way
‫and let's just leave it at this.
‫Anyway, let's just come back here
‫and then use that function.
‫So remember how we returned the reset token,
‫and let's store that here.
‫So reset token is equal to user dot set
‫and I'm not sure of the name anymore.
‫Create password reset token,
‫so that's a long one.
‫All right and so that is done,
‫but actually what we did was just to modify
‫the data in here.
‫When we set this dot password expires for example
‫to this value, we did in fact
‫not really update the document.
‫We did not save it.
‫We really just modify it,
‫but now we then need to save it.
‫Let's say await user dot save.
‫But watch what happens as we now use this.
‫Let's just grab this one here.
‫This is the route that we did find before.
‫And now we get this route is not yet defined.
‫Let's see why that is.
‫In the user route, we clearly have the same url here,
‫but I see that we actually need to do a post request.
‫All right, okay, but now we get an error
‫saying please provide email and password.
‫And so that's what I meant when I said
‫watch what happens when you try this.
‫That happens because we're trying to save a document,
‫but we do not specify all of the mandatory data,
‫so the fields that we marked as required.
‫Let's quickly fix that.
‫All we need to do is to actually pass a special option
‫into this user dot save method.
‫We say
‫validate before save
‫set to false.
‫This will then deactivate all the validaters
‫that we specified in our schema.
‫It's these small things that you need to know
‫that will make all the difference.
‫Now I also didn't actually know that this existed
‫because no one really knows all of the stuff.
‫It's impossible.
‫A library like Mongoose is simply way too big
‫for you to know everything there is.
‫I went ahead and read the Mongoose documentation
‫and so that's where I found this extremely helpful option.
‫All of this just to say that again,
‫no one knows everything
‫and so it's really a good habit to
‫if you run into some problems
‫to take a look at the documentation
‫for the library that you're using.
‫Let's take a look at this now.
‫And we still get the same error here,
‫but I see down here that it's actually
‫coming from the login function.
‫Let's take a look at what's going on here.
‫Let's take a look at the routes also.
‫Ah, okay, so here's the problem.
‫We are now trying to call
‫the login handler, which of course, doesn't make sense.
‫Here it's forgot password.
‫Here it's reset password.
‫And so the error that we got before was actually not because
‫of the validation.
‫Let's send this again
‫and now we get the error that there is no user
‫with this email address
‫and so that's because we didn't specify
‫any email address in the body.
‫We tested that
‫and so now it's time to actually test it
‫with a user email.
‫All right.
‫And so now it shouldn't actually do anything
‫because we're not sending back any response.
‫Let's just cancel this
‫because all I was really interested in
‫is to see these tokens here
‫and then also to take a look at the user object.
‫This here is the original reset token,
‫so you see it's a random hexadecimal string
‫and then we got the encrypted one in here.
‫This remember is the one that should not be in the database,
‫so ending in a901.
‫Let's take a look at that.
‫And indeed, here it is,
‫password reset token ending in this a901.
‫And also the date, which is in fact 10 minutes from now.
‫Now you know at what time I'm recording this video.
‫Anyway, but this worked just fine.
‫And so this is actually the first part
‫of creating this password reset functionality.
‫In the next video, we will then
‫send this token here via email to the user
‫and so actually prepared a separate video
‫only for learning how to actually send email with
‫node to js.
‫That's a very fun one
‫so don't wait to move there right away.