Current section: Third Party Login 4 exercises

Onboarding and User Authentication with Third-Party Providers

Loading solution


00:00 Let's get these users logged in. We'll go to our callback here and we've got this little import of a couple of things that we're going to need here in a bit, so we'll just uncomment that. Now we're handling a bunch of cases. So if there is an existing connection and a user ID, then we're going to tell them they're already connected. If there is an existing connection, then we'll log them in.

00:19 We also need to handle the case where there is not an existing connection, but the e-mail from the provider matches an e-mail we already have, we want to connect those and then log them in. We'll do that next. So the last fallback, if none of those things apply, is we want to get the user onboarded.

00:39 So let's grab our verify session from await, verify session storage, that get session from the request.headers.get cookie. Then we can set to the onboarding e-mail session keys. So verify session set

00:57 onboarding e-mail session key to this profile e-mail. So this is the thing that's been verified, is that we know that the user has access to this e-mail, because they verified it on GitHub. That's something that the remix

01:13 GitHub package does for us, is it filters out any unverified e-mails. So if there's an e-mail in this profile, this user has access to at least the GitHub account for that e-mail. So we are verifying that yes, they do have access to this, they can create an account with this e-mail address.

01:32 That way, they don't have to go through the whole e-mail verification flow that we built earlier. Okay, great. So now we have the verify session set, pre-filled profile key. So this is just like stick the whole profile into the session,

01:50 so that this is the part where we're like transferring this data over to the onboarding page through this cookie here. Okay, so we do have an extra credit that we can do. So we've got a couple of rules in our usernames that do not apply on GitHub.

02:08 So what we can do is add just a bit of an override here. So we're going to say profile. So all the properties from the profile are great, except the username. We want profile.username, and we're going to do a couple of things. So it's only alphanumeric characters. So we're going to say, oh,

02:27 and actually the username here could be possibly undefined. So we'll do a Elvis operator there, and we'll say replace. We want only alphanumeric characters, and we're okay accepting the uppercase alphanumeric characters. So we'll say uppercase A to Z,

02:46 and then we'll lowercase it ourselves. Okay, so we've got the replace there for those, and then we've got two lowercase right here. I think we need that for the syntax there. There we go. Right there. There we go.

03:01 Then we also need to just take the first 20 characters. So slice from zero to 20. Then if it's shorter, if it's like a two-character username, then we want to add additional underscores or something. So we'll say pad end three characters underscore,

03:21 and that should clean up the username for us in the event that they didn't have the right username or a username that doesn't match our rules. So it's just doing some extra stuff for the user so they don't have to worry about doing it themselves. Okay, and then the last thing that's also very critical,

03:38 just like this onboarding email session key, is the provider ID. This is the thing that they're going to be connecting their account with. So there is that. Now, we can redirect return onboarding provider name,

03:57 and we will commit the session right here. Headers and set cookie, commit that session. Right now, of course, this is a redirect. There we go. Okay, great. So with that now,

04:14 we've got to go over to our onboarding here, because we've got a couple of things we need to do. We've got to export pre-filled profile key. That can be whatever. I don't really care what the actual value is. That's why we make it a variable, so we don't have to worry about it. Then we can come down here and get

04:34 the pre-filled profile from the verify session. Here, actually, let's get the verify session from our verify session cookie. There we go. Then our pre-filled profile is going to come from the verify session.get pre-filled profile key.

04:50 Then we can pass that from our loader to our UI, just like this. So we're going to say, if the pre-filled profile exists, then we'll pass that as our payload for the submission, and then that gets fed into our Conform stuff. Okay, awesome.

05:10 And then the next thing we need to do is handle this sign up with connection. So we need to go to auth server to implement that sign up with connection. So we'll export a function called sign up with connection, and this is going to take a bunch of stuff.

05:27 Let's see if we can get Copilot to fill all this stuff in for us. Come on, Copilot, you can do this. It's really thinking. It's probably going to try and implement the entire function. Yeah, now we're talking. Holy smokes. All right, let's just make sure that it did it right. Okay, so we need the email, the username, the name,

