Current section: OAuth 6 exercises

Setting up OAuth Authentication with GitHub

Loading solution


00:00 To get started, let's create our OAuth application on github.com slash settings slash application slash new. If you're using github for your OAuth and this is where you're going to go if you're using Google or Twitter or wherever, they're all going to have their

00:16 own different setup. But it's going to be something similar to this. So here I'm going to call this Epic Web Demo and the homepage URL will be your website, but we'll just say epicweb.dev and then just a demo, you'll describe your app.

00:32 And then you're going to want to have a callback URL be any place where users can authenticate to your app. For us, we're just going to be doing this for local testing, so localhost .4000 and then register the app.

00:48 Okay, great. So now I get my client's ID. So let's come over here to our .env and we'll set our client ID, which is right there. And then our client secret, we're going to generate a new one here and right here.

01:04 We'll never be able to see this again, so you want to make sure you save this somewhere safe. And again, as with all of the environment variables that we have set so far in this app, you'll want to set this in however you set environment variables in your deployment strategy. So with that all

01:20 configured, then we'll go to our .env server and we'll add those here to say that these absolutely must be strings at runtime. And that way we also get type safety as well, which is kind of handy.

01:36 Now let's go to the auth server and we're going to grab RemixAuth's authenticator and the RemixAuth GitHub strategy. And then down here, we're going to create that authenticator. So const authenticator equals new authenticator.

01:52 And we're going to pass the connection session storage. Now you didn't actually make this because we've done this several times before, but this is just a cookie storage object. And so we're going to pass that to the authenticator and bring that in from

02:08 that import there. And then the authenticator is going to be used to create a new GitHub strategy. So authenticator.use And we're going to create a new GitHub strategy. And then we also are going to give it a name

02:24 called GitHub. So that's just going to be the provider name. So with that, we have the client ID, we have the client secrets, and then our callback URL. Now this is pretty common to make an environment variable that will be equal to the base URL

02:40 for your app. I don't personally like doing this, and instead I prefer to derive the base URL from the URL that is on the request. And this functionality is built into the GitHub auth strategy. And so we can simply do

02:56 slash auth GitHub and callback. We'll stick that there. Okay, great. And so then finally we have another argument here that's going to be async. And this is going to accept an object with a profile property on it.

03:12 And this is going to be the thing that we use to go from the OAuth2 profile to something that we can use in our onboarding form and everything. So we've got a bunch of stuff in here. We don't actually want to

03:28 create the session or anything like that. We're going to do that elsewhere. And so all we need to do is take this profile and get a couple of pieces out of it. So email is, of course, one thing. Profile, emails, yeah, Copilot, you're trying so hard to be helpful, but I don't want your help right now.

03:44 Value, trim, and then two lowercase because our emails stored in our database, they're all going to be lowercase. If there is no email, that's possible that the user might not have an email. Then we're going to throw a redirect with toast. And we'll

04:00 redirect the user to slash login with a type error and a title, no email found, and a description, please add a verified email to

04:16 your GitHub account. There you go. Okay, great. So now we know for sure that they have an email address. Then the rest of this we just need to make sure we return the profile that we want to have accessible wherever we're trying to authenticate this user.

04:32 And this will only be temporary during the onboarding flow anyway. If you think about the onboarding flow, we ask the user a couple of things like we need their username, we want their password,

04:48 we want their display name, and actually when a user creates an account, we also want their image, their avatar. We don't do that during onboarding, but it would be cool if when we create the user we use the image that they have as part of their

05:04 GitHub profile just to save them some time. And so we're going to do all of those things. We'll return the email. We also need the ID on this provider. The username is going to come from the display name on the OAuth spec for this profile.

05:20 That's where GitHub puts the username. And then we have the given name for their name, and then the image URL, and that will be plucked off of the photos. And that takes care of our GitHub strategy.

05:36 So we can't actually go through the whole flow yet because we need to set up the other routes, but we're in a pretty good spot here. Now one other thing I'm going to do here to make all of this a bit more type safe is I'm going to say that this authenticator has

05:52 a return type for these profiles that we return. So what the authenticator is going to store inside of this session storage should match the return type of this. And to make that type safe we're going to actually make a specific

06:08 type that I'm going to call a provider user. And that provider user is going to have an email, ID, username, a name, and an image URL. Now the name and image URL are actually optional so we'll make those optional there. And then we can use the generic. And what

06:24 that will do for us is if I misspell this then we're going to get a type error that says, hey, hey, you said that you were going to return something and you returned something else. That's not good. So let's review really quick and then we can move on to actually getting

06:40 the flow going. So first we created an OAuth application and we got a client ID and we got a client secret. Don't even try this one. I'm going to delete it as soon as I'm done recording these videos. I mean, feel free. Knock yourself out. But yeah, so in ENV

06:56 I have the client ID and the GitHub client secret. And then in ENV server to make this a little type safe and run time safe we're validating that our process ENV has all of those environment variables.

07:12 And so then in our OAuth server where we're creating this authenticator and then using this GitHub strategy, this Passport JS inspired API here for that, we're going to pass those environment variables along with our callback URL and

07:28 that callback URL matches what we configured in here. And then we get the profile. So assuming that the whole OAuth flow works okay, we should get the profile in here. We're going to resolve or go from that GitHub user profile into something that

07:44 we can use for onboarding. That includes the email, the user ID because we're going to need to stick that GitHub ID in the database, the username, name, and image URL. And with that, we should be ready to get the actual

08:00 OAuth flow going. So let's continue with that.