Let's Build a Discord Events app with Remix

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
is that a stream deck that you're poking right now yeah yeah yeah all right i think we're i think we're live so uh yeah thanks everyone for being here alex thank you so much for um being someone who's way smarter than me and uh able to be waving at everybody thinking through uh thinking through you know a lot of stuff that i just don't know yet so i'm really excited to learn from you and uh i hope that um yeah i hope everyone everyone is both uh here in discord and on twitch um so yeah uh let's uh let let's start no further ado let's uh let's go tell us about yourself before we before we go though super i'm alex i really like making spaceships you can find my spaceship project at thoriumsim.com which is also a remix website um and that's a video game that i'm building in react i work at a company called ui.dev where we teach people uh how to be better developers i made the typescript course for them so if you're interested in learning react typescript anything like that check out ui.dev that's the website and the name of the company and we've got exciting stuff coming along pike too so today though we're going to be talking about remix which came out just a couple of weeks ago in 1.0 and became open source at the same time which is awesome i assume that everybody has a rough idea of what remix is if not check out the docs they've got a really good explanation of how it's great and i'm sure that will just keep getting better as time goes on you can think of it as a framework that is similar in scope to it's when compared to rails uh actually uh i don't know what marbiano's that that's your name right mariano he wrote martin okay martin wrote a really great post about uh how react sorry how remix is similar to rails recently so um if you look for that i'm sure you could find it uh retweeted by the remix account recently really great uh comparison i'll grab that and post it so my goal right now is just to speed run through getting remix set up and getting it deployed as quickly as possible and then we're going to add the discord integration so i'm going to start by grabbing this npx create remix i'm going to come to my terminal go into my projects folder and run that this is a nice little setup for getting remix running i'm going to put it in the lunch dev i'll just call it lunch dev and i'm going to use the remix app server the reason for this is because it's going to create a long-running node.js server which makes it possible for me to build a uh a bot in the future bots aren't really possible with serverless since they have to be listening for message events and so you need to have a long-running server so you'd want to use remix app server or an express starter for that but then or fly um but they also have great serverless support on aws uh netlife or cell and cloudflare workers so we'll use the remix app server because it's easy and then i'm going to do it in typescript sorry if you don't know typescript we won't be doing a ton of stuff with typescript but it really helps me to not screw up and we're going to run npm install now just a quick point of clarification in the times that i've gone through some of the documentation and remakes in the past um the documentation is actually written in typescript is that right uh i can't remember i it's all the same to me at least when i need to go to some of the documentation here yeah there it is and yeah it is written in typescript okay so cool i mean the typescript just kind of melts away you won't be worried about it too much like this right here that's typescript but everything else here is javascript so it's not going to be too mind bending cool okay so i'm going to go into the lunch dev folder open up visual studio code and then close my terminal because that's all i ever use it for it's just opening visual studio code um and i'll just bump up the size there a bit so everyone can see how's the size for everyone looks good okay the next thing that i'm going to do is get this deployed asap i'm going to use a service called railway you can think of it as heroku for hipsters so i'm going to start uh we'll provision postgres and that's going to start up a database for me and in the meantime let's just start running the dev server so i'm going to run npm run dev and that's going to start it up it's up i can go local host 3000 and here it is that's the basic remix app they've got some demos here but we're not going to worry about those in fact they recommend that you just come here and nope don't want to delete the whole routes folder just the demos folder and we'll delete that that's a good tip so to start off we're going to need a login page and we'll also need a log out route and that should be all that we need for now um so the way that remix works is you export a default uh react component and gosh i should really get tailwind installed here too um i've got by the way just so everybody knows i have github copilot so it's going to be coding most of this today so there's the email form and there's the password form that's the big takeaway if you want to learn remix button just just get up co-pilot uh the great thing about remix is this right here will work all i have to do is um change the form so that has a method of post we want to post our password so that it's actually secure because if you put the password in the get parameters that's just silly and then um i also want to export what's called an action this is the code that runs on the server every single time you perform a post put or delete request or maybe a patch request to i don't know anything but get um with those http verbs so const action as an action function i'll import that from remix that's just some typescript magic that makes it so i don't screw up i'm going to get the request and then from there since i'm using a regular http form i'm going to pull out the url parameters from that uh i can't remember the best way to do this so i'm going to highlight that no copilot doesn't in this case um i thought there was a helper form data there it is so this gives me some form data so i'm just going to call this the body and then from there const email equals body dot get email and that's async the form data is async you're right thanks kent we got a ken c dodds in the house so that means that this needs to be an async function and this needs to say a weight and just typescript tells me that this gives me a form data entry value which if we dig in here uh oh i'm diving into the typescript internals now that's not good we'll just ignore that anyway it's going to be a string um we'll we'll need to assert that it's a string but it's a string and then the body dot get password so that gives me my email and password and then from there we can actually start doing stuff with this so by now my app called soggy haul which is great uh is all set up so we'll just leave the login route for right now i'm gonna shut down the dev server and run railway link and then my project id and what that's going to do is oh hang on that's that's not working right i can't find that project maybe i'll just try railway in it and see what that does oh that's why i need to run railway login okay so you have a railway browser running in the cloud somewhere you're locked i don't have a railway app yet oh okay okay okay sorry i'm logging into my railway account right now okay gotcha so now i need to open up this url hit verify because it's true it's just the usual device oauth flow and now i'm logged in as alex so now i should be able to run railway link and it's going to link that with my link back i'm getting an echo now can somebody please mute themselves okay so now i should be able to come here here and i guess i'm linked yeah it looks like my postgresql in there so i'll say railway up and this is going to package my app up send it up to the cloud and deploy it and it should be all set um so i'm just going to let that go while we get postgres setup so uh oh we need to connect this is some secret stuff here um so i'm actually going to move this over to a different screen while i set up my environment variables uh now this is something that i've um that that's kind of interesting to me about remix is is that or i guess specifically like this kind of like development environment where you have kind of like a cloud back-end type of stuff just in general like sometimes you have to have some like you'll oftentimes have to use like their cli to actually like connect to data is that like is that correct am i thinking are you talking about are you talking about remix or railway uh well like railway right so like railway is your database and you're not running that locally right no i'm not okay um and so so that's the thing um they give me this database and they give me just a regular postgres connection url which i can use with any uh package any orm that supports postgres so i'll get prisma set up real quick okay cool and i've actually so here's this back again i've actually taken my dot emv file and put it in a different uh vs code window off on my other screen so we don't have to worry about that oh fancy um i really should have set up i realize now i should have set up more of this earlier but that's okay um i don't want to download the starter project i just want to go there's the quick start oh that is the quick start um we'll start from that to an existing project uh-oh we can figure it out alex i'm sure we can between the two of us i think we can do it now that you're here i just feel so much better okay i just needed to change that really quick gotta install the prisma client so i'm going to run npm install prismaclient here probably install more stuff later and then i'm going to run npx prisma generate which is going to go to my prisma database in railway grab all of the tables that we have and set up all of my fancy stuff the thing is we don't have any tables yet because i haven't created them so let's come over here to the data we're going to create a table it's going to be called users yeah sure you've done some scary stuff right now alex uh databases are always wrong okay i know right um i just need to remember what needs to be in the database so i'm actually going to come over here this is an app called postico that lets me connect to my thorium sim.com database oh wow cool and i'm going to look at the table that i have there oh shoot that's go away i shouldn't have done that because i do my own auth and so you saw a little bit of some password hashes there oh well [Laughter] this is always a really funny thing people can have fun with their rainbow tables on your password hashes i i know right you're probably fine probably um but that's the thing is we don't actually need to have those columns in our table i'm just going to have like a display name um that's going to be text sorry text we'll have a profile picture url that's going to be text and we'll have uh probably should have email just in case we need it sometime in the future that's gonna be text and then i'm also gonna look at the connected accounts table which i'm doing some like crazy sequel joining stuff but for oh crap i'm doing it again those are secrets don't look at my secrets what am i thinking okay in order to connect the account we need to have the access token which is going to be a text and we need to have a refresh token which is also text these are the oauth tokens that are provided by discord so we're just going to assume that people only log in with discord and when they log in discord is going to give us an access token or it'll let us get an access token which we can use to make requests uh on behalf of the user to discord now if you were to do like a multi-oauth type of setup would you just prefix these so you'd have like discord access token and discord refresh token and then have like maybe like a github one etc so i can show i can show you this this is actually this is what i should have done to begin with just showing you the structure not the contents so this is the table that i have for any connected accounts so i have a type field so i have the user table and then that connects to this table using this ui user id um foreign key constraint which is a sql feature that allows you to connect two tables together that's how it becomes relational the type field is going to be whatever the provider is so i've got discord and uh github that i currently allow and then the access token and refresh token which are part of the oauth spec although you don't have to have a refresh token github allows the access token to last forever whereas discord i think only lets it last for like an hour and then you have to use the refresh token to check with discord to see if that user should still uh or to see if that app should still have access and then i have a created ad expires at and account id which is the id that discord uses to store that particular user so i'm going to say discord user id um and then this shouldn't be text this should be a date so you could do it the way that you said where you have discord access token refresh access token and then sorry i'm doing weird i'll do it that way weird casing casing is the worst it is i wish there was just a universal rule for casing but there isn't i mean they should just look into my brain and know exactly what these things are i shouldn't even have to name these things they should just be like numbers you need copilot for uh you know everywhere on the web right so we'll create our users table here and that should be good enough for now um and now that we have that i can come over here and run npx prisma generate hit y and it's going to go blue and oh i need to create a schema.prisma file hey alex i missed that could you could you say what what's it going to go again it's going to go bloop bloop it didn't go blue i i like is that should i be looking for that when i uh run that command in my terminal [Laughter] okay um i'm gonna go back over to my cheat sheet and look at the schema.prisma file that i have there eric has a fish emoji in in chat which feels very appropriate alex i think if you run your npx prisma init that'll scaffold out the folder and the schema for you and then then you can run your um db poll that's why we have helpful people here so yep this is exactly what we need um and now i can run npx prism generate which is going to do some stuff i don't have any models oh i think you have to run db pole first it's a prisma db pole and then then all right i just have for those of us who are new to uh to prisma in general so the first command is creating a like a what for us when we did the prism okay so so it creates the schema.prisma file which uh just scaffolds out this schema.prisma file sorry so we've got the generator which tells me what provider i'm going to be using in this case it's prismaclient.js they also have uh i think a python provider i mean this allows them to use the same prisma command to generate uh code for any environment okay down here i'm specifying my data source in this case it's a postgres database and the url the connection url is in this environment variable that you're not going to see because i'm a good developer i keep my secret safe actually true story i'm going to go through and delete all of the connected accounts because that right there's actually a real vulnerability in fact i'm going to just do it now let's just come over here and force all these people to sign in again hopefully they don't sign in they may be getting a an email today there was a breach i was live streaming exactly well and it's it's only like let's see two of these are uh my test accounts and yeah so nothing to worry about everything's fine still embarrassing okay so now that that's taken care of uh i can run that npx prismadb poll what this is going to do is use the database url that i set up here go out to railways database i could do the same thing on a local postgres database but i like living on the edge as you can already tell and what that did is it pulled down the schema for my user's database here and has all of the information that it needs to know how to generate the typescript types for that so now i can run npx prisma generate like that and what it did is it created a code in yeah we'll do node modules come on um at prisma that is not what i wanted sorry i'm using fig as well because i like living on the edge and it's just not working right now guys just too much edge i'm pretty sure somewhere in here is where it generated yeah this is all generated by that prisma generate command and i'm sure if we dig in enough we can find that uh the user stuff i don't know exactly how it works but i do know that it shoves it into the uh node modules folder wow this is wow okay let me just check messages all right so we created a database we uh we're using prisma to like pull the schema of that database and then we generated that monster of uh like of a client for ourselves is that right and now i can import uh actually let me just make sure i'm doing this right db and so now effectively our app is aware of the database schema like through those types very cool okay i'm going to demonstrate that in just a second i just have to find okay so what i did in my other app is i created a helpers slash db.ts or no i said prisma dot the dot server.ts extension makes it so that remix is never going to bundle this in the client it's only ever going to bundle it on the server and so now i can just import db here and use it anywhere in my app so here in my login i can say await db dot users dot and then i can create a user i can create many delete whatever okay dang look at this yeah so we actually don't need a password in this case i had uh co-pilot do all of this stuff for me but that was probably more of a flex than anything because we're just going to log in with discord it was an unintentional flex i promise you're just kidding everybody turned away by github co-pilot i'm honestly i i'm honestly curious like how much code is going to go down that route of like actually i was just carried away by the co-pilot i uh i didn't even need this feature but co-pilot did it i absolutely i have done exactly that before yeah okay i'm just installing react icons right now so we can make this just a little bit nicer and i'm just going to do some coffee pasta because i'm a lazy cuss so i'm going to create a components folder and i'm going to paste in the sign in button so this is a button that i made for my other site that just takes care of some things for me i pass it a provider which is going to be either discord or just discord a title which is what it puts into the button class name so we can style it nicely and an icon that shows up nicely and it is going to use github forms to not github remix forms to perform this action and it's going to make that action against this route which we're going to set up soon but the idea is you click this button it's going to redirect the user or it's going to perform a post request to this route this route is going to take care of all of the auth communication stuff with discord which we'll set up next and while that's happening it's going to use this use transition hook which is part of remix that lets you know whether a form has been submitted or whether the user is navigating to a different page and in this case what i'm doing is if we are in the middle of performing some action and or some if we've submitted a form on the page and that form has been submitted to this url which is the url that's being submitted to then we're going to show the spinner and otherwise we're going to show in the show the sign in text so that gives us just a little bit of loading state there okay so just probably this used transition is not the react used transition that's coming out in react 18 soon yeah this is part of remix okay got it you can use it today so this transitions between this the the states of the the form kind of as you get that data then uh yes okay in this case it's just whether it's loading or whether it's not locating okay that's what we're getting here so we're going to say the provider is discord and the title is going to be discord icon is going to be fa discord i can't remember if that's supposed to be it's just a react node so that means i need to make this like that and then we also need a class name which i'll just leave blank for now because i don't have tailwind installed yet which is really sad and we don't need these guys either are you missing it right now don't need that okay um because all of that other stuff is going to happen inside of our other route that i'm going to change right now i'm just going to make this api connect account and then down here api because i was doing something weird before and now i'm not doing something weird okay so now i should be able to run the app i'm going to run npm run dev that'll start it up come back over here now which starter did you um use again was it the netlify starter no i used the remix dev server starter which is built on top of express and again the reason i did that is so that we can add a discord bot in the future which you can't do with serverless gotcha okay cool cool that makes that makes a lot of sense but if i go to the login route we've got this very ugly sign in with discord button and when i click that it's going to try and take me to this api connect account page but it's not going to show me that because uh doesn't exist um the remix folks in the audience really want me to point out that oh look this error boundary is so cool and it's amazing how it works go watch kent's stream or ryan's stream with jason they talk about that in much greater detail do you have a best link for that do i'm posting that yeah throw that in the discord yeah yeah i'll find a good link for that whenever we show this for the first time for anybody we like go nuts over how awesome it is that you have contextual error boundaries i think probably the home page you scroll down toward the bottom uh yeah that explains it pretty well yeah for sure and it's a it's a really cool feature it's just not important to me right now we got things to do we got we got apis to connect for reals and yeah this is this is not going the way that i expected it to go but like we're still having fun right i feel like that's every lunch stream is uh not where we expected to go but we went somewhere okay so i'm using this really slick i'm going to close the terminal because i don't think we need it anymore i don't think we need any more dependencies i'm using this really slick feature of remix called resource routes which is basically the same as next js api routes except you can respond with any type of data that you want in this case i'm not responding with any data i'm just redirecting you to a specific url um so let's walk through this code that i just copy pasted because i am a lazy cuss oh i need to put in this uh app url here so let me open that in my dot n and add that environment variable it's just going to be http colon slash local host colon 3000 since we're in development but when i deploy this to production i need to make sure that i put that in as in the environment environment variables we also need to add in a cookie secret which is uh what i'm using to create uh an oauth token basically the idea is i create this hash that only my app knows and i use that to make sure that these requests coming and going from discord are actually coming from my site and not some other site that's trying to steal my users data so that's just a security thing the cookie secret is just a long string you can hear me typing in this is like very high entropy right now i don't know if you can hear all the clicking but we'll check it really quick uh just open up node and say that string.length oh it's 149 characters my friends that is security right there just have to take my word for it the last environment variable that we need is this discord client id so let's come back over here and come to this discord developer portal i've already created an app for lunch.dev in the discord developer place and um what i need to do is put in the client id that is right here for this app that i've created this is what i'm going to send to discord to identify my app so they know who is trying to ask for access to discord users um in the chat i'm just going to pop a url oauth.com that's it all of this this this little rigmarole that we're doing with this court is part of a spec called oauth that um it it it's barely a specification but it it it's more a set of guidelines than rules where basically you're able to communicate with third-party providers and get access to information on their sites on behalf of their users which is exactly what we want to do now to clarify client id sometimes an app will offer a personal access token and i think that when i was originally thinking about this i was thinking like oh i could just grab my personal access token do this thing and like you know we'll just use my personal access token that's not really like a great way to build services like this and so the bot is basically a way for like it's like an additional party in this whole thing that's like okay i'm gonna control the um like you have to like authenticate as a person through this bot instead of just like throwing your personal access token in there is that right bingo okay cool okay yep and discord doesn't even offer personal access tokens excuse me personal access tokens in the way that uh github does okay sorry did i say github the first time discord doesn't offer personal access tokens github does and i actually do use a personal access token on my thorium sim.com website to do some administrative stuff um but you're right it's much better to do that with something like oauth okay especially when it's random people like you and everybody else who's logging on yeah so exactly we've got our client id here and then the way that this works is i send a message to or rather i redirect the user to this url right here which discord provides to authorize oauth 2 connections and we'll see what that looks like in just a minute and i'm pat i'm adding on some params which i'm generating here that include the client id identifying my app the launch dev app a redirect url which is where discord is going to redirect the browser after the authorization has been successful i also passed in a scope which is all of the different permissions that i'm asking for as part of this uh oauth rigmarole and that's just a space eliminated it is a space to limit it to yes okay i think other oauth specifications do it with differently with commas and such okay again it's it's more guidelines than a rule but these are all the different permissions that you can get and you can look in the documentation on discord to see what each of these does i actually don't need all of these um i think i'm going to one thing to call out real quick if you're not familiar with uh kind of discourage internal tournament for things what you and i might call a discord server a set of channels with a collect group of members um discord internally api wise the guild so anytime you see guild think disorder yep thanks for the question i'm actually going to delete messages red i'm going to ask for identify which tells me who you are it gives me your profile picture and your name email is a separate thing that you need to ask for i'm going to ask for guilds so i know which guilds the person is a part of and i'm going to ask for the guilds.join permission so the idea is when they click this button i should have permission to add them to a guild and in this case i just add them to the lunch.devguild or lunchdev guild whatever uh sorry i work for ui.dev and so having that dot in there is you get used to it anyway we've got this state thing here which we created up above that's just going to generate a random string that i can use to identify folks and i'm passing that here and then i've got the response type code which is part of the oauth spec saying i want to get an access code for this user when you redirect them back to this oauth discord place okay so with that in place and with our sign in button pointing to api connect account i should now be able to come here here go to the login page hang on i was doing this and it returns null oh because i'm not okay it's it's because i did it with uh a post request because i'm using an action here i could even make it more explicit by saying if request dot method equals post but i'm not going to do that because it'll only ever be post right so i'm going to click sign in with discord again and we are now on discord's url i don't know if you can see that there but it says discord.com blah blah blah and i'm getting an error it says value blank is not a snowflake i'm glad you got this error because that's a great error no and i know the reason why snowflake is actually a term for a very specially formed unique id i think twitter invented the concept of snowflakes so it's not like talking about millennials in gen z that can't handle being woke or whatever no this is an actual technical term the reason why is because i changed my environment variables without resetting the server so now i can come back here we'll go back here click the button and it still is complaining because the redirect uri is undefined and the client id is empty why is that very very confusing um let's go to the docs yes remix conveniently has this search and we're going to look at server environment variables and aha they do not they do not have dot m for you already does npm ad actually work let's try it whoa it's like yarn except npm wow what when did that happen i i did not know that that was a thing yeah i guess so today i learned so i'm gonna go to my package.json like it says in the docs everybody read the docs it's important i'm gonna come here to the dev script and i'm going to paste that in and now i should be able to run npm run dev it's going to execute so node r just runs a little script before it actually runs my node program it's running for config that's going to go to this dot m file that you're not going to look at because i'm a good developer that don't show my secrets and once it loads that it's going to run the remix dev command and by doing that it's going to put the environment variables in dot m into my environment so now when i come here go back hit this button it actually takes me to the discord page [Music] so now it's asking me to sign in and discord is so great because they've got this app where i'm already signed in and so if i have the app on my phone i can hit scan qr code and then after i scan it it shows hey that's me and on my phone it says are you sure you want to log in on this computer i says yes log me in and then it logs me in like instantly it's so cool i love it [Music] this right here is the oauth authorization screen this is where it says this person wants to access your account or sorry this this app wants to access your account speaking to me alex and it tells me all the things that it's going to be allowed to do so i could get i get the username avatar and banner email address i know what servers are in it can join servers it's not going to be able to solve a mystery with scooby and the gang bummer dude oh well i click the authorize button and what this is going to do is redirect my browser to back to my app to localhost 3000 with a specific url with some special magic voodoo that we'll look at in just a second so it's not found because we haven't created the oauth discord page yet but we do have this code here which is the code that i asked for remember back here sorry back here when we said response type code this is the code that i wanted oh and that state thing that we generated earlier that's here too so we can verify that this state actually was signed by my app using crypto up here to make sure that it was my app who requested this user sign in and not some fake hacker app okay so now that we've done that i'm pausing for just a second to copy and paste stuff and people can talk in the meantime ask questions now the so the screen that we saw with the permissions those are all set by this scope right here so if we had if we were requesting more permissions we would see more of those green uh green check marks exactly request all the permissions if you really wanted to can we request scooby-doo or that's just no that's just discord being their delightful selves okay so just for convenience because i don't know what i'm doing and it's easier to just copy and paste i am npm installing discord js and discord.js rest which should be nice little helpers for me um i also have some other stuff here for uh authenticating the user and creating a session so the idea is you don't want your users to have to sign in every single time they come to their app to the app you want to give them the ability to stay signed in for an extended period of time and that's what sessions do for us so this is the idea of a session in abstract is something that's been around forever php has it rails has it i'm sure remix has it and they have some nice little helpers for helping you with that so i'm just going to do some more copy pasting and we'll take a look at it together but i don't want to have to write all this code myself or have co-pilot do it because i am not cruel to bots oh and i've gotta actually copy that okay so where was where was this created i created it in a folder called auth because this is where i'm just handling all of the authy stuff you could put it anywhere you want in remix the only special folder inside the app folder is routes gotcha okay so this isn't everything else do whatever you want gotcha so this isn't a route so this is this is this is what i'm learning right now so remix is controlling all of this stuff but this isn't a route so it's not going to have a page but it is going to have access to all of the like remixy internals um yeah i mean this is just a utility exported by remix that i can use to do okay and again look at the docs for more information about sessions specifically in this case i'm using their cookie session storage which creates a session on a cookie um i i don't know exactly the mechanism uh whether it's like a jwt or something but the idea is if i have access to this cookie then i can recognize that um this user is who they say they are like if this user gives me this cookie then i can i can be fairly confident that they are who they say they are cool um so i'm naming the cookie underscore session i'm using same site lacs which um does something about cross-origin cookies i'm not going to get into that too much pass makes it so i can use it anywhere in the site it's sent for every page that they visit http only makes it so you can't access this from within javascript which is a security feature because if you could access it from within javascript and you had a cross-site scripting error of some kind people could try and get these cookies and this makes it so they can't from javascript okay this secret uh makes it so that it it signs the cookie so that i know that the cookie was actually created by me so people can't create fake and remember the cookie secret is 149 characters long so uh it's secure in production which means it's only sent over https connections and the max age is how long the cookie actually lasts in this case it's in uh seconds so 60 seconds is a minute 60 minutes is an hour 24 hours is a day 30 days is a month got it um and that helps i imagine that that helps like doing the numbers this way helps contextualize them versus just having whatever the sum or the the result of all of those multiplications is exactly exactly uh it's it's just a little thing that i do so this session storage that we create here gives us just three little utilities yeah gives us just three utilities get session which gets us the session from cookie commit session which lets us save the session to a cookie and destroy section session which destroys the cookie cookie monster is sad but what you got to do sometimes so now that we have that in place we can create the excuse me create the authenticator and for that i'm going to use another utility called remix auth which is a whole bunch of different off things um it gives you a bunch of different ways of signing in in fact let's look at the docs for remix off just for fun see what they offer sergio he's i think he's a peruvian developer and just has so many amazing uh things that he's created for the remix ecosystem um is sergio here i don't know that i saw anywhere i don't think i saw them okay anyway um but the idea is you create a session storage you set up remix auth it's very similar to passport js but it works across all of the different platforms that remix supports including cloudflare workers which is not a uh node environment um martin just said that sergio lives in peru but he's from argentina so anyway energy is awesome um so what we do is we grab an authenticator from remix auth that's a class that you can use and you also use a strategy which uh is a different way of signing in and then do i even do i actually need this let me check and see if i actually need this or if i can just plop stuff onto the user yeah so i i only use this for checking to see if somebody is actually logged in so i don't actually need this but remix auth is pretty sweet just just saying um just just for fun let's go into the strategies folder it's easy to make your own strategy but they already have one for oauth2 so i probably could have saved myself a lot of hassle uh local which is like uh username and password google github uh basic http shopify off zero so save yourself a lot of time by doing that way um and i'm just gonna find i'm gonna run npm run dev again and then close this so that you have a little bit more room and um [Music] all that we have to do is just change the session key so i'm just going to make it a so with remix auth you kind of set this up like once but then you could it seems like you could pretty easily add additional providers once you've gone through this setup uh right we're not using remix auth right now just to be clear but yes you can use multiple providers at the same time i'm pretty sure okay you just when you do the login process you say which provider you want to use so you could say oh we're logging in with a username and password right now or oh we're logging in with github right now and it'll use the appropriate strategy for what you ask okay okay so let's go through this notice that this is a hang on i gotta check one thing first oh i'm doing janky stuff go away okay this is a loader which means it's going to run for every get request okay and what we're doing is pulling out url search params but i don't actually no i do need that because what we're doing is getting the error and error description which come from discord if something bad happens in the error uri so that's how discord tells me that there was a problem i'm getting the state which is the same value i passed earlier in connect accounts i'm getting the code and then type is something extra that i added for my site that i copied from but we don't need that and we're just parsing that out of the url parameters i'm turning it into json and we don't need this rest either next we pull our session out by grabbing the cookie from the headers and then i check to see if there's an error and if there was no code provided i throw errors in both of those cases then i regenerate the state uh using the same method that i used before and if the state is not what i expected then i just say that the state wasn't expected that means a hacker tried to do something evil ah okay i have this switch on the type for doing github versus discord i'm just going to get rid of github because we're not worried about that right now and then i'm going to come down here to the bottom and make sure that all of that is cleared out too okay then so we've got the code the next part of the oauth process is going to discord and taking that code and exchanging it for an access token and a refresh token i do that by making a post request to this discord api uh using xww form url encoded and i just hard code the url in here but we can see we pass it the authorization so like i say the grant type is authorization code because i want to get an authorization code oh that's that's what i'm passing in yeah and then i pass in the code i also have to pass in the redirect uri which i used earlier which i need to fix this is now oauth discord that i pass in my client id and i also have to pass in the client secret this is the way that i uh tell discord that i'm actually the person in charge of this app so i'm going to have to grab that as well from over here that's still in the oauth section and i can just click copy and you'll never see it hahaha because i'm a good developer now this is something that you're not going to want to commit to the code base right so you're going to put this in some type of like credit environment variable oh watch this git ignore already does not have.him ignored so um when i run railway up it ignores everything that is ignored by git ignore okay and so it's not going to upload these dot end stuff to okay railway even though i'm going to tell railway the same stuff anyway so that's taken care of um discord sends back the access token the refresh token and the expires in values uh oh it looks like i need to install another module because i am lazily importing it so that and then npm run dev again and hide this oh accept i've got to change my module flag that's a typescript thing so i've got to come here and actually add a module flag oops module thank you and i'm going to use common js the reason for that is because the remix server uses common js um they don't support esm quite yet but they're working on it and besides this no emit thing here means that typescript isn't even going to worry about compiling my code anyway it's just doing the type checking so this doesn't affect the output bundle since remix bundles my code for me okay so this right here is just a helper that helps me generate um rest apis for discord you could write the rest apis out yourself in fact if i were to console.log discord rest uh actually no yes if i were to console out the results of this right here it would just give me a url nope it wouldn't nope these are two different things okay if i were to console.log this it would just give me a url okay discord rest is the rest api sdk that discord provides or no i think this is a third party thing but the idea is i give it the version of the discord api that i want to use i set my access token up here and it gives me a little class that i can use to make api calls so in this case i use this to make a get request to oauth to current authorization and that gives me the current user who is signed into discord i also have to make another request to the users route to get just a little bit more information i'm using some typescript stuff to just um specify what the results of these are if i wanted to be more safe with typescript i would do some type narrowing to make sure that these were actually the objects that i say they are but i'm a lazy cuss developer and i know that it's going to be that way because discord doesn't break promises okay and you actually have a course on typescript if someone wanted to learn about type narrowing right i i do wow michael's here my straight man yeah on ui.dev i wrote the course on typescript just for ui.dev not for everything but people tell me that it's a good course so nobody's told me it's not a good course like with that evidence it has to be good right uh i no i really enjoyed making it i learned a lot from making it and i think you'll learn a lot from taking it too um so at this point we've got all the information we need we can finally create our user object so i'm going to say all this stuff is just extra now but i'm going to say db or i'm going to say await db.users.create and then i have to put in all of the information that i want to create in this data field so we've got the access token which is access token fresh token uh discord user id which is going to be discord.user.id super uh we've got the display name which is going to be more discord user dot username email which is more discord user dot email and then we need the expires at two i'll move that up here so that it's with the other token stuff and that's gonna be that buyer's ad expires in come on guys profile picture url i think that comes from yeah discorduser.user.avatar and then the id is auto-generated okay so far so good any questions coding with copilot i love this so this is going to create the user shove it into the database so we can get rid of that we can get rid of that and we can get rid of that and that and all of that awesome and we can get rid of that great um actually i do want to pull out a couple of objects so if you are relatively new to javascript here's a fun tip if you want to just pull out a couple of properties and not have them included in an object you can say const the properties you want to exclude like the access token the refresh token refresh token sorry guys and uh expires at actually isn't important so we're not going to include it and then use a rest to get the rest that gives me we hover over this you can see it gives me the id the display name the profile picture url the email and the discord user id i don't know why those aren't uh cased the way that i wrote them oh i know why it's because prisma expects me to use camel not camel casing uh snake casing oh interesting the whole time so was that so is prisma changing that from your database schema it's it's pulling that from the database schema okay and yeah because if i recall correctly i could be wrong about this don't quote me but it's possible that postgres column names are case insensitive okay prisma just to lowers all of them gotcha so you had in the ui you had used the camel casing but prisma is like with its knowledge of how postgresql works uh just to lowering the all the names yeah okay so we've got what i'm not sure about that on my website i use yeah we're not going to dig into that right now because i got two minutes left and i really want to make this work okay okay so really quick um i'm doing some extra stuff with discord rest to add the user to a specific guild in this case the thorium send uh discord guild which hit me up if you want to join the thorium sim discord guild or go to thoriumsim.com and then this right here gives the user a specific role so hang on hang on hang on am i oh hang on i'm i'm trying to move this chord over here am i so privileged that i am able to create new roles no dang it if i could create a new role i thought you could i'm sorry i really would no i can't um do you want to hear do you want me to make one real quick uh no i think i think because i would have to figure out the role idea and stuff i don't have time for that i'm just going to uncomment these and then here at the bottom i'm using this session.flash thing which allows me to add a message to the session which only lasts for one read so as soon as you read it it it gets removed from the session which is great okay then at the end of all of this i'm being redirected to the profile page which doesn't exist so i'm just going to redirect to the home page and it uses the set cookie header to commit the session which puts the user that i created onto the session with this specific session key i'm going to actually change this this is the user session key so that's the whole process all together and we will know that it works if we get a user put into the database so ready so we'll see a user put into the database and we'll get redirected to the uh the root route so this table is empty yep um here's my local host i'm gonna go to slash login here's my ugly button i'm gonna click my ugly button it takes me here with all of those scopes that i specified i hit authorize it redirects me back okay and then i refresh the page and the table is empty because something bad no uh it is an unexpected value six zero four eight zero zero aha i said expires at expires in that's the problem expires in is an interval but expires at is a date so i'm going to say dave interesting dot now uh plus actually it not new date plus expires in i forget if it's seconds or milliseconds though so it probably a second so i need to multiply this by a thousand okay wow okay okay yep and now it's complaining because it needs to be a date perfect there that'll take care of it so with that we're rebuilt we can come back here go to login click the sign in with discord button click the authorize button we come back here there's nothing changed click the refresh button yeah so um at this point uh we are overtime so anybody who wants to continue partying can continue partying uh because i am going to uh party yeah we're going to do some shenanigans oh do you want to sign off michael yeah no i think that's i think that's great so we'll call it we'll call quits on the um the the streamer twitch um and then once we're done streaming that'll give us um an opportunity in discord for anyone who has um questions but doesn't want to ask them on stream to ask them um so that's how we'll that's how we'll do that just a quick recap though um you know in this hour what we were able to do was generate a remix app kind of uh set up a database on railway um integrate prisma for like for interacting with that database and then getting all this really cool um uh uh uh autocomplete um in type checking into our remix app and then uh we were able to use loaders um and uh forms to actually handle the uh the request the form as we like you know clicking that button it's gonna do the oauth dance and whatnot we use remix auth did we did we actually integrate that i no we didn't okay i said i might need to and then i didn't okay cool so so you did you handle all the auth um on your own and then we were able to use the discord api to actually like access the fields that we need from that and um and actually put an access token in the database um did i miss anything sounds good to me okay cool um yeah sorry we didn't actually get to doing fancy discord integrations but i am going to be able to show you my discord username and uh profile picture in just a second okay cool yeah let's see that because you know that's once we once we get there i mean the rest is just kind of accessing the api and pulling off the stuff we need exactly so remember i put my user onto the session using this user session key as the key so the session is a key value store this is the key the value is the user object so i should be able to i'm doing this in loader in the root.tsx file which is the root route so this is the most the most fundamental route in all of remix it's comparable to the underscore app or underscore document files in next it's run for every or it it is what loads every other page in every other route in remix so if i console.log user and then i'm just going to return that oh you can see it here it reloaded the page automatically and it pulled out my display name my profile picture url which is obviously not a url usually alex you can fix that really quick by just logging out and logging back in except i need to implement logout first no i don't need to just kidding let's see avatar url nope that's not right i guess that is a maybe it's a path and you need or like a maybe that's the name of the file or something like that let's find out what happens i'm just gonna go to login again do that rigmarole ugly button authorize and it's not a function okay uh let me just take a quick peek at my notes and see how i did it my other site this will take but a moment um i don't actually get the avatar off of discord which is a real bummer so we will just not just not for now but i'll show you my display name yeah so we can see the display name showing up right here my email address my discord user id which i can use to access the api so here in the root route i'm just going to return the user and then a lot of people are like oh remix is this fancy weird thing um and it is a fancy weird thing certainly but it also is react so i'm going to create a context here call it user actually i'm going to make it tsx and sorry i'm trying to go really fast i'll explain what i'm doing in a minute so we're creating a react context for a user it's null by default um and then we're setting an interface for it which has all of the uh what is it so the id display name email and then you're setting up all the types for for those based on what data they hold um and so then we're gonna export that context so people can oh just the provider yeah okay cool i'm a huge fan of actually yeah i will say user i'm a huge fan of the pattern where you don't export the context directly you just export the um the provide sure the provider for the context and a hook to access it okay yep so there's github pull up pilot coming in clutch giving me all that stuff i've got to import in fact i'm not even going to import react i'm just going to import create context and this react node type there and then i also need to export my use user just like that um that's not right and actually what i need to do is const user context equals use context so context like that if this is null then i'm going to throw an error because we want to make sure this is only called from within the user provider and we probably will never not call it from within that provider because i'm going to put that provider right here in my route so this is where we're exporting default i'm going to put my user provider here it needs the user to be passed in which we're going to get from our loader in just a second so i'm just going to put user here wrap that around layout did you not get imported friend you have children without an arm ooh other way yeah there we go thank you thanks very good typo cat yeah for sure um so now i need to get the user and i'm going to use uh use loader data which is a hook provided by remix that gives me whatever data was returned from this loader awesome that's now provided in my provider so i know that it's like totally in the same file because my layout is just down a little bit but i'm going to put stuff here using that use user wait sorry use user hook just like that and then i can come down here and just plop it wherever i want so i'll put it here i'm going to say user dot display name and there it is it's me and not an emoji because something's broken but that is awesome it's very satisfying to see that all come together and then also especially like so so i've done this with you know kind of like pre-baked solutions we talked about maybe doing this with um something like uh what's the what's the hotness right now the meme hotness superbass yeah we talked about doing it with this um but how that is really kind of like a client driven type of like connection and so it's really cool to see you do this with a um with a node server and um kind of have that that full off cycle super neat yeah the the awesome thing about it is the fact that i can come up here disable javascript and go to the login page well first i can reload the page everything still works i can go to the login page everything still works okay it still took me to discord although for some reason it's oh this page probably requires javascript oh you're right discord requires javascript but my site doesn't require javascript and the cool thing about that is if it for some reason takes a while for javascript to load let's let's let's do that let's come back here we'll keep javascript on oh it's easier to do this from chrome so we'll do it from chrome huh that's weird that's real weird maybe you have some javascript cached or something do a hard refresh on that i thought i did do a hard refresh yeah i'm doing a hard refresh that's super weird interesting well it's saying internal server error there's probably logs okay yeah good point oh there it is user provider not found hmm that's really weird because i i put it right here maybe try and restart the server do a turn it off again hang on a second hang on a second good old faithful it's the catch boundary that's causing the problem hmm i need to use the provider in the layout yeah so this uh this error is actually hiding uh the actual error so there's some error that's happening and then we get a new error uh because of the provider can i use use loader data in um i i don't think so i can't no i totally maybe can't i can because if i can use it in app and app renders document i can use it in document okay yeah well well apparently not though well no there there's a different error oh well maybe not you defined a loader for route but you didn't return anything from your loader function oh okay because user is undefined that's the actual error so i would have to go in and figure out how to make it so that the errors actually work with what i'm doing but yeah now what i normally do is i always return an object with properties rather than right yeah oh gotcha which is a a good strategy certainly so i'm just gonna slow down my network so no matter no matter if you have an actual user object or not like so you would make kind of like a like a null user or like a guest user type of thing yeah i would just say user is null yeah okay as a property on i i call it my loader data that's the type name um is loader data gotcha okay i don't know if you noticed that but i'm just gonna refresh this actually i i need to i need to go home first oh slow guys okay and then i'm going to hit login and then as soon as it loads i'm going to click the ugly button notice it doesn't show the pending spinner state which you have to have javascript for that is progressive enhancement at play but it still redirects me because http still works browser still works um lindsey wardell asked what is remix using for bundling they are using es build and they don't want to let you manipulate the config because they want to have the ability to change bundlers in the future i will give a hot and spicy take i think that that is a limitation that is going to go away in the future because enough people ask for it but i will let the remix team decide that for themselves but they heard me say it i have opinions wait sorry so you were talking about how great it is that uh you don't have to wait for the javascript to load before you can navigate but then you start talking about customizing the bundler why why do you want to customize the bundler lindsey wardell asked a question in disco oh oh i see okay so that wasn't really you with remix oh oh there i see it now yeah um sorry for that strange context shift so view will will be supported eventually that's that's definitely a plan um here to hear first folks well we've tweeted about it um yeah and uh and svelt as well like pretty much the the thing is that remix is like 80 percent not react and so we just need to fill in the 20 for other frameworks um you won't need to customize the bundler for that cool sure thing good question lindsay um were there any other questions that people wanted to ask me or kent who is the uh he has job title but he works for remix and he knows things let's do this let's um let's uh we're going to stop streaming and then um to twitch and then that'll give people an opportunity to kind of you know freely uh use their use their mic and their um their video so um let's do that alex thanks so much i'm gonna turn twitch off and then uh we can kind of carry the conversation on in a little bit more high fidelity um in in discord so if you're in discord stick around uh if you're on twitch thank you so much for joining and we'll see ya see you around next time bye
Info
Channel: lunchdev
Views: 37
Rating: undefined out of 5
Keywords: games, twitch
Id: ZRmVb7D4yKw
Channel Id: undefined
Length: 74min 37sec (4477 seconds)
Published: Tue Dec 07 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.