I Never Want To Build Authentication Any Other Way

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's Poppin I'm Elliot a 19-year-old software engineer from Singapore and today I'm finally back after a few months of highers of not proding content uh but today I want to talk to you about authentication strategy and my many many frustrations after trying out so many different authentication providers finally setting settling for uh Lucia which is a a custom lowlevel uh authentication utility Library uh in nodejs that allows you to have a lot of nice functionalities uh to create your custom authentication framework so today in just a short period of time I'm going to teach you how to create this sign up and signin feature along with Google oo all custom build we are not using next off we're not using cler we're not using anything we are going down into the session token level and just uh rolling everything on own I'm going to tell you why that is so important later on but let's just do a demo right now so you can come in here and create an account using an email so if the email already exists uh you can put a name here if the email already exists it's going to tell us that the user already exists right and here has all of the client site form validation that you expect um and then you can do like if you have something that that is not that is not taken Elliot test gmail.com and put Elliot TR let's do like 1 2 3 1 2 3 1 2 3 one 2 3 1 2 3 1 2 3 obviously it should be more secure but once you sign up you can see that uh it creates an account successfully it brings us to this protected route so this homepage is protected only if you signning you are able to see this page we are able to get your name and your email right if you try to go back to the SL authenticate page we're just going to basically redirect you back to this page uh so if you're signed in it doesn't make sense for you to be able to see the authenticate page again so then on top here my face is blocking but there's a sign up button up here um actually I'm going to move it down down there later but you can press sign out and then this will clear the session token and be brought back to the authentication page and pral demo the the Google or feature so obviously we can continue with Google uh you can also sign in so this also works you can log in with an account and obviously you can sign out and so if there's the wrong password we're going to tell you that it's invalid credentials right so let's continue with Google so you can just choose a Google account to want to log in with uh it's going to ask us for our name and profile image and email and then we can see that it's properly rendered here so we get the email out uh the image and the code uh so it's actually incredibly simple to impl commend any type of social login be GitHub or Google in this case I'm going to teach you how to do the Google o off and I'm going to go deep dive into how the O flow actually go so instead of just uh showing you the code I'm going to tell you each step how the server exchanges the access tokens how you going to basically communicate with Google server to get back the information from your users right so to then begin with why are we talking about this so I have been using different and experimenting with different uh authentication providers over the last few months and years right and so I started out with rolling my custom authentication which means uh using jwt's and then us it putting into a mongod DB storing the Json web tokens in local storage and then like configuring all that stuff and it was very low level it g it has given me a lot of control over my authentication the thing is it's very complex because you need to be able to implement all the little features by yourself uh and so there's a lot of pieces and as amateur you don't actually know what's the best security practices when it comes to proper authentication uh so that is the custom workflow then after that I moved into next o uh which was also like a pretty lowlevel uh library that given that gave you authentication for next years uh for like user credentials or like Google o of login the issue is that it is too high level there's too much abstraction going on in next off right it doesn't even allow you to do like user password uh username password authentication because it doesn't trust you uh that it's safe for you to do so it just basically takes away a lot of control from the developer it treats us like we are idiots which I don't really like uh so the abstraction is kind of leaky and the the documentation is not that good but it does give you like some sort of control over how your authentication flow goes like uh it's easy and it's also free so we're going to touch on what's the difference between simple and easy right there's two different meanings behind being simple and being easy to use so then I move to clerk so clerk is what I'm using for my Enterprise project uh and my job uh it's very high level because it's literally a soft a software as a service company that's powering authentication so they are trying to make it as easy as possible the thing is you don't get to store your user data in your own database your user data is ultimately made and stored on cler server so if you if you trust that cler will protect your user data then go ahead right but the thing is it also provides very nice UI and a lot of nice features out of the box like a good a profile management they give you like uh email verification of the Box they give you all this good UI all for free in the free TR and it's incredibly easy to use so if you have a sess application like I would still recommend Club the thing is it's paid there's no data control and when you actually want to do some custom authentication logic so it happened to us recently in our company we wanted to do something custom with our users where a user can belong to multiple organizations and when we need that Gran granular control over our uh flow clerk does not support that we literally email cler's employees asking if they support the feature and they literally just said that oh that's too bad we don't support the feature and now we're just left with a ton of code dep uh with cler that we have to migrate over to our own Au authentication strategy so it's kind of like a trap you get trapped in the nice UI and simple usage but then when you actually want something more advanced K will fail you uh so now we finally come to Lucia so why are we learning Luccia now so Lucia is firstly is open source so there's no vendor lockin it's low level but it's low level in the right kind of sense so it doesn't abstract away every thing from you but it also doesn't like leave you to die when you're doing custom JWT flows or custom session token flows so it gives you control over the data it gives you control over the flow at just the right amount of abstraction level it's simple and it's free so let's talk about what's the difference between being simple and what's the difference between being easy so simple would be uh simple will mean that the underlying concepts are actually not that hard to grasp once you grasp it once you understand it once you understand how session tokens work once you understand how Google o flow works these are very simple Concepts that you literally understand right but the thing is being easy would just mean that it's easy to set up it's easy to copy the codes from next off documentation into your code base and see something work but when you want to actually go in and customize and understand what they're doing underneath the hood it becomes super complex because they abstract it all that away from you and in the end you have no control over the code base right but simp simple is even though it may be a little hard to set up at First Once you understand the underlying Concepts and the flow setting it up yourself becomes super easy and customizing it down the line makes it even easier so that's why we're learning Luccia for today right okay so I'm going to be talking about two big Concepts in this video one is session based uh off and the number two explanation is the O of 2.0 flow so these are two very important Concepts today so let's start with what session based authentication is okay so imagine here is our nextjs application app so this consists of our front end and our backend server because nextjs is full stack right and then let's say we have a database here so this database could be like a postgress SQL database or like a just a squel like database and finally we have our lovely user over here so how does the user authenticate with us so when the user comes into our next GS app I'm going to demo it here right so I'm going to sign up first so when the user comes into our next JS app and clicks on uh sign in for example so they give us an email and password what we're going to do is we're going to take that email and that take that password and we can to compare it within our database so in our database once we registered the user they're going to be a there's going to be a rle uh with your email and their hash password password right so once we have that registration flow the user is going to submit that email and password and we're going to compare it with what we have in our database if everything goes well we are sure that the user uh is who he says he is so in this case like aliot test at gmail.com has his password so we know OT @gmail.com is trying to log in so then what we're going to do is we're going to return a success message right but the thing is we're going to keep track of this user uh locked in our user so imagine we have a record book right and the record book book I'm going to keep track of two things literally two things is when you log in so when you log in and who are you so we start your user ID so it's a very simple record so when the user comes here and log into their database once they provide us with the uh email and password we're going to store a time uh time frame so let's say it's 7:40 p.m. right now and we going to store this user ID of let's say ABC so we have user ABC here okay and it exists in our database as well so now whenever the user comes back to our app we know that it has only been 5 minutes since he last logged in therefore we actually want to be able to keep him logged in without him trying to enter his password every time he visits oursite it doesn't make sense so how do we make sure that the client is able to give us uh this record on when the user tries to log in and this where session cookies come in so session cookies are just this small little uh like cookies like little cookies if you like if you even lived on this Earth before you know cookie is just like this small little snack that you bring you can it's very portable right so this cookies in the context of web de development are just little data packets right so if you go into like your application and you can look into cookies not sure you can see this underneath cookies I can see that on Local Host 3000 I'm storing this cookie called um session okay so this session is basically what I'm holding on to and every time I visit this website I'm going to pass this cookie to you I'm going to tell you that okay this is my session token right so we have this value of this ID right and what we're going to do is we're going to compare this session token that you give us with this red along let's just contract it to like the first five letters right so whenever whenever the user authenticates with us we're going to store this we're going to create a new session token for them right we're going to create a new session cookie for them cookie ID session ID right and then we're going to pass this session ID back to our user into D browser and store it into a cookie okay so now a user has a browser that is storing this session ID for us so now whenever the user logs into our nextjs application the user is going to basically give this cookie to our server right it's going to give this cookie to our server and then we're going to compare this cookie with the session ID here and then we're going to find the user ID and we're going to check if the last time they logged in was it so long ago maybe they last log in 6 months ago if they lck in 6 months ago it will make sense for us to make them relog in but let's say the session ID that they submitted to us through a cookie is only at 745 p.m. so we're gonna basically just retrieve the user ID and then we're going to basically pre-log them in So then whenever they come in and refresh the page they already logged in so I'm going to log in here and now if I refresh the page we can see that if I refresh I'm I'm staying logged in but the thing is if I come in and I come into my application and I come into my all session here this value and I delete this cookie and now if I refresh the page you can see that I'm logged out because what I'm essentially doing is I'm removing the cookie from the user so now when the user comes into my app again it's as though it's a new person coming in and therefore I'm not uh logging him in so that's a pretty long explanation for what session uh tokens are but that's a high level of what is so now let's actually implement this uh project okay before we continue with the next part of the build I want to take a quick moment to share something super exciting with you so uh last year that was a Docker AIML hackathon with over 2,300 International professional uh uh experienced developers and guess who won third place by myself right so I built this fullstack AI project here end to end and using this project I've won third place in this hackathon and I've won $5,000 from this hackathon alone and I've won much more hackathons in the past and so over the past few months I've actually been working on a hackathon course intentionally designed to help coders like you win the first $10,000 in hackathon pricee winnings and the course goes beyond the typical tutorials it's filled with strategies insiders tips and practical examples that can give you a significant hge in hackathons we cover everything from idea generation team collaboration pitching to Advanced coding techniques and rapid prototyping plus you get access to exclusive resources and the community of like-minded CES and in the course I'll be teaching you step by step line by line how to build this entire AI power developer tool that help me win this hackathon hey what's Poppin I'm aliot a web developer from Singapore and today I'm to showcase the project that I've built here called dionysis so what dionysis is is a power tool for any developer that is collaborating on a code project here I have a sample uh repos repository called chat PDF and it's it's just like a a s application where you're able to chat with a PDF and yeah so you can like drop a PDF here and you can chck with it using vector embeddings and what I'm going to do here here I'm going to create a new project within di Genesis I'm going to call it chats PDF and then we can link it up with our repository so I'm going to copy the link and just paste it in here and this does a lot of things in the background first you will try to use Lang train to actually script all your GitHub repository all your files the repo and you summarize them up and then using open embeddings we're going to convert them into vectors and store them into Pine con DB a vector database so we're actually making a retrieval augmented generation model for your GitHub repository so the first thing here is it actually able to generate documentation of your code just from looking at your repository so here we have a full flet editor right where you're able to edit it is a markdown editor right you can see the different sections that the EI has generated so it gives you an introduction of the project is about and it gives you some instruction how to get started with it like cloning the repository uh navigating into it and all of these are are repository specific the next part is you're able to ask it any question you want about the code let's say I'm Ted with a new feature of like uh uh changing something about the AI a conversation so I might ask like hey uh which file with the AI about the PDF right and so this is a valid question and because I'm a newcomer I might not know where the project the code lies in I can just ask this question to diis it's able to give me is able to give me uh the answer so it can say it the file that contains a logic lies in the chat component. TSX file right which is correct right right and all of these questions are St in a history log so everyone can see it at the same time right so I can ask another question like let's say um which file should in the PDF viewer right so I'm going to ask this question so we have a PDF viewer here and what it does is it's going to try to look at the context right look at this it's able to answer with a context about the code base so it's telling me that I need to change the source component check component. TSX file which is absolutely correct and there's also we generated a flowchart diagram of your code base your file tree so we using mermaid um mermaid JS to actually all this so this is a a one by one accurate representation of your file tree so instead of looking through the file tree you're able to just come here and have a very big overview of what the uh what the project looks like so I can see that oh under this components photo I have 1 2 3 4 5 6 7even around seven components I can just have a very nice overview of what the code tree looks like the AI is able to pull in all your comments from a repository and using AI is able to look at the diffs in your comments and generate a AI summary based on the comment so all this you can see that these are my commit messages but this gray tags here are what AI generated based on just looking at the commit default and what I can do here is I can pull comments so that I can see the most updated comments and let's actually try that out if I come down here to my so let's say I can add like a change that says um hi this is a test uh change exclamation mark I'm going to commit the changes and just update with me mown right with that if I come back to my diagnosis and press PLL commits look what happens if you give it a few seconds to summarize a commit and you can see that it's able to uh detect that I add a commit update REM on markdown just a few seconds ago and is able to use AI to generate a message saying that added a test change right so these are all very powerful tools imagine all the time uh freed up using AI to help your developers understand the code base even more and this is still not the most powerful thing about the project yet if you come down to the meeting section right so imagine you having a meeting about uh the code base right and then you already finished and recorded a meeting what you can do is you can upload a meeting so I'm going to link this uh down in the description so that you can test it out yourself but you could theoretically upload any MP3 files right so in this case it's like a 30 minute uh audio recording of our meeting and I'm going to just wait for a while and come back when it's done so it's going to take about a minute or so and you can see the meeting has been processed and look at the power of this we're able to readin the transcript from the MP3 file and it's able to generate all the key issues and key topics has been talked about in the meeting isn't that amazing I can click on the details I'm able to see uh the summary of the of the key point so I can ask for further clarification like let's say I come down to like reviewing the build board right so as we're reviewing the build board and then this is a quote from the meeting so I can ask like uh what is the build board about question mark so I'm going to send a question and diogenous with the context of the meeting is able to answer the question with respect to the meeting and yeah so if I come back to home I can even invite another member so I just need to invite copy this link I've put a lot of my own experiences and secrets into this course and I know for a fact that it will make a difference in your hackathon journey if you work hard at it and also for the first time ever I'll be opening slots on my timetable to get on call with 10 of you guys to help with any problem that you face on your coding Journey so if you ever send me a DM you send me an email or you left a comment under my video asking me help for code this is your chance to do so remember there's only 10 slots and so if you're ready to elevate your skills and you're interested in this hackathon course that I'm building and you're ready to start winning your first $10,000 or more in hackathon prizes just check out the link in the description so other than that thanks for letting me share that with you and now let's get back into the course today to finish building this awesome project so the first step is let's actually begin a new project a next new next JS project so let's do uh studo bun uh let's just go into my coding folder okay and what I'm going to do is I'm going to do sud sudo but next uh create Das next app at latest so this going to create a new next year's project for us and let's just call this Lucia o- YouTube and we're going to choose typescript yes Lin TN CSS Source directory and we're going to use the app browser and we'll just leave everything on the default so it's going to go in and install and okay that's really fast so now let's just CD into our Luci off- YouTube okay okay and now let's just press codee Dot and this is going to open it in our code editor awesome okay so now that we have this code editor Let me just zoom in here and what I'm going to do is I'm going to just run sudo bande to basically run our next year server so actually let me stop my previous server so that we can utilize Port 3,000 here so sudo Banda will run uh my app on this logos 3000 so I'm going to close this down and I'm going to just use this page and boom so we have our next JS application running here everything looks good okay so now what we're going to do is we'll come down here and we're going to go down to our sourcea page. TSX folder okay so this page. TSX in the s/ app folder is a special file whatever name called page. TSX is a special file within nextjs that maps to the the URL here so this page of TSX represents what we're seeing in here so I'm just GNA clear out everything here I'm going to return a H1 that says hello world boom and I'm going to see Hello World showing up on our page so everything's working that's good so what I'm going to do is I'm going to clear out everything here I'm going to go into my global. CSS and just delete everything here I like to start a fresh so now we have a flash white page here okay that is really cool so now let's actually uh initialize Shen so if you're not familiar Shen is is really nice uh and kind of overused Tailwind uh library that looks really nice uh and it's really simple to set up so this is what we're going to be using for now we don't need any fancy libraries so what we're going to do here is come down to your terminal okay I'm going to just split the terminal here and what we're going to run this command so bun x uh let me pull this down we're going do shat cn- UI at latest in it so we're going to initialize shat CN for our project so it's going to install our all the dependencies and all the configurations let's just choose New York for this uh choose slate as the base color we'll use CSS variables so it's going to create this components. Json file right so if we come down to components. Json it's just a components uh it's a just a just Json file that consists of our options when setting up shs yet okay so that's good so now let's actually uh use a shed CM button in here so how do we actually import a button so if we go down to the shed CN Library you are here and we choose the button okay how do we actually get this button so you can install it using the command line interface so I'm just going to copy this right so we run the command uh for me I need to do sud X cn- UI at latest I'm going to do add and this is the name of the component so here we can see that there's a list of components whichever you want you just have to type in the name add button right or the faster way is just to do add right and it's going to list down all the components that you can add and you can press space to like choose one by one so you can add it like five at a time so I'm just going what I'm going to do is I'm going to just choose all by pressing a in my keyboard and press enter so this is just going to download the entire Shen components into my uh project for me to use okay so it's installing everything and so what it's going to do is it's basically going to install it into this Source SL components slui fold so we can see all these custom components that shn is installing for us manually now if we tap into a button. TSX we can see that it's just uh uh it's just radics UI with some class variance authority to be better style our components and we can make a lot of nice changes in here uh customize it as we want to right but let's just wait for it to finish and we're going to start using the button component soon so let's come back down to our page. TSX and what we're going to do is we're just going to do uh button so we can see button we can import from at/ component ui/ button my face is blocking as usual I'm going to move my face down here okay so we can come in here and see that it's going to Auto Import from uh button compon uh component /i/ button and then we're going to use hello world all right and then if you come back down to our browser we can now see there's a button showing up here nice and beautiful okay cool cool cool cool cool so Shen is working now we have installed sheden so now let's actually build the let's actually build the authentication page so how do we go to slash authentication authenticate authenticate right it's going to tell us that's a fall for page not found so what we going to do is oh I'm going to close this thing down here first so under your app folder I want you to create a new folder called authenticate and under this authenticate folder we going to create root. TS F so I'm assuming that you have some uh knowledge about next year so I'm not going to go through how we going to set up Roots so I'm going to do uh ra fce which then is a snippet from extension for react aror functional export uh so it's not be root. TS sorry it should be page. TSX right root. TS is for our API folders so let's just rename this to um authenticate page okay let's Del this Del this and save this all right oh let's actually delete this all right so now if you go back to here authenticate we can see that authenticate page shows up here which is exactly what we have here so this maps to the authenticate URL we have here okay cool everything's looking good our shn has finished configuring so I'm going to ex exit this terminal and let us continue so I'm make it bigger okay so we're going to just set up the the the components that that we're going to use in here first so we're going to have two right we're going to have the sign in form and the sign up form so let's just C along here first so I'm going to just return a div right that has a class name of a relative Flex width of full height of screen and BG of background right so we can see it's like this and then underneath here uh I'm going to just have a another diff here and we'll have a class name of Max width of 3x Cel absolute left half right half so I'm trying to Center Center this div in the middle of the entire screen translate X half and we'll do negative Translate Y half and then we have a inside here we can have a text here so we can see that it's not centered in properly here now uh because this should be top left and top so now it's absolutely Center in the middle okay and in here I'm just going to have a uh uh I want a tap switcher component here so a tap switcher is going to have a card and on the top we're going to use case the use the T tabs component from shed CN right we're going to basically have this kind of layout here okay so to do this let's actually just copy what they have here right so they have already given us this code for free let's actually just use this um cool yes so uh I'm going to copy it but not Direct ly cuz I made a tab Swit component that is more reusable so I'm going to come down here to the source SL components right I'm going to create a tap switch. TSX oh and of course because I need to okay so under components I'm going to create a sorry under components create a tab switcher TSX file okay I'm going to put use client here because this is going to be a client component right and then what I'm going to do here is I'll just import I'm going to just do a a tsrf for typescript props and in here for the props I'm going to receive two things I'm going to receive a sign up tab which is a react. react node right and I'm going to do a sign in tab which is a reactor react Noe so how I want to use this component is I'm going to import in here and I'm going to do is I'm going to do sign in tab I'm going to basically put in a component Here sign in form I'm going to put a sign up tab to be a sign up form so obviously I haven't created a component but this is how I want to use the component so this is like a declarative way of doing it so I'm going to basically accept this two children as props I'm going to render it into my tabs here so what we going to do is we're just going to import uh we're going to import the tabs from shn so we're going to import from at SL at components at SL components slui SL tabs I'm going to import a few things we're going to import tabs tabs content list and Trigger okay and then let's actually just craft the tabs first we'll have a tabs list right and inside the tabs we have two TS trigger so each trigger will have a sign up and a sign in so let's import the trigger T trigger okay and it needs a value so this value is going to just be called sign up this value is going to be called sign in okay and Char BD has literally finished the code for us so we're just going to take in the sign up Tab and sign in Tab and put it into this TS content and then let's actually also give this a class name of Max width of 500 pixels so it doesn't overflow and we'll control the state through a tab actually we actually is fine like this is fine so the Tab S component is basically done right uh is there anything else okay let's just save this first and let's import the tab Swit and in this case I'm just going to put in some fake values here I'm going to put a H1 that say sign in and put a h one that says sign up so let's save this and go back to our browser and now we can see there's a sign up and sign in page so we can see that the tabs already looking decent we can see that when you press sign up it shows the sign up content and when you press sign in it shows the sign in content okay we're doing really good we're doing really good okay so for the T content uh for the sign up for the signin page let's actually create the signin form okay so what I'm going to do is come down to authenticate I'm going to create a signin form. TSX okay so for the signin form uh it's going to be a use client component so we'll do t uh we're going to do just rafc so it doesn't accept props right and we can actually import it in here uh like this let's import signin form okay so how do we actually do the signin form so let's just craft the UI so we're going to need we want to show it in the card format right so let's just import card from components sui uh let's have a card header right with a card title that says welcome back exclamation mark and for cut cut description we'll do sign into to your account to continue so let me just commment this uh sign up tab first sign up and let's say the sign in form and let's look at how it looks like so right now we can see that sign in we have a card now which looks pretty decent so what I'm going to do here in the tabs feature is I'm going to give this tabs a default value of sign in I'm going to move this up so by default when you refresh the page we can move this sign in trigger up here so when you refresh the page the sign in tab is going to be selected by default so this looks good okay cool and then now let's actually craft the form inside here okay so let's go back to our sign in form and let's do a uh card content underneath here and let's do a class name of space- y-2 oh sorry it should be class name not the snippet space y-2 okay cool and how we going to do the form so if you go down to shn UI they have given us a very nice uh form form validation component so this is how the anatomy of a form will look like here and so let's actually just copy the example so to do this you actually need a few things you need uh hook form resolvers as well as react hook form so this for the client side form validation so let's actually do this uh do we have to install it let's check let's do import from react hook form okay we do have react hook form uh that's really cool so the first first thing is to basically create a form schema so import zot so zot is a validation Library so we're going to call it sign in schema I'm going to export this out and we're going to need a few things right so we're going to need a email which is a z. string. email and a password that is a z. string do minimum of eight characters okay so we got this signin schema right and what we're going to do is we're going to just uh Define our form so I'm going to copy this in here okay so this use form comes from uh react hook form and we can see that we're using z. infer to get the schema of the sign in schema so this will basically give us back the default uh the type safety so we can see that when you do email and password it automatically pulls from these two Fields so let's give a default password email of string and password of mty string so we also need resolver so where are we getting this from is from Hook forms SL resolver let's copy this in here and looks good okay so this on submit is basically what what the function that's going to be called whenever we submit the form okay so let's actually just get a minimal form up okay the most basic form okay we will need a few things so we're going to just import this few components from form we're going to build the rest of the stuff out so import from component /ui form so in here we're going to have a capital form right and so this comes from Shen and we're going to pass in sorry we're got to pass in the form variable that we get back from use form from from react hook form so this react hook form uh controls the validation for us and we're basically passing it into this uh component okay inside this form we just need a normal HTML form component right let's give a class name of flex Flex has call and getap D4 and let's do onsubmit uh sorry in the form onsubmit so whenever we submit we just want to uh do the form so this form from react hook form handle submit and passing in this onsubmit function that we Define up here okay okay so now that we have this form let's actually delete this we want to code it ourselves so let's just save it first we can see that nothing's happening right so let's just show a text view here for now so I'm going to get a form field component right and this form field component is going to take in a control which is comes from form. control so this form as you can see we keep using it because this form comes from react hook form right and then we're going to give you a name right this name can only be two things email or password so we'll just leave it as email for now so this is email text so we're going to render so when you render we can get a few component here a few variable uh and we're going to return a component called for form item and this form item will have a form label so this like a label for the form for the email and we have a form control inside this form control we can put input imported from Shen right this input has a placeholder of enter your email dot dot dot and we have passing in the rest of the field here that we get from this render higher order component so then when you change it uh actually it's fine right like this and let's save it to C now and we get this email fill so that's pretty cool that's pretty cool and so we want to see the error message right we can see that obviously it's airing out but we don't know why right so firstly let's give you a type of email and let's also add a form message component underneath here so we can see the validation errors so what it happens so if I try to submit we can see that it's like showing me this error and everything looks good uh that's because I have the type of email so if you remove this and try to enter email it's going to say invalid email so this rate text corresponds to this form message component okay we're doing really well we're doing really well so now let's actually code out the rest of the login form so I'm going to just comment this out right so the rest I'm just going to copy in uh it's actually not that complicated we're going to do the same for uh the password F so this a password F we're rendering the password so we get this password field here right it's exact the exact same component we coded out just now and underne this field we're going to have a button imported from components right we're going to have a type of submit and we have a class name of self start and we'll just have a login text in here so we can see a login button right it's going to uh uh trigger this login so we're going to basically just console.log the values whenever we log in to make sure that our values are being submitted okay so I'm going to open my console here hope is super big for some reason okay that's actually pretty good so now if I press long in okay I need to what I'm going to do here for you guys is I'm going to move this into the side so now we can see it together so we can see that this line 38 here is what is being called whenever we Press login and we can see the email and the password that is being pared for us so now that we have this uh email and password we can actually do something cool with it so what we're going to do is we're going to create a form action a server action that's going to take this values and create a uh lock try to lock our user in okay uh so before we do that let's actually create the registration form okay so now we have this login form let's actually create a signup form so the signup form is very similar so let's go back to our tab switcher uh sorry not tab switcher we go into our file folder let's create a signup form. TSX boom and we'll do something very similar so in fact we can actually copy in the sign in form copy everything here we just need to modify it such that it says uh oh by the way if you're not sure I'm doing I'm selecting this sign in schema then if you're on vs code a handy structure is pressing command d right this will select all the instances in your file and then you can edit it so we can do sign up schema so for sign up schema what do we need we need uh email password uh email password what else do we need we also want the uh confirm password which is a z. string with a minimum character of it okay so confirm password and actually one thing I forgot is that actually in our signin form uh actually sign in form is okay but for the sign up schema we also want a name f which is a c. string dot let's just give you a minan character of like five okay so we need name email password and confirm password and one more thing is we can we want to make sure the password and the confirm passwords are the same so for all we can do a refine so we going to take in the data right so we're going to return true or false uh based on the custom logic so we can do data dot we can see all the type save attributes coming in from our zot schema so we're going to just basically return if uh if data. password does not equals to uh data. confirm password we're going to just return false right so we can actually shorten this so instead of having this C Braes we just directly return data. password not being equals to data. confirm password and for the second attribute here we can pass in a custom message of what we want to show when they don't have the same password we can see that passwords do not match and the path is confirmed password so the error is going to show up on the confirm password field okay so now we have this sign up schema we're going to have this sign up schema let's put in our default values for the confirm password to be a string and we'll do the same for our name boom okay everything's good so now what do what else we need to change um let's come down here so for the title let's change it to beginning of Journey dot dot dot and we'll just give it some text cool so if we come back to our signup form we can see that uh let's actually use this component inside of our authenticate page here so let's do sign up form uh sorry we need to change the name of the component here as well so we'll just change it to sign up form save this come back in here and import it and boom we're done so we got the sign up here sign up is begin your journey we have the email and password so let's actually add the rest of the fields so for the rest of the fields we need our email obviously but we also need the name so let me copy this down so for this will be the name field let's say name for the type will just be a normal string and we'll say enter your name dot dot dot so now we got our name name here and we'll do the same for confirm password so we'll copy this down and we'll name this confirm password so we'll say please confirm your password we'll save it and then and so I'll sign up form finally it works so if I see that it's not the same wait sorry it's actually binded to uh for the control the name here should be confirm password confirm password here so we have our email F here we have our name f here our password VI here and our confirm password here and so now finally we can see sign up works so if my password is not the same it's going to say that string must contain at least eight characters and here for name it also works the same right then if if it's the same password right it's going to say that it matches but if it doesn't matches it's going to tell us that passwords do not match okay so everything works good we got a UI set up I think this is looking really clean okay so uh actually here I want the form to be a little wider so I'm going to do is for this I'm going to do a class name of minan width of 500 pixels so it looks a little nicer okay yep I actually prefer this much better um okay so we can sign up and we can sign in now so let's actually create the authentication Logic for signing up so when we console.log the values Here sign up here let's just confirm that we get the data so let's just do Elliot at gmail.com we'll give you a name we'll have the password of 1 123123 1 23123 so we press sign up sorry it should be there's a text here that should say sign up so let let's try again so we'll do Elliot Elliot so password of 1 2 3 1 23 1 23 so when we press sign up we can see that uh the passwords do not match 1 2 3 1 2 3 1 2 3 oh okay a silly mistake here is that when we refine it the logic here should be checking whether the passwords are equal to each other so if we save this and now we can see that sign up we can enter our name right our password let's just do 1 2 3 1 2 3 right sign up okay let's add two more characters so when we press sign up we should see the console here so we can finally see our data so our confirm password our email our name and our password here okay amazing so we can finally do some cool logic instead of stuck here uh writing forms okay so uh what I'm going to do here is I'll come down to my I'll come down to my uh we got to come down to our folder folder folder folder right and we're going to do uh we're going to come down to authenticate and we going to create a new file called off. action. TS so this is just to make sure that this file is an action server action we'll do use server right so to make sure this file is only for Action that's only going to run on the server so for our off. action so let's actually Define the sign up function so we're going to export uh we're going to export a async component uh async function called sign up right async that's going to take in the values so what this value how do we get this type c value we going to get it from Z z. infer passing in the type of sign up schema which we import from our signup form okay and then we can then we can see that this values is a type save uh variable containing the four things that we want okay so actually we have not initialized Prisma I just remember so we need to store our users in a database somewhere right so let's actually do that so come down to your terminal okay and let's actually do uh St bu x uh press uh stud bun install Prisma and pris at Prisma SL client right so let's just install this to libraries in here okay and we're going to do we're going to run Soo b x print init D- data source- provider is a sqlite so we going to use a on in memory on this SQL like database for now so we can initialize this and what this does is it has created a so let me show you let zoom up a little bit so it's created this Prisma folder for us inside here there's a schema. Prisma that basically contains our object relational mapping uh for how we want to represent our database okay we can also see that that is pulling from a database URL so where does this database URL come from it comes from ourv file database URL you can see that it is it corresponds to the schema. Prisma here so we're just storing it into SQ SQ like file right so let's actually Define our model so a model is just a table right so CH uh Define a user table we want the ID field which is a string we'll make sure it's an ID and we by default by default let's do it as a c U ID okay for a user we need obviously an email which is a string and we want it to be a unique uh string across the database so no two users can have the same email it doesn't make sense right so we enforce it on the database level okay and user will have a name as well so let's just start our name right and you can also add a row here so if you want to do like enam enam of like uh user row we can do like admin or like uh user we can do a user row here and we can do a default of admin or like default of user that makes more sense so the error here is uh okay SQ like does not support enums I just realized that uh but if you're using postgressql this will work perfectly so let's just remove the row for now uh actually row can also work we just have to name it to be a string okay so then let's actually do uh Let's do let's make it optional for now and we'll have a store the hash password so remember we are storing uh their password but we have to Hash it so we're not storing plain text password so let's make this a string uh but it is optional because we can have users coming in from Google authentication that do not have a password so after this let's actually Define our session table so remember in our explanation just now we have a session table that keeps track of which users are logged in at at which time so let's actually create the structure to hold that information so so obviously uh and every table will have ID right okay and then we have a user ID right so this is basically telling you for this session which user is is basically holding this session and then we can about expires ATS right expires at column and this is a date time so this tells the session when it has expired and then obviously we want to link it up to the user so we have a user and we have a relation of uh this so chb is able to finish this for us so we just have to finish it so we can see that uh a user can have multiple sessions and each session can belong to a user so this is how we are representing this uh relational data in our Prisma database so now that we have this let's actually uh push this uh schema change into our database so we're going to do sudo bu X Prisma DB push so this is going to take our it's going to look into our schema. Prisma and it's just going to create these two tables in our SQ like database so now we can see that there's a there should be a def. DB here that's SQ like database right and I got extension that here that shows me that we have our two table session and user and right now we can see that there are no roles in our database okay but the good thing is now that we have these two tables in our database and now let's actually create a way to interact with our database so under the source folder let's actually create a lip uh actually we already have a lip so let's actually create a Prisma TS so this is the file that allows us to interact with our Prisma uh database so for this Prisma we're going to import uh from at Prisma client right we're going to import Prisma client obviously so Prisma client is the client that allows us to interact with our SQ like database so we're going initialize our client to be a new Prisma client all right and then we're just going to configure it so that we don't want to show any debug locks so when when process. env. node n equals to development right we want to show errors and warnings if not we just want to show errors okay so this is just for the logging purposes in in Prisma okay then we going to do a single turn pattern so basically because next year reloads out there's a hot module reloading we're going to basically try to connect our database every time we're going to create a lot of this database connection that's going to uh put a lot of stress on the database so we just want to initialize our Prisma once and keep using that same database connection and to do this we can store in a global variable so we have a a variable Global for Prisma and we'll just call Global disc as unknown as Prisma and this is the type of Prisma client or undefined undefined okay so this are Global variable that STS a Prisma Clan so we're going to actually export uh default Prisma uh export cons Prisma to be Global for Prisma do Prisma so if we already have initialized Prisma and we store it in the global variable we want to reuse it but if you have not reused it yet that mean this is the first time initializing Prisma we're going we're going to basically export out the client and we're going to check if process. env. node EMV does not equal to production so we are in development mode we're going basically bind the Prisma client we're going bind the Prisma client to the global environment here okay so we can finally interact with our Prisma database right by doing Prisma do user. find many right so this can return us with uh a list of all users in our database so this Prisma object is what we going to be using to interact with our DB now so let's save this file and now let's actually go back to our off. action. TS and let's actually Implement our uh action so the first thing we're going to do is we're going to wrap everything in a TR catch block so we going to first check if the user already exists so if user already exists uh troll an error because it doesn't make sense for us to register two users under the same email so we're going to check cons existing user equals to await await Prisma so we're going to import Prisma from our at/ Li / Prisma Prisma do user. find unique where the email fill so we can see the email so we can see a list of all the configurations from Prisma so we want to filter by email right equals to values. email so this values is the values that is passing in from our form so actually let's test this first so this function is going to run on the client so let's actually run this so we do console the loog I am running sorry it's running on the server I'm running in in the server right with values being values so let's see if you can see this in our server so if we come back here into our file let's actually link up here so if we go into our sign up form whenever we submit it here we want to uh actually convert this to aing function we're going to do a wait sign up so we're going to import this from / off /x action pass in the values in here so this values will be passed into this sign up function and hopefully we can see this being caught in the server so we'll just save this we'll save this and now let's actually look into our console and now if you go back to Arc so if we do sign up here let's put in a random name 1 2 3 1 2 3 1 2 three sign up we can see that I am running in the server with values being whatever passed in here so it's good the values are being passed into our server and now let's actually continue the the logic so we are checking if there an existing user so if existing user exists we're can return an error saying user already exists and passing in success being false okay the thing is if there's no user let's actually create the user okay so we'll just do uh cons user equals to await Prisma do user. create we passed in the data being so so the data requires what we can see that we need email fill uh email name and password so the email obviously comes from values. email the name will be values. name all right so let's actually normalize the email to lowercase okay here and we need the hash password so how do we actually create the hash password so let's come on top here and let's actually create the hash password so there's a function right uh from basically Oslo so if you're not not familiar with Oslo is a uh mpm Library also created by the same Creator from Lucia that give us a bunch of off related utilities like password hashing so let's actually install Oslo so let's come down here and let's install roban install Oso okay so this will install into our project and because there's some issues with next 14 and Oso we need to come down to our next stock conf. MJS right and I need you to copy in this so come down to your next config and copy in this web pack config so without this is it's going to break our app right we can see that uh something wrong with node RS that's breaking our app when dealing with this ow package so let's save this next config right it's going to the server is going to restart but then now that we have this Oso package let's actually import import it so import from ow/ password word so there's a utility called Argan to ID Argan to ID right so this Argan to ID we can initialize it here and this gives us a uh a function called hash that will hash our password for us okay so now that we have this hash password we can store it in here and then we are basically done so now that we have created a user let's actually create a session token a session token for them and create a cookie to be stored in the in your browser so in here we need to create a new Lucia instance so what we're going to do down here is come down to our lip here lip and we'll create a lucia. TS okay so this Luci is going to basically help us with creating session cookies validating uh user tokens validating session cookies and getting out the user for us okay so uh let's actually just import a few stuff from luciia we need to inport uh Lucia okay we actually have not installed Luccia yet so let's do solo bu install Lucia okay so really step by step here so we'll need a few things we need the Luci uh here and we also need another stuff which is the Prisma adapter because luciia needs to be able to interact with our database to read and write session uh session information from our table so we need uh at Luci o we need to inst another uh P database adapter so this library is for Luccia to interact with Prisma so we'll do at Lucia D o/ adapter D Prisma so let's install this okay and we need to import it from here we need to import the Prisma adapter from here and then let's actually do cons adapter equals to new Prisma adapter so this is creating the actual adapter we pass in Prisma so this Prisma comes from our a library folder we pass in the session and we pass in the user so this are the two tables that we want Lucia to control therefore we pass in the session uh table and the user table for for Lucia okay then let's actually export a Luci instance so this Lucia variable is going to be the helper functions uh that's going to help us create all the session to uh tokens so let's initialize new Lucia let's passing in the adapter as our first variable and for the session cookie we can actually put in a few uh configuration so we can put in the the the name of it here so we can put in like a special name so let's just test it let's just put like Elliot o token uh aliot o cookie okay we're going to see it show up later in the browser okay we're going to put expires to be false so what we're seeing is that we never want this user to ever log out so they can be forever locked into application uh this probably not good idea but I just want to demonstrate it then for our attributes sorry for attributes so our cookie attributes right we can we got all this list of stuff we just want to set the secure to be true if our if we are on production so if our note EnV equals to production then we want to set this secure attribute to be true so we can see a secure cookie so if you set the attribute to be secure right it will make it will make sure that uh the cookie will only work in the https setting so when we're in production and our app is on https we want this Tech to be true for security purposes okay so now that we have this luciia uh authentication uh luciia function that we can export let's go back into author action right so we are back here we want to create a cookie to be stored on the user's browser right so uh what we're going to do is we're going to have a session called await Lucia so we'll import Luci from our lip uh folder do uh do create session and we pass in the user. ID and a empty attribute here so this will create the actual session for us we can see that session has a few things is expires at we can check whether it's fresh we can check the ID of the session and the user ID that is associated with this session so we created a session but we want to actually store this cookie or put it in a cookie and store the cookie onto the browser so let's actually create the session cookie first so it also comes from lucia. create session cookie we pass in the session. ID in here okay and now we're going to use a function from next year it's called cookies so cookies comes from next slhs right so using this function next yes is going to help us set a cookie on the users browser so we can call cookies. set we pass in session session cookie so sorry session cookie. name we pass in the value and we pass in the attributes here so this attributes will be like uh HTTP only secure equal to True Etc so then we pass in success equals to true and if we catch any error we're going to just return the error saying that something went wrong and we'll pass in success is false Okay cool so this Logic Let me just reiterate we just check if the user already exists if it exist we through an error if not we create a new user with a hash password we create a session for the user then we we create a cookie to store the session in the cookie and then we are using asking nextjs to make sure that the cookie is set on the user's browser so now whenever the user comes to a website it's going to basically give us the cookie and we can validate all sorts of requests to make sure they're locked in so uh if you come back to our sign up form here right we can do a weit sign up we get a response back C rest we can see the type of response is error or success here so we can check if a rest do success right that means we successfully sign them up we want to redirect them to uh to the basically authenticated page so we're going to import router so that we can redirect them so cons router equals to use router so imp import it from next SL navigation not next router so if it's successful we got to do . push and we going to do like slash dashboard okay and we're going also uh do a to notification so for TOS we're going to use soner so it's already installed when you install Shen so we do to. success and we'll do uh account created successfully but if there's an error we're going to do tool. error pass in the error here okay uh so the last thing we want to see the toll show up we need to go into our layout. TSX right we need to add a toaster uh component from soner here and we'll pass in Rich colors to be true here so if you're not familiar with sonor it's a really cool toast library right that gives you this actually let me show you here top Center so you can see this toast event being created so this is what sonor does so whenever they successfully register we want like a cute little to to popup saying that hey you successfully registered okay so now if everything should work I should create a new account new user should be created and I should be redirected to SL dashboard so let's actually try that out so we'll have a Elliot gmail.com we'll pass in the name of Elliot Trump we'll pass in the password of 1 2 3 1 2 3 1 23 and 1 2 3 1 2 3 1 23 and I'm going to press sign up and something went wrong did something go wrong uh sign up if. successful so let's see what's the error so sign up uh something is still wrong we're in sign up form we are waiting sign up so this goes into here while making sure that everything gets created cook keys. set okay and then we return it uh let's say you refresh the page maybe it's invalidated so we'll do Elliot gmail.com Chong we'll do 1 31 three sign up okay user already exists so it got created just now it's just that maybe we didn't refresh it so at least we know that it works user already exists that means it exists in our database so if you come down to our database to check on it so we see we come down to our Prisma into our def. dbe we can see that there's a user ID so I to you to look carefully so we have a user ID a user row with the email the name and the hash password right we got the Argan hash password and we get a session token so only to keep track look the user ID starts with clxv and the session we can see the user ID is clxv and we got this session ID called H25 F so where do we actually see this session ID H2 5f if we come back into the browser right and we come down to our application and let's look into the cookies we can see that aliot of cookie remember the name that we set in here remember the name that we set in Lucia here Elliot off cookie it shows up as a cookie name here and what is the value inside this cookie H2 5f so what I'm doing is I put the session ID in the token and now the token lives on the browser so now whenever the browser makes a request to my web server I'm passing in this cookie along with this session ID so with this session ID I can look up the user that's loged into my application and now I understand that this user trying to authenticate with my platform is Elliot right which makes a lot of sense and we have expires at few okay so now we can sign up let's actually uh allow them to sign in right so sign in is also a very similar process so let's actually also create a off. action. TS okay so let's actually create a new function here called export cons sign in so this would be a very similar thing so be Asing uh Asing function with the values being z. infer we passing the type off but this time it's the signin schema that we import from our signin form and for now I'm just going to delete all this here I just want to console. loock I'm in the server signing in and my values are the values here so I try to make sure that my values are getting back to my back end so let's come into my signin form and then whenever I submit this form what I'm going to do is I'm going to do sign in which is comes from my allo action right we'll have a rest equals to A wait sign in pass in the values here so let's just make sure the value show up here so let's convert this into a Asing function save this and now let's actually open my console here so we should be able to see something happening so I'm going to sign in I'm going to just pass in this I'm going to press loog in so then I can see here in the server it works I mean the server signing in if I change the name here like something random I press log in I can see the server uh console lock again so good to see that it's working so now let's actually code out the logic so for the signin flow is actually even easier because we just want to get the user ID create the session for them create the cookie for them and as next just to set the cook keie on the browser so that's actually pretty St straightforward so let's do that so the first thing we want to do is let me check here we got to check we can find the user so we do await Prisma us user find unique where the email equals to values. email right so this values is the form values I'm passing in so if there's no user or there's no user. has password that means like it doesn't exist or for some reason uh there's no password Here we can return success being false and an error of invalid invalid credentials okay uh but if the user exists we're going to check if the password matches so cons password match equals to await await new Argan 2 ID we going verify that the users hash password so this user is the one that's coming from the database here right and we want to make sure it matches the the password that they sent in through the form so this is a Boolean right so if obviously the password does not match we want to do the same thing here return uh a FAL success and saying invalid credentials right but if everything works here that means we we successfully create them successfully log in we want to create a session cookie for them and put it onto the browser so we have a session is the same thing so we do a wait luia do create session pass in the user. ID and the empty object then we create the session cookie right so we put the session into the cookie it's await lucia. create session cookie pass in the session ID and lastly we asking next yes now that we have this cookie help me put this cookie into the users's browser so we do cookies. set pass in the cookie name values and attributes and return the success of true okay excellent we are done with the signning logic look at how simple that is so now coming to the signin form we're going to do the same logic here sign in form we will do uh let's see okay so if if rest. success we're going to do router. push so where do we get the router from router equals to use router from next SL navigation we do router. push to/ dashboard where they're going to see the dashboard info right if not we're going to just do to do error right rest. error but if they successfully loog in let's just give them a success tools log in successfully okay so now if I try to to log in uh if I okay my password is going to be wrong it's going to say that invalid credentials but if my password is correct they should create a session cookie for me and redirect me to the dashboard page so let's try out but invite credentials um let's let's just test Elliots gmail.com I actually forgot what I even put here so I think the password is 1 3 1 3 1 23 okay so edit gmail.com is the user and then my password is 1 123123123 login so we can see it successfully reg uh directed me to SL dashboard so uh we loged in so we loged in so now let's actually try to get the users information okay so uh to get the users information let's actually create a utility function for this so come back down to your lucia. TS file right we're going to export a function called get user okay so whenever so let me go back to my excal draw so whenever a user uh how do I draw a user if a user tries to make a request to my nextjs app server right the user itself remember is carrying with it a cookie object a cookie and this cookie contains the session ID which I know I can look up into the database to find out which user is holding this session so when the the user comes in to make a request I'm going to basically take the cookie out from them right and I'm going to look up the session ID within it I'm going to match the session ID in the database to find out the user ID and then I can see who's authenticated with me okay so that's the logic I'm going to try to implement that so this going to be a async function okay here and then what we're going to do is we'll do concession ID equals to await uh sorry we're going to get uh cookies so these cookies come from next year so remember we are trying to extract out the cookies right so we'll get the cookies called luciia for session cooking name so remember this session cooking name is what we set here so I can do the same by doing it here right but like this is a more less hardcoded way of doing it so we'll just do lucia. session cook name okay uh we're going to check for the value of it so this will get back the actual session ID right so remember if you come down to our app here we can see that under application here this's this aliot off cookie we're trying to get back this session ID here right and we'll just do if we don't have this we'll do it now so if you have you have no session ID obviously I know that you're not authenticated with me so I'm just going to return now like there's no user authenticated with this request okay so for now I'm going to just console. loock out the session ID console. loock uh I have session ID and I'm going to show you the session ID okay so how do I actually call this get user object here okay so I'm going to create first create a dashboard page here so let's un go under I'm going to clear out everything we have here let's come down to/ app let's do slash dashboard SL page. TSX so this will correspond to SL dashboard so let's export a RFC boom here and do dashboard page so let's just do make it a async server component right I'm going to do is I'm going to do cons user equals to await get user which I'm using from the function that we are literally just writing right here right I'm going to just uh this is going to run on the server so we're going to see that it's going to be console to lock out on the server all right so we can see that it's already I I see my session ID because I refresh here if I refresh the page we can see the dashboard page here uh but also we because we're calling this function we can see that the session ID we're getting the cookies we're getting the aliot off cookie we're getting the value and we're getting the session ID so this is the session ID we get here we can see that that it corresponds to whatever we have here if I copy this we can see it's the same value right and now if you go back into our database I'm to show you this database dev. DB we look under our session right we can see we got this cab TDX session ID and this is correspondent to this user ID right so now I know this who is authenticating with my server so I can easily get the user from this right so what we're going to do is we're going to get two things but we're going to use Lucia await lucia. validate session pass in the session ID so this is what I mean by Luci providing us with utilities Lucia will help us look up in the database to help us get back the user to uh user information ourselves all right so we'll get back the session as well as the user okay so now let's actually console. log out uh uh the user us is user okay let's save this and now we can see the user is this ID here I get back my user ID right so we can get back the user and now we have to check so the first thing we going to do is we'll put everything in the TR catch block so we got to check if there's a session and the session is still fresh that means it has not expired right so obviously if we expired we're going to basically unauthenticated them right so but the thing is if they have uh not exp if they are not expired yet the session is not expired we're just going to redistribute them a new cookie so that uh you know they have a fresh cookie to play with so we'll just have a new cookie session cookie right using Lucia do create session cookie we pass in the session. ID so we're basically refreshing their session cookie and we'll do the same things we do cookies do set so you already know how this works but asking nextjs to reset the session cookie for us right so obviously if there's no session okay that means something is wrong something is broken if there's no session we're going to basically clear out the session cookie so we're going to take away that cookie from them so they cannot like reauthenticate so we'll have to clear a session cookie is the same as setting an empty cookie for them so we have a set a empty session cookie await luciia do create black session cookie right and then we're going to basically Set uh us next year to kind of set the session cookie to be blank so this basically deletes the session cook key from them right and then we can just uh be done with it so we're going to check here we got to find so now that we have this user object we got this user object uh we want to check for the user so how do we get the user we can do user equals to await Prisma we can look up the Prisma database ourself Prisma the user do find unique where where ID equals to user. ID okay so we name is to DB user so this user comes from this uh lucia. validate session so after this we're going to basically select a few FS from it so we only want the name to be we want the name the email and the uh actually we just need this to we don't want to return the hash password right so then finally we can return the DB user so what this does is it will look at the session the cookies and it will uh do the logic to finally return us with a DB user and now if we come back to my dashboard page I can finally see this user to be a type save object with the name and the email so I can first check if there's no user right that means they're not authenticated and trying to access the dashboard page which is wrong because they is protect right protected so how do we do it we're going to basically redirect them so import redirect from next SL navigation redirect them to SL authenticate okay right so after they authenticated we are sure that the user exists then now we can finally display the user let's display user.name so do say you are logged in as user.name and user email so let's save this come back to our page and and boom so simple you're logged in as Elliot gmail.com okay and obviously now we can still go back to authenticate which doesn't make sense because I'm logged in right so let's actually make sure that if they already signed in they cannot access this authenticate page so let's go back to/ authenticate the page. TSX we're going to do the same we're going to make it Asing component we're going to get the user way get user from our Luci off so if there's a user so the user exist that means you lock in we can re return a redirect response to SL dashboard okay so if we save this now we can see that we locked into dashboard and if I try to go to authenticate I'm going to press enter authenticate boom I can even see the authenticate page because it redirects me instantly to/ dashboard right and vice versa like if I'm not logged in here it's going to kick me out of this of the dashboard and so let's let's actually emulate the logging out by basically clearing my session cookie so if I come down to application and I basically delete my session cookie and I refresh the page and we can see we are kicked out because when we try to run this get user function we can see that there is no session ID so we return now meaning that there's no user and if there's no user we kick them back to authenticate this is really simple so it's also really clean to implement okay so now let's actually create a function to lock them out manually instead of forcing them to clear that cookies right so let's just lock them in first um let's do Elliots at gmail.com let's log back in 1 2 1 2 1 2 three right we can see log in successfully right so let's actually create a log out button so the first thing is come back to our all. action. TS so we can export a Asing we can export a function called log out which is an async function and all I want to do in this is to set a blank cookie for them right so setting a blank cookie as I mentioned is the same as deleting a cookie from their browser so we'll just do con session cookie equals to await luciia do create blank session cookie and then now I want to ask next GS to set the session cookie for me so this will basically set the cookie to be blank which means it overrides it and we just return success of true so now we got this uh very handy function instead of returning success of true we actually just directly redirect them back to/ authenticate like this so when you call this function it's going to overwrite this and going to return you back to authenticate which makes sense right so now let's actually create a under components let's create a component called sign out button. TSX let's do uh use client cuz we need the on click functionality TSR fce right uh so we're going to do like chose children right we're going to do like react react node and we'll unpack the children and we'll see we're going to create a button here and we'll put in the children here and then we'll do on click what we're going to do is we're going to call sign out uh do we export oh sorry we call it log out so log out we're going to call this function here so it's going to just log out here and then actually if we import our sign up button in now dashboard page dashboard right let's actually create import the sign out button sign out button let's actually say sign out boom you can see you got sign out button and when I click it it's going to clear my session cookie and redirect me back if I try to come back to dashboard we can see that I can even access it because it's protected right the moment I try to access it it's going to keep me back to authenticate right uh yeah so this is in and signing out with uh with Lucia so that took like what an hour to explain okay now the really interesting part comes in I'm going to try to teach you how to do Google oo flow okay let's talk about oo 2 so when you see social logins like you press on the Google button and you see it basically redirects you to a page like this right it says like oh some app is trying to access your Google account do you want to share your your user profile information with this app and you press allow and then some for some like somehow uh the app is able to get your your the users information like the name and email and profile picture so this whole flow is called the oo flow I'm going to explain to you exactly how it works step by step so we got three parts here we got the next year front end we got the next year server back end and we have Google server so Google server is where everything is storing the actual users information right so imagine I got this user he comes to next year front end right and he wants to log into our application but he wants to sign in with Google whatever that means so he sees this like Google signin button right he clicks on it right so what we're going to do is we're going to basically ask Google for this information we're going to uh ask Google can we access this users information on behalf of him right so imagine this guy is called Elliot is me okay and I'm logging into this application right so I'm basically giving permission like I'm aliot uh I'm giving Google permission to give the application access to my information right so the first step here is what I'm going to do is uh when the when Elliot clicks on the Google button I'm going to redirect them to Google to Google's auth uh to cre I'm going to redirect Elliot to Google's credential screens like consent screen so Elliott is going to see a screen like this right and Google is going to tell Elliot okay this next year application is trying to access your information are you chill with that right and for me I will say allow like I click on that yes I want to give my information to this guy to this application so then what happens is Google is going to say okay fine uh ell has given you given this project uh permission so I'm going to send I'm going to give them a redirect URL so imagine my next J backend livs on Local Host 3000i off/ Google callback right so I'm going to give uh Google this call back and whenever Elliot gives Google permission Google is going to hit this next year's back end this call back URL and Google's going to give me a few things Google's going to give me uh uh authorization code that's actually the main part Google just G give me an authorization code okay and now I have this next year's backend I got this authorization code I'm trying to get the user's information right so the fact that I have this authorization code that means the user has given me permission right so what I'm going to do is I'm going to take this authorization code I'm going to except I'm going to exchange it to Google server I'm going to exchange it for another code called the access token right so now I finally have this access token I can use this access token right to request for the users's information on behalf of the user so Google will have another server called Google's uh data endpoint right so I'm going to use this access token to exchange to exchange I'm going to draw it here I just draw it here like this I'm going to exchange uh the access token for the user information so then the final step is I finally get back the the users email their name their profile and what information I'm trying to get from them so we can see there a few steps right so the first step is uh I'm going to just copy this over cuz I drew a visualization before so I'm going to delete this uh I'm going to move this over here so this is the actual diagram that I was referring to so the first step is the user clicks on the Google button it is being brought to this consent screen here and the the consent screen has the structure of this so you can see that accounts.google.com O2 right the client ID this is the client ID of the application of my app here and then the redirect URI which is the back end in which I want to redirect them which Google redirects to whenever uh the user gives them permission tool so in this case the redirect UI could be like HTTP Local Host 3,000 / API callback something like this right and the rest response type is code that means we're going to it's going to give us back an authorization code right and the scope is basically what I'm trying to get from the user so I'm trying to get the email of the user and like the profile their pictures and Etc and finally we got the state so this state is like a unique code like it could be a random string here that's generated here and this St is just for us to verify that whatever response that Google returns us with here make sure that the state is the same so this prevents some cross-site request fery attacks so this they're going to fill this up the user is going to press allow and then it's going to send it's going to look at this redirect URI Google is going to send a get request to my redirect U here so imagine it sends like a it sends to Local Host Local Host 3000 slash call back right and it's going to pass in the authorization code so remember what I was saying is it's going to give us a authorization code here and it's going to give us a state so this is the state that was generated here it should be the same here so let me just copy here so we're just going to make sure the state is the same to prevent uh any request forgery so imagine someone like uh forging this request that would be terrible right so now that we have this authorization code we're going to take this authorization code we're going to get we're going to exchange it for an exess token so the third step here is exchange this authorization code for an access token from Google server and now that we have this access token we can finally get the juicy juicy user data okay so this is a high level overview of how over o flows and in fact there's actually much better diagrams here that I can show you um okay here's a very general or flow so just now was very Google specific but let's just look at this diagram here okay so this is the abstract protocol flow so the client which is the browser it's going to send an authorization request sorry it's going to ask the user uh are you sure you want to log in with Google do you want me to to get permission from Google to get your information so the user is going to Grant access to the application in this case the analogy here will be them clicking on the consent button so it will Author grant us authoriz ation right then we get the authorization token we're going to go to Google server to exchange this authorization code with an actual access token right so this is like our step four we're going to exchange the authorization code with the access token so now we got this access token we can finally use this access token to exchange it with your resource server for the actual uh user data that we want so that's a very abstract flow when I code it out step by step it's going to be much more intuitive so let's begin okay so for this we're going to be using this Library called Arctic Arctic is what is uh helping us to deal with all this authorization code thing like parsing it uh getting the code getting the token uh exchanging it for exess uh tokens and managing all the like you know the the state variables and all the request fery stuff so this is like a really cool library that handles o off utility functions for us so it supports all this Pro providers like apple atash off zero GitHub all this stuff so obviously Google is one of the more popular ones here so we're going to be using this arlick library to help us Implement o flow okay cool all right so the first step is we're going to just add a Google button on top here right so uh let's actually just create a new component here components let's just do like Google o off button. TSX so do use clients TS uh actually just R fce should be fine Y and save it let's go into our What's this called authentication page here and let's actually just put it on top here can we do that um let's just do like uh Google all of button so we're going to see Google all button showing up here okay cool and now let's actually go in and install it so let's just give it a make it a button here and we'll say continue with Google and we got continue with Google here pretty cool and let us just give it some space so let's just do a height of four here so we get some space between everything here okay and then in this we're got just add icon here cuz I love icons um but we do have icons here so I'm going to just install uh so but install Lucid Dash react right so just a pretty cool like icon Library so let's just like Google so import from Lucid D react so I think there is a Google button here am I wrong do they not have a Google button here that's so weird Google I swear I saw it before okay I guess they do have it but you know who has It remix icon has it so let's get remix icon remix icon react boom boom boom so let's do sudo bun install remix at remix icon react okay so let's do like the let me get this out Google button okay we have this import r i Google Feld from at remix icon react so then we can actually put a r Google F here and put a margin R of two and let's hope that it looks nice okay that looks pretty decent so then when I click on this obviously I want something to happen on click one to say like console.log logging in with Google Bo so let's just see that when we click on this loging with Google is cool all right so to to actually set up a Google application you need to come now to cloud.google.com and set up a new app under Google Cloud console okay so once in Google Cloud console you're going to create a new project so just create a new project here let's name it uh Lucia d off- yoube right and create a new project so this should take pretty fast like a minute or two so once you once it's done you can click into it so let's find so once it once it's done you can click into luciia D off- YouTube and come down to uh uh o off content screen so this is a consent screen that the user will press continue in order to give us permission to access your data so let's just uh configure it which choose external create and put a name for the app so we just call it like Lucia YouTube demo put a user support email just put yours uh you can put some other stuff if you want but the most important one is to put a uh contact information so then just press save and continue and for the Scopes you can just leave it blank here right save and continue uh save and continue and then back to dashboard and I want you to just basically publish the app so this will make sure that like uh anyone who is using it can actually log in instead of like specifying your testing mode so now let's go into the credentials and we need the Google client ID and Google client secret right so if you remember in the drawing what's my drawing where's my my drawing XC draw okay remember here there's a Google client ID client ID so we're trying to get this client ID so let's actually create credentials or of client ID okay let's name is a web application you can name it whatever you want for the JavaScript Origins you can just put as HTTP c/ loal host 3000 or whatever you're running your application for the redirect URI so remember we are basically telling Google whenever the user give me give you per Mission you I want you to redirect to my uh backend endpoint so it's very important you set the backend endpoint correctly so let's just do uh HTTP call loal host 3000 and we'll do/ API SL off/ Google SL callback so please remember this U it's very important later so while we on this we're going to press create actually before that we actually create the backend end point first so let's come down to our app we're going to create a folder called API and inside the API we can we can match the structure so we need off folder so we need off then we need Google then finally we need a call back and then we have root. TS so then we can export a Asing Asing function called get right which have a request which is a next request and we'll just do console.log request for now so it's just a a stop function so this this this function here will correspond to http col loal host 3000 API sl/ Google callback right so you can see the folder structure here it should match exactly what you put in here and it should match exactly what you put in here so this is important because this is the backend end point this is the backend end point that gets hit here when we trying to exchange the authorization token so this important so now let's actually find press create and we should be able to get our client ID and client secret so I'm going to copy this in here come down to myv I'm going to just name it Google client's ID put it in here I'm going to do the same for Google client secret Google client Secrets put in here okay and we need one more thing which is the next public uh URL for now it's going to be HTTP code such as Local Host 3000 when we deploy it later on is going to change to the proper domain name okay so we got this three variables that we have added make sure that everything is good and now we can actually do the interesting logic here so remember just now I talked about the the Arctic Library so let's actually install Arctic first Arctic okay pretty cool pretty cool and now I'm going to create a new Under lip I'm going to create a Google or o. TS and this is where we actually initialize the a Google client so what we're going to do is we're going to import a few things import actually just import one thing from Artic right we can see that you can have a lot of stuff you can have Amazon Cognito Apple GitHub things like that but we're looking for Google only okay so we're actually going to export one variable called Google uh o off client right and this is going to be a new Google instance and we can see the new Google instance needs three things client ID client secret and redirect URI and the Tre things that we have so let's actually do that so the first thing is process. env. Google client ID so make sure this name matches up with what you have in the ID here the name here and then we have and we have uh Google client secret and the the third URI which is the next public URL combined with/ API all/ gooogle callback so this is what we're talking about here right we got the client ID and we we tell them where's the redirect URI after the user confirmed it so let's just set exclamation mark to make to tell uh typescript that it's going to be here okay everything looks good and now what I'm going to do is uh we can actually do interesting stuff now so the first step here is whenever they click on the button remember they click on the Google button we want to redirect them to this authorization URL this consent screen so where where where is this consent screen let's actually create this URI to redirect them to so what I'm going to do is come down to our off. action. TS we can export a function called uh get Google o of consent URL it's kind of long but I'm trying to make it uh very intuitive to understand so it's going to be Asing function right so this function is going to be pretty pretty cool uh okay so the first thing is let's wrap everything in a TR catch block okay so the first thing is we're going to generate state so remember this state is what is this variable that's being passed in here so this is just needed for security purposes so this state will just be from generate state that we can import from Artic here right so Arctic provide us with this uh function here so it's literally just going to be a string right just like what we see here okay and then we need a code verifier right so this code verifier is needed to actually get the author ization token out later uh the authorization token being the the stuff here you see this authorization code here okay so this code verifier we can also get from generate code verifier from Arctic okay and then now what we're going to do is we're going to store this in the cookie so later when the when Google basically returns us returns us this URL to our back end we need to basically get back the state and the the code verifier to make sure that the request is still valid right so we need to store it across the request somehow that's why we are storing in the cookies so we storing the cookies we set the code very fire we'll store it as the code verifier and then we want to make sure that HTTP only is true and I want to be secure when I'm in production so when I'm in production this will be secure okay and I'm going to do the same for state right the state so you see both are just strings both are literally just strings there's nothing complicated about it these are just security measures so I'm going to copy this down I'm going to I'm going to name it State and I'll just do okay so now we have put in the cookies we can actually generate this long ass URL here okay so let's actually do this so we do cons of URL equals to await Google o of client so this Google o client is the one we we we initialize here right we're going to do generate uh sorry create authorization URL we're going to pass in the state which is this digit string here we're going to pass in the code verifier and the last thing we do is we need to pass in the options here which is to Define what are the Scopes what are we trying to get from the user in this case I just want their email and their profile so this will give us the like the name the email the picture Etc okay so this Scopes is like what I'm writing here you see this Scopes this scope is going to be this URL later and what we're going to do is we can just return a success of true and the URL to be this all URL I'm going to convert it to string okay so this all URL is a part of your is a URL object and then if there's any errors we're going to return success to be false and the error being something went wrong okay but before this uh okay now that we're here let's actually go to the Google o button so when they click on this okay I'm going to do cons URL equals to await gets uh Google all con send URL right so if you come back here when they click on this button I'm trying to get this URL let's just console.log what this URL looks like okay boom here let's just make this async save this let's come back to our app uh okay so if I press continue with Google I should get this URL and we can see let's actually dissect this out I think this pretty cool so let's actually dissect this out to excal draw let's see how it looks like okay you can see it's exactly what it is right accounts of google.com right let actually par it down our response type is code right which we have here I'm going to split it up here response type equals to code right we have here our client ID which is the client ID that we got from the CL Google Cloud console we got a bunch of Scopes that we're asking from for the user we can see email and profile and all that stuff we can see the code challenge right this for the for the for the verification token later right so now that we have this right if you if you redirect if you go to this actual URL we can see that it is a uh it is a how to you see it is the content screen but there is something wrong here uh let's actually see what's the error here but what I'm going to do is just once I get the Google o of consent URL uh let me check is everything correct everything seems correct okay let's just try out first so we're going to basically get the response so if response if we have a response. URL we got basically window do uh location. hitra we're going to set it to the response. URL so we're going to basically link them to that URL if not we're going to say that there something that went wrong to. error okay so let's actually try out so if I come down to my app okay and I press on this button I should be redirected to the content screen and boom okay perfect everything works wow I'm lucky today so it's going to say choose an account and I'm going to just click on this email so what what this is going to do it's going to then redirect us to the/ API callback and boom correct so we can see this URL that they redirect us to Let's actually uh investigate this together so this is the redirect URL so the first part here we can see this first part is exactly the redirect URL that I gave Google right so this is redirect URL and the state here is the state that I generated through otic so I'm going to basically compare the state to make sure the state is the same to make sure there's no request forry and then there's other thing like the scope and then I can also see uh the off user and the prompt and so I should able to get the author authorization code from this URL using Arctic so let's actually do that now so let's go back to our root. TS this is the this is the URL that's being hit the Callback URL right so now let's actually do the interesting logic stuff okay the first thing here is we're going to we're going to get back what we're going to get the cons URL equals to uh request on next URL okay we're going to get the code and the state so we can see that there's a few things we are trying to extract right we got the code here sorry I can see here code so this authorization code here and we got the states which is somewhere here that we saw just now okay I'm trying to extract the two values out so let's do that so we'll do con code equals to url. search programs doget code right and then I'm going to get the state out of it as well and I'm going to check if there's no code or there's no state I'm going to return a new response saying that okay something messed up like we are not supposed to be like this invalid request we'll pass in a status of 400 inite request I'm going to console. lock console do error no code or state okay zoom out a little bit okay so it can see it here okay but if I have a code and a state I'm going to get the code from the cookies remember we St we stored the code verifier and the state in the cookies right we stored it in remember we stored it here we're going to retrieve it back from the request so we going to get code verifier equals to cookies from next year. getet code verifier do value and I'm going to get the state right soorry the saved state from the cookies as well I'm going to then compare if I have no code verifier or I have no Save State I'm going to return the invalid request as well right and then I can check if the states that I have does not equal to the save state that means someone has tempered with my request that's not good I'm going to return a invalid request as well okay so now we get we are in the diagram we are here we are parsing out the state we're now trying to ex get the authorization token and trying to get the exess token okay so how do you exchange the authorization token right we're going to get it from await Google all of client right remember is this thing here o o token sorry o of client do validate authorization code right we can pass in the code here this code comes from uh the code in the search perams right and I'm going to verify it with the code verifier so this once we do this it's going to finally return us with the access token so this is the juicy access token right we can get other stuff too but this is a juicy access token that I can use to exchange for actual user data isn't that pretty cool right okay so now we got access token let's actually exchange it right so let's get cons Google response equals to await fetch right we're going to fetch from this URL uh fromom here right or of V1 user info I'm going to exchange it for the user info I'm going to pass in the headers I'm going to pass in the authorization authorization header to be a barer token and I'm going to pass in the access token so I'm going to exchange this access token for actual response so this Google data right it's going to be await sorry await Google response. Json right what's the shape of this right uh the shape has it has ID right it has email it has name sorry name and we have the picture obviously there are more things you can console.log this out to go and explore yourself but I'm just I'm just interested in these four attributes right so finally I can do I'm going to basically get Let's uh user ID to be a string for now MD string because now that I got this user right I can do two things if uh the user if the you if the email exists in our record we can uh create a cookie for them and sign them in if the email doesn't exist we create a new user then create cookie to sign them in so anyways we're going to just create a cookie for them okay so we're got to first check con existing user equals to await Prisma do user. find unique where the email equals to the email that's passed back from Google data right Google data. email so if I have a existing user okay I'm going to set the user ID to the existing user ID I'm going to delete this right existing user ID but if I don't have a user I'm going to create a new user it goes to to await Prisma do user. create pass it in uh the the name to be Google data. name the email to be Google data. email and I do have hash password and so there only two things I have um actually I have a picture fi so what I'm going to do is I'm going to come down to my schema at the Prisma I'm going additional picture F to be a optional string because if you loog into normal user and password you do have a picture and then to push this up to my database I'm going to do p sudo bu x uh Prisma DB push so this will add a new column in my database pretty cool okay so now I can see there's a new picture VI here I can put Google data. picture and then I'm going to set the user ID to the newly created user ID okay so now we're finally done we can then create a session cookie for this user and put it onto their browser and now log them in through Google okay so we're going to just create session you've already done this so many times I'm sure you understand create a wait Luccia do wait we have to make sure we import it from the correct luciia package lucia. create session pass create session pass in the user ID and the empty attribute sorry we can just put user ID and then we want to create a session token oh sorry session cookie to be await Lucia here do create session cookie passing in the session. ID and then we can do cookies from nextjs oh like here do set session cookie. name oh session cookie. name session C.V values and the attributes and then we can return a redirect to SL dashboard so we log them in and then we're going to just directly redirect them to dashboard okay so pretty cool pretty cool and actually we can do uh rest. redirect rest. redirect and we get the rest from the second attribute okay can we do rest. redirect no uh I guess we can just directly do the redirect from next SL navigation we can just do/ dashboard here this works as well okay so let's just recap a while so we are getting this Google is going to return us hit this callback URL after the user authenticates and gives us permission we going get back the code and the state right and we're going to exchange this authorization code for the access token we're going to then use this access token to get back actual user information right we're going to check if the user already exists if they are not existing we just create a user for them and finally we create a session we put a session in a cookie we we bind the cookie to the browser log them in and redirect them to dashboard so I hope this lines up with the flow that I've demonstrated here right and now finally finally this should work like this should work perfectly like we pray so I'm going to go back to Local Host 3000 um SL authenticate okay I'm going to press continue with Google I'm going to authenticate here and by Miracle it should invalid request so let's look at the error State mismatch so there's a state mismatch okay so let's find out why does a state mismatch um State mismatch uh State here the state get cookies to get State here we're setting it up here get conent screen set State okay okay this a super silly mistake I was coding too fast and when we're generating the code the URL right we can see that the state I set it the code verifier it should be the state variable here in the state okay it's a silly mistake so let's hope that now this works so let me go back here and now let's continue with Google press this and hopefully it doesn't work what's the issue now okay so it looks like the Prisma okay so it was just a Prisma issue because we added a new column we just need to reset restart our def server so to make sure that prismal is able to head handle the new column okay so let's just come back here and let's pray that if f it works so we're going to go to/ authenticate continue with Google select this and now it should work it should work okay continue and boom works so we can see we logged in as electron 16 that's my email that from Google and if I come down to my database DB def. DB I can see a new user with my email my name and uh there's no hash password but there's a picture here if I look at a picture here I should be able to see my profile image so that is cool so now let's just do like some super simple styling on this uh dashboard to make it not so ugly okay so if you come back to our dashboard page dashboard page we're going to get the uh we're going to do some symbol styling okay so we have a diff we have a class name of absolute uh left of half top of half negative translate X of half negative Translate Y of half okay so this centers everything in the middle okay and then what we're going to do is we're going to check okay if user the user has a picture okay so we need to go in here to get user we need to get out the picture vi from the user here from the get user function when we are pulling out the Prisma DB so if the the user has a picture I'm going to render a image com a next next SL image right the source will be the user. picture right I'm going to give you a class name of class name of of rounded four uh height of 16 sorry size of 16 okay and let's do a height of like 40 and a width of 40 okay and then let's just do this first it's going to True an error because we need to configure this inside our next config so let's go into our next config let's do images images let's hope chgb is able to complete this for me okay remote patterns we get the l3. Google user content so when we save this is going to restart our server but then it's going to allow nextjs to help us optimize the Google profile pictures so now let's actually restart and refresh this we should be able to see our image showing up here nice and rounded cool cool cool and then in here I'm going to just delete this we're going to make it nicer we'll have a flex flex-all here okay um before that I'm actually going to wrap everything here into a flex Flex container inside this Flex call I'm going to do a span with the user.name and span with the user. email okay so let's see how this looks okay pretty chill so let's actually Center this so item Center on the first diff here we'll give you some Gap in the middle okay uh I'll give it a border padding of four rounded large okay save this so this looks pretty good uh let's give it a BG gr of 100 transition all cursor pointer and then when you cover of it I'm going to give you some Shadow so now it looks like this pretty pretty cool okay and then for here let's actually give this some class name so it doesn't look so ugly font semi Bol text- XL and for this pen we have a text Gray 500 save this and look it looks really nice okay and for this sign up button let's actually put this uh let's put this in the corner of the screen so let's position it absolutely so bring this down we put it in absolute container let's put it on the top right right off four and top of four let's put the sign up button here and sign out works if I press sign up we should sign out pretty cool I can still sign in with my Elliot gmail.com 13123 uh except there's no image right right my Google still works I can try my this other email so this will create a new account with me and now I get this pretty cool logo in here I can sign out and everybody's happy everybody's happy so these are protected routes as well we can see that there's no user we just redirect them to/ authenticate authenticate um okay uh I think that is pretty much it
Info
Channel: Elliott Chong
Views: 13,706
Rating: undefined out of 5
Keywords:
Id: t-JJgTRf3Ms
Channel Id: undefined
Length: 123min 19sec (7399 seconds)
Published: Thu Jun 27 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.