Resetting Passwords and Handling Verification
00:00 Let's start by going to our Forgot Password route. And in here, we're inside of our action. Once we've verified that the user submitted their username or email properly, and that the user does, in fact, exist, and all of that stuff, then we can create our verification. Now, we already did something like this.
00:17 So we have this new prepare verification utility. So this is where we're going to get a redirect to, and our verify URL, and our OTP is going to come from a awaited call to prepare verification. So that's going to come from the verify route.
00:34 That's what manages all of our verification stuff. And inside of here, we can specify a couple of things. So for this, this is an email. So we probably want to do 10 minutes. But again, this is in seconds, not milliseconds. So there you go. You got 10 minutes. And then we want to pass the request.
00:53 This is so that the verification can generate the redirect to and the verify URL that include the domain, which will come from the request. And then we also have the target. Now, the target is going to be the username or email. So the thing that the user submitted, that's the thing that they say, I'm the owner of this thing.
01:12 And then finally, the type, this is actually a typed type. So the type is just onboarding is the only option. But we're not onboarding. In this case, we are trying to reset the password. And so for that reason, we need to go into prepare verification right here.
01:29 And the type is typed as the verification types right here. And so this is actually kind of cool. So we can say, hey, we have another type of verification. That type is reset password. And once we do that, we're going to get some errors here. Down here, we'll get that this submission is not right and that the status is not right.
01:49 And the reason for that is our verification code right here. We are handling every type of verification. But since we added another type of verification, now we're not handling all of the cases, all of the situations. So we could just add a default right here
02:07 that says throw new response invalid verification type. You could do something like that. And that would take care of those errors. And maybe we should leave that in. But what we really want is to add a case for reset password. And we'll need to handle that. So we'll take care of that in just a moment.
02:27 Let's get back to this. And now we can say reset password. Awesome. So then the rest of this will happen as it's coded currently. So we're sending an email. We have now a React component for creating that email using the React email packages. And then when that email is sent,
02:47 we'll redirect them to the redirect too. And that goes through that process. So let's try what we've got so far. My username is Cody. That's going to send me over to verify. We can look at our type is reset password. The target is Cody. And now it's asking for a code. So I can come over here. And we'll look at our terminal output.
03:06 And we'll see here is the code that we got. Here's the URL. So let's just actually I'll just grab the code, copy this, and paste it in. And now it's going to blow up because we haven't handled the reset password verification type yet. But that gets us in a pretty good place so far.
03:24 We're pretty close to getting this working. Now, our verification has been deleted now. So we'll have to request another one once we get this verified. So let's continue. Now, on the reset password route, this is where we're going to handle that verification.
03:41 So verify is only responsible for actually verifying the code. It doesn't know anything about what should happen once that verification is finished. So that's what this handle verification is going to be doing for us. So let's add that. And we'll say return handle verification from reset password.
04:00 I'm going to F2 rename this because we're going to have a couple handle verifications. We're going to say handle reset password verification. There we go. And then we're going to send the request body and submission. And we're getting type errors in here because we haven't finished implementing this over here.
04:18 So we've got to get that piece done before TypeScript will be thrilled with us, which, of course, it will be. So the first thing we need to do is get the target out of the submission value. Now, this is complaining because it's not
04:35 sure that the submission value is defined. And we're pretty confident. So we're just going to add an invariant right here that says that the submission value is defined. And we can just say submission value must be defined. There we go. OK, great. So we've got the target.
04:52 Now we're going to get the user based on that target. We know by this point, we already know that they're verified. So we don't need to worry about this. We're handling what happens after verification. So we get the user. We're going to await. And because the target is a username or an email, as we have them fill in here, we're
05:10 going to have to look up the user by one of those fields. So we're going to have an or in our where clause. And the email is going to be the target or the username. So we allow them to enter the username or email. I really don't like when websites say, did you forget your password?
05:29 Or did you forget your email? It's like, just let me enter either my username or email. Either way, that's fine. So that's what we're going to do because we care about the user experience. But we don't want to select everything, of course. We're going to select the email. And the username. So now we know for sure whether it's a username or an email
05:48 because that's what we're going to select. OK, great. So then if the user doesn't exist, if there's no user, then we're going to need to return a JSON with a status of error and the submission.
06:02 We're going to set the error for the code to be invalid code because there's something weird going on. We don't need to give them any specifics. We'll just say for this to happen, they would have to submit a request to change their password.
06:22 And we already verified that their email or username exists. And then somehow, maybe their account gets deleted between that point and the point they reset the password. And if that's the case, then there is no code that will possibly be valid anyway. So we'll just say the code is invalid. This is unlikely to ever happen.
06:40 But you need to handle those types of situations because the things that are unlikely to happen will absolutely happen at scale. So there we go. We are handling that case. And if there is a user, then we can go ahead and send that information in the verify session and send them off to actually allow
07:00 them to reset their password. So let's get our verify session from await verify session storage. And we're going to get session from the request.headers.get cookie. And then with the verify session right here,
07:18 we're going to set the reset password username session key. So we're going to need to create a reset password username session key. And that is going to be up here.
07:33 So I'll say reset password username session key will just be this. So it's just a variable that we can use to use this also in our loader or in our action below. So let's put that right there, this right here.
07:53 So we're going to set that. And we're going to set the user's username to that. OK, so now we know which user is allowed and has been verified to change their password in this browser. And so finally, we can return a redirect to reset password to our current route.
08:13 Because remember, this code is actually running under the verify route still. So we're going to redirect them to this route. And our headers will have a set cookie that will await the verify session storage commit session, the verify session.
08:30 And now we're going to set that value in the cookie so that we can pass this along to the reset route. OK, so from there, that's as far as we're going to take this in this first part of the exercise.
08:46 So let's just review and make sure that our types are all happy. We're handling things properly. Types are good. So let's review what we've done here. And then we can proceed and finish this up. So I can type in Cody. And I can say, hey, I want to reset my password.
09:04 That will send me an email that includes a code. So I will grab that code. We'll stick this right here and submit that. And now I've got my password reset form. So that sent me over to the password reset. I can change my password and then reset the password.
09:21 That part is yet to be completed. We've got our action right here. And we have yet to implement that. So we're going to get a big blow up from this and also the passwords you need to match and all that stuff. So that is your task for the next exercise.
09:38 But that's as far as we've gotten as far as that is concerned. So a quick review of all of what we've done. We prepared a verification using the new prepare verification utility, which is doing the same stuff that we've done before. We pass it the period of 10 minutes. We give it the request to get the domain URL.
09:57 We give it the target of username or email and the type of reset password. This is going to go into the database. And then when the user goes and actually after that, we send the email and do all that. So then when the user checks their email and they go over to the verify and enter that, once that has all been verified with the stuff
10:17 that we've done already, then it will come down into here. And it's going to take our reset password case, which we added right up here in our valid types for this. So it takes the reset password case and in handle verification for the reset password,
10:35 we're going to grab the target so that we can get the user that this is intended for and verify that the user does, in fact, exist. Then we're going to pass the user's username into this verify session so that when they get over to the reset password route, we can
10:53 use that to make sure that we're changing the correct username for the correct user or changing the correct password for the correct user. And that is as far as we've gotten. We've still got more to do. Well done.