Secure Password Reset Flow Implementation
00:00 The first thing I think we should do is go to the reset password right here, and we're going to make a little utility for our loader in action to make sure that only people who are allowed to be here can be here.
00:10 So we're going to export a function called requireResetPasswordUserName. Remember, we're setting that right up here where we're handling the verification, and so that's a password username session key. That's something that's in the session.
00:30 Now, we did something similar to this actually in onboarding. So let's copy what we did there, come over here and paste that right there. So that's going to require anonymous. If they're not anonymous, if they're logged in, they shouldn't be here. We're also going to need the request. So here's the request. Yeah, we're also going to need the proper
00:49 key for the thing that we set into the verify session. So we'll stick this right there. Instead of e-mail, this is actually going to be a reset password username. There we go. That will be handy for us to say,
01:08 oh, wait, requireResetPasswordUserName. I save that, and boom. Now, we got, hi, Cody, no worries. So we're loading the right data. We now know which user is trying to reset their password, all of that. We can use that in our action as well.
01:25 So if they try to hit this endpoint directly, then it will do all the same verification there too, which is quite nice. So now we're supposed to call this ResetUserPasswordUtility. That is something we're going to write in the auth server. So right here, we've got this ResetUserPassword function. We're going to export,
01:44 chain ResetUserPassword. It takes the username and password, and both of these could be typed just as strings, but I actually like to, oh my, Copilot almost did it for us. I like to use the model type from Prisma,
02:03 just to communicate that this is exactly the thing I'm looking for is a username that comes from the user table. So it ends up being a string, it ends up being just the same, but I like to communicate that in the code. So that's what we're going to do. Then the password is set to be a string because we don't have
02:21 anything for plain text passwords in the database anyway. So from there, let's see if Copilot can do the rest of this for us. There we go. So we're going to create a password hash. We're using this also in our signup process as well. So we get the hash password, and then we say, hey Prisma, I want you to update the user where their username is the
02:41 one that we've provided and update the password hash to this new hashed password. Then of course we can return the user. We don't have to, there's not really anything we're going to be using this for. So I'm going to select the ID because I don't want to grab more data from the database than we need.
02:58 We don't really need anything from the database anyway. So that takes care of our reset user password utility. So then we can come back here and we can call that. We can await that. We can pass the username, which is going to be the reset password username that we get from the cookie.
03:17 So the user can't submit that. That's part of what makes this secure is they have it. It's in their browser, but they can't change it. They can't set it. We are the only ones who can set it, but they are the ones who store it. That's kind of the interesting thing about cookies. And then we have our password that's coming from the submission value. And finally,
03:37 we're going to return a redirect to login and we're going to set some headers. So we've got to actually grab our verify session and a way to verify session storage dot get session from the cookie. And then we want to destroy it.
03:57 So not commit the session. We're going to destroy that way. It's gone from the user's browser. We don't need it anymore. And then they can verify other things later if they want to, but we don't need it from here. All right, there we go.
04:16 So let's try the whole flow and I'm going to try from the very, very beginning. So I'm going to say, Oh no, I forgot my password. So we'll type in Cody and now it's going to send me an email. So we'll come here, we'll grab the code and we'll do the verification process, submit that.
04:33 And my new password is you are great by the way, you are great. And there we are. So now I go, Cody, you are great. And boom, I'm logged in and yeah, so we can edit our profile and all of that other good stuff. Probably be good to just double check. We don't have two passwords or something that really shouldn't be possible,
04:53 but Cody loves you was our old password and no longer works. So we're in a good spot. Let's just review a couple of the things that we did here. So in, in the recent password module, we created a require recent password username that way people can't even get to
05:11 this route if they haven't set up the, or gone through the verification flow and set in the verification storage, our reset password username. So if they haven't done that, we kick them out. We throw them over to sign up. Otherwise we return the password username, and then we can use that in our loader to display something in the UI.
05:32 And then in our action, we use that to actually perform the password to reset, which we created in the off server right here where we're hashing the password and we get the user update the user with that new password. And then we redirect to the login, destroying the verify session storage,
05:51 cookie, and then the user can go through the login flow. So there you go. That's password reset. Good job.