Implementing a Secure Email Change Flow
00:00 In our change email route, we've got this handle verification. This is going to be called when the user has successfully verified their ownership of the new email address. We sent that email to the email that they said, hey, I want to change it to this new email. I'll say kodyatexample.com.
00:18 That will be the submission value email. We send the one-time password to that email address. When they end up in here, then we verified that they do in fact own that email address. We need to get that email address that they submitted from the verify session. We'll say verify session equals
00:38 await verify session storage.get session from request headers, get cookie. Then we're going to get the new email from the verify session using that new email address session key, which we sent down here.
00:55 We stuck that in the cookie when the user submitted it. If we end up in here, then they verified that's correct. Okay, great. Then with that new email from verify session, we can check if there is no email.
01:14 If there's not an email, then we need to let them know that there's some problem. Copilot, that's nice of you, but we're going to do this a little bit easier. We're going to say submission.error at the form level. We want it to say, you must submit the code on
01:33 the same device that requested the email change. The reason for that is because we're looking for the new email address inside of the verify session. This will sometimes happen where the user will request it on one device and then confirm it on their new device. They can't do that. They have to request it on this device, and then maybe they receive the email over here.
01:53 They just look at the code and type it in there. But yeah, that's the best way to make this secure system. Here we say that, and if the user's email address, we need to get what the user's email address is before the change, because we want to let them know that, hey,
02:12 your email address has been changed, just FYI, contact support or whatever. Let's get the user or previous user, and find the user by that ID. Here TypeScript is complaining because it's not
02:31 sure whether the submission value is null. It should be valid by the time we call this function, but TypeScript doesn't know that. We're going to add that, and submission value must be defined. That works. Now, it's not complaining about that,
02:50 and let's update the user. User await, Prisma user update, where the ID matches the thing that we're verifying ownership of, and the email is the new email address that is inside the cookie.
03:07 Then we're going to send an email to that new or to the previous email address. Now, this is something that I'm going to actually use void for. We're going to void send the email. What that means is, don't wait for this to complete, just proceed. If it doesn't complete, we're not going to not change the email.
03:26 It's too late now anyway. We're going to just send the email as is, and we'll just let them know the email. We have a template for this already, so we'll just use that, and say, hey, this has changed. We'll send them the user ID,
03:45 so when they contact support, they can say, hey, here's my user ID. Please, can you help me with this? Yeah. The previously updated user, if we can't find that user, then there's major problem. TypeScript is like, hey, this could be null, but we can just say or throw.
04:04 Now, it's going to throw an error, and that is unlikely to happen. But if it does, then yeah, that's definitely a major problem, so we don't want to proceed anyway. Okay. So with that, then we're going to use a redirect with Toast, throw, await, redirect with Toast,
04:21 to send the user to this place, to settings profile, and the Toast message we want to send them has a title of email changed, and yeah, message, yeah, your email has changed, yeah, whatever you want that to say is just fine.
04:40 This is actually a description. There we go, and we're all set. So let's test this all out, make sure all of this works. So we want to verify that the emails are sent and all of that. So let's start from scratch right here. So I want to change my email. I'm going to come over here, I'm going to say,
04:58 Cody at example.com, and we'll come over to my inbox right here, and here is the code. We'll copy that, paste it in here, submit, and boom, your email has been changed. Ta-da, we can look at our email, it's right there. Can come over here and verify
05:16 that your Epic Notes email has been changed. We're writing to let you know. Yeah, contact support, here's your account ID, all that. So that's kind of a good idea to make sure that in case somebody got a hold of their account or something, they'd want to be made aware of that.
05:33 And that is how you implement the user, or change email flow. We have this handle verification, it's the same as everything else we've been doing, and we grab the new email. Once the user is verified, then we can take that email that we stored in the verify session
05:51 and verify that this user does, yes, indeed, own this account. That's what we verified their ownership of was the account and the new email. And with that, we can grab the previous user and update the current user, and then send the email to the previous email address,
06:09 and then redirect them with a nice message to say, you did it, good job. So there you go, that is change email.