05:44 the provider ID, the provider name, and the image URL, which is optional. Not necessarily will a user have an image URL. And then I like what Copilot did with this. We have the user email. So even though that's a string, and it'd be easy to say string, I like that it communicates.

06:03 Whatever the type for a user email is, because that's where it's going. And we did the same for username and name. Provider ID and provider name should probably come from connection from Prisma Client Provider ID. And the reason Copilot didn't use that is because we didn't have that imported. That's probably why. And then the image URL. Now that's not in a model at all.

06:22 We need to download that image. So let's see if Copilot did that for us. So here we're going to create the session. We've got our data. Here's the expiration date. And then we're going to do a nested create of the user. Here's our email and our username. Those don't necessarily need to be two lowercase right here. We should have done validation earlier,

06:42 so we can get rid of those. And then we've got our name, our roles. Yep, we want to connect to this user or make this user a user role. And then our connection. So we're going to create a connection for this user instead of a password, which is what we do right up here.

07:02 So we're going to create one with the provider name and the provider ID. But yeah, image URL, not quite right. So that's actually pretty good though. And then we select our ID and our expiration date and return that. So what do we do about the image URL? That's the tricky thing. So we're going to make a user image

07:22 that's going to come under, there we go, image. And this is a create. And then we're going to just await download image or download file, there we go, from the image URL. But the image URL could be undefined, right? So we're going to say that,

07:40 or actually I think we do that, otherwise undefined. Something like that should work just fine. Okay, great. So we can download the file and the user can get their profile image set up right from the get-go. That's awesome. Okay, so with our sign up with connection, then we can come over here and call sign up with connection right here.

08:03 Await, and this is our session. And we can delete that and boom. Then we of course want to bring that in from our auth server save that. And then this has been bugging me. What is going on here TypeScript? You're not happy about something. And it probably has to do with some syntax error, some silly thing that I've got right here.

08:24 So let's just figure out, we can debug this. Okay, we don't need that anymore. That's for sure. Oh, and that's it. So let's test this out. I'm going to click on sign up with GitHub and awesome. We went over to onboarding slash GitHub. So we're in a good spot there. We can say, here's our profile photo is prefilled. We've got our username prefilled and our name is prefilled.

08:44 Yes, I want to agree to the terms. Remember me, all of that stuff is, yeah, awesome. So let's create an account and boom, we've got our image was uploaded. Now we can go change it. We have notes that we can start taking all of this awesome stuff as part of that. And then of course we can log out. And then if I go to log in with GitHub,

09:03 I'm logged back in as that user. So we're in a really good spot. Let's review all the stuff that we did because there were quite a few things. So first of all, the key stuff here was our final case for this callback. So far, the last thing we're going to check for

09:22 if all the other things didn't happen. And we're going to get our verify session so we can set the onboarding email session key and the prefilled profile and the provider ID. And then with all that stuff, we'll commit that cookie and send the user over to onboarding and that way all of that data will be available on onboarding.

09:42 And not only is the prefilled profile key, that's useful, just helpful for the user, but right here for the email session and the provider ID, those two are critically important for getting the user signed in and verified from the verify session. So then in onboarding provider,

10:01 we have the prefilled profile key and we use that in our loader to get the user's data so we could prefill our conform form with that data. And then in the action, we have our verify session right here and that's what we use to get the user all signed up and everything.

10:20 We are able to sign up with a connection. We take the data that the user submitted along with the email provider ID and provider name. And yeah, that email comes from this required data utility which gets all of its data from the verify session. And so that way we know if it's in the verify session,

10:39 we absolutely know that it's in there correctly and that somebody didn't just like throw something in. So we're in a good place if it's in the verify session. So coming back here to our signup, we created the signup with connection function and this is gonna create a session

10:56 with an expiration date and a user with a nested create. That user is gonna have a nested create for the image and connect the user role and then add a connection so that the user can log in again in the future. And that is the whole thing. We've got onboarding implemented

11:15 with third-party authentication.