Building a SaaS from scratch Episode 2 - Finish Setting Up Auth, Database & More

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
for [Music] all right guys so if you're joining in um I'm just going to go ahead and start I know it's a Friday night so we might not get that many viewers on a night but pretty much where we left off on in episode one was we created a nextjs application then we started working on the register page and we are working on it through ajs version 5 so if you're not familiar with it we're using ajs version five which is in beta um we installed the package right here um we configured our application with a .ts file a off. config file and our catch all route we are using the git uh the Google provider and the credentials provider so we set that up and the Google provider we went through the Google Cloud console we answered the questions necessary to get that up and going so our Google provider is working and it's getting sent back to our database which we are using mongodb and we're using prism orm to actually connect it so the Google provider is completely done it's functional working how it should and it's actually sending users to the database and then where we left off last night was we finished the form and we used the form from shat CN and we finished the form on the client side and then I was working on the onsubmit and then we ended the stream there so that's where we're going to pick up on and we're going to start from there I did write a few things that I want to get done in the Stream So for this live stream number two we're going to complete the UI of the register and login form we're also going to create the functionality functionality of the register and login form so the back end we're going to create a functions that gets the current user from the session so that's by using the O uh function that next off provides us and then we're also going to create a function that creates and send an email verification token and then we might do more stuff depending on the time but that would almost round up all the authentication for our SAS product and if you don't recall the SAS that we're creating is going to allow users to build pretty much a chatbot widget on their website very easily especially it's pretty much like a no code uh chatbot they're going to be able to create a custom chatbot based on PDF files a website site Maps um just any documents that you want to feed it they're going to be able to get a script tag place the script tag in the head of their application either it's Wix WordPress any kind of coding application they should be able to do it and then they're going to have a widget on their website that's a custom chatot so let's see if anybody has joined looks like we got somebody in here so um if you're in here if you want to ask any questions you can I have the screen open on the other side but other than that let's just jump into the code and actually start coding stuff out so I'm going to close a bunch of files up right here okay and I'm just going to go have this on full screen like this and then I'm just going to go back and forth between the pages like this and let me okay so what we have is like I said we ended up stopping on the register form and inside of our app directory we have a alt folder and then a register folder with a page. TSX we kept this as a server page because we want to make sure most of our pages are server side because there just a lot more benefits when it's all said and done we have a register form that we are rendering inside of it and this register form is the use client reason why is because we have to use a hook primarily the use form hook and that does require it to be a client side page and then we're also using the use State hook just so we could show a loading State on the button um we created a card wrapper um component and the card wrapper component is essentially just the card component from Shaden as you can see here and we have a card we have the card header we have the card content which is going to be all the children which all these children are technically everything inside of the register form so everything inside of this card wrapper so it's all of this right here okay so let's go back into the card wrapper and as I can see I have the card I have a card header which is the all header which is going to be dynamic depending if the page is going to be register page or if it's going to be the login page and what we want to do here is we are getting the label and the title we are getting that actually from the register form so as you can see we get a header label which is the create an account and the title which is the register and then when we have the login form the header labor is going to be pretty much log in to your account and the title is going to be log in so that is kind of how this goes and the next thing we want to do is we want to add a card footer and for this card footer we actually want to add the back button so just in case a user went on the wrong page the user is actually just going to be able to just click the back button and go to either the register page if they're login or log to the register um hey AOS what's up how you doing um can you please make a video on nextjs typescript prism mongodb from beginner to advance um yeah so you just yeah I could definitely do that let me um I always write down um video ideas inside of my notion so let me do that real quick so I'm assuming just like an overview of all that from starting from beginner to advance nothing very specific but just pretty much all the topics hey what's up herot haret I don't want to keep butching the name thank you again for joining I I remember you from obviously last night but um let me add this real quick so YouTube video projects and what I could do is it could just be on nextjs typescript prism and mongod DB I usually like adding this icon which just not doing now but that's fine and I'm just going to do from beginner to advance okay cool I just want to see how many this is the only way I could kind of see how many people are in here I just refresh this so we got you both that in here perfect okay so let's work on this back button right here that's going to go inside of the card footer so what we are going to do is we are going to create a component it's going to call be called back button and then the back button we're going to have to pass in a few things so for the back button we're going to pass in the label and we're getting the label from the back button label as you can see here I named it so we're going to have label equals back button label and then we're also going to have a hre which we're just going to say hre equals back on hre and it's a self closing tag self closing component and then we need to create this back button component so I'm going to do inside the auth right here inside of the components folder we're going to create a new folder I mean file we're going to call this the back button. TSX and inside of this we are going to make this a button from shaten so we're going to import the button and this is coming from I like doing the at symbol better so add SL components slui slbn and then we also need the link and this is going to be from next SL link so we could actually navigate to the other page we're going to Define an interface we could call back button props we're going to have the label as a string and the href as a string let's export um the cons as the back butt we're going to call this function back butt it is going to accept two parameters and the reason why is because we are passing them in right here inside the back butt so we are accepting the label and the hre so let's D structure that and then set it to back bun props as the type let's get the curly braces so we could actually enter our code let's get the return some parentheses and this is just a button component and we want to make it Dynamic that's why we're doing a different file because one back button might say um return to what what are the labels let's check real quick so the labels are going to be for this back bun label it's already have an account and the back bun href is going to take us to the Au SL login page so we're going to have a button let's just do that cover it and then we could have a link and the link it requires an hre property and the hre is technically just going to be the hre which is going to be the for slash uh Au SL login close this and then inside of this we can name the button as the label so the label is going to be like and it's lowercase l so like that and then we could do a different variant for the button so variant could equal link and if you want you can actually remove this and you could check out all the variants either through here like space uh I know there's a way you could do it but you do just a string and it gives you all the variants here and like I said we're just going to do link and you could test them all out to see how they look let's add a few tail and CSS classes we'll keep the font normal in the width full and then you have a size um attribute that we could add to this we could keep this small and then we need to add the ass child prop as well um and that's just coming through tail uh chaten docks let me open the um development server real quick and let's just keep making sure we go back and forth and looking at it I don't want to have it side by side because I feel like there's not enough room for you guys to see so I'm just going to go back and forth between the pages so we're at the off/ register page and we never um actually imported the back button because it's undefined so let's do that real quick so inside the card wrapper we're we don't have this imported so we're getting error and that's the file we just created what does the as child do um if you go to the nextjs docs not XS docs the shats the Nui docs and we go to the button component and if you look at the code um I'm not in the button so we go to the button and if you look at the code uh where is it as here it is alternatively you can set the as Ash parameter and Nest the link component so pretty much I guess it just allows you to NE excuse me allow you to Nest the um link component inside of the button so if you don't have to I guess Nest the link component then you don't have to has the as child parameter um I guess it just makes the link clickable that's what it does but the docks don't really give to too much but I know a bunch of these buttons and stuff are built off like radex um UI and uh stuff like that so that's what that is for um but now we have the back button so let's check the um development server so that is our register form right now for our um application looks pretty good um so if you already have an account it's going to take us to a page we haven't created yet so perfect so we have email name password confirm password um the thing we worked on at the end was if nothing's here we made sure that the titles were black instead of red and we have these error mess like invalid email name is required password must be at least six characters long and then just confirm passwords required and we're getting these error messages from just so you guys know where everything's coming from these error messages are actually coming from that register schema so the register schema right here password must be at least six characters long six characters long name is required uh stuff like that so you could change the error messages in inside of your schema okay so after we have we created the back button next thing we need to do is let's go inside the register form make sure everything looks good everything looks pretty good we tested the console log so we actually do get all the data and then we set the loading to true so next thing we need to do is we actually need to create the backend for this um on submit right here so the back end we could either use a server action or we can actually use an API route so I'm going to use a server action um essentially it's like the same thing as an API route honestly but the server action is a little newer and I know they're probably pushing that more than the actual API routes and there is a few benefits to it but I actually got to look at the docs to kind of see what they were I think it's like less back and forth between your client and um server and so forth but um let's create a new folder inside of just the root layer of our application called actions so this where we store all the actions and the first one we can do is we can do the register. TS file and the first thing for use server is you need to mark this as a use server to make sure all the code in here are secured on the server and because it's not technically an API route so we need to make this as a used server so this is for sure pretty much on our server um next thing we need to do is we need to do a few Imports so we need to actually import all from AZ from Zod we also need to be able to access our prism methods and our prism methods are inside of our lip folder and then inside the file prism db. CS this gives us Global access to prism client which allows us to actually use the methods like find many find One update update many delete all these prison methods you can see on the docs but that allows us to make pretty much calls to our database and then do specific queries that we need done and we're exporting this as database so we need to import that at the top database and this is coming from at lib prism DB another thing we want to do is um we need to encrypt the password when they register in our database for Extra Protection so a package we're going to do that's pretty popular is bcrypt um JS that's all we need to do is install bcrypt and it's installed I still have my server running on the other terminal we're just going to import bcrypt JS or just you could do bcrypt from bcrypt JS and bcrypt is declared but value is never read um could not find a declaration file for module bcjs try npm install so we have to install its types so we just copy this control C paste it and then we can install the types in a as a Dev dependency so this eror should go away and now it's away and it's just saying it's declared but value is never read um what if you use Aggron what if we use Agron rather than bcrypt I've never used Agron before but we could look at it why do you think it's better than bcrypt it's called Aggron um npm hashing passwords in Agron 2o h 172,000 uh 172,000 um th 172,000 weekly downloads let's see bcrypt I just want to see the bcrypt downloads almost 2 million B yes so bcrypt has 2 million weekly downloads versus Agron which has 172,000 um I think bcrypt is it seems like bcrypt is like tried and true l published was seven years ago lash publish was a day ago I mean it looks like it's get maintained more than this one but I I'm G to look in Agron agon is com confusedly hard to break is bcrypt easier to break or what's the deal with that Let me refresh this see is bcrypt easy or harder to break because um search Agron vers bcrypt have you ever used Agron before um more secure but demands more resources it's excellent for offline key derivation but can be an overkill for some web applications bcrypt offers a balanced approach it's less resource intensive making it a suitable choice for web apps where response time time is critical do you like it better than bcrypt as an injury like come across the concepts of data hashing when you're handling sensitive data both hashing encryption are important to craphy and are often confused and choosing the right algorithms for your use case is not necessary straightforward decision Agron 2 is designed by Alex uh is this him maybe not it might be Dimitri from the University of Luxembourg they released their specific paper on Agron 2 in 2015 in the same year they won the password hashing competition organized by a global panel security and cryptographic experts in their paper designers stated their motivation for creating AGR 2 was to maximize the cost of password crack that passwords despite all the drawbacks Remain the primary form of authentication BCP was designed in 1999 damn they based their hashing algorithm on Blowfish and encryption algorithm created by Bruce Sher in 1993 to take advantage of its purposeful expensive key setup phrase phase they state that the computer cost of any secure password scheme must increase as Hardware improves um do you let me see Agron 2 have you used it in a nextjs application is it seems um typescript usage so that's that's that's how easy it is right there it's that um a typescript type declaration file is published with this modular if you use typescript 20 2.0 that means you don't need any installation simply use the libraries mentioned above okay I think this is a good viable option I'm going to stick with BCP for my project but I'm going to do more research yeah it looks the same it's just like um cons has equals away Agron 2. and then the password seems it seems simple um that's easy change I'm going to do more research on it to see but um I'm G to stick with BCP right now but that's that's a really good recommendation I'm going to I started already just go back to later but yeah the downloads it's almost like 20 times more in bcrypt okay so let's go back real quick we have bcrypt from bcjs we also want to import our register schema from the schema folder and then let's create the function cons register equals a sync and then um I want to try to do this without looking at anything so if you have any recommendations for this um backend syntax let me know but we could go through this step by step inside of the register form we need to pass in some data to the back end so I could remove this console log is there any difference with between bcrypt vers bcjs um I don't know I think there is I just heard that bcjs is more reliable and just better so I always stick with bcjs but I think it is different um I'm gonna move the register um from the actions folder inside the register now I'm just going to pass in the data expected zero arguments but got one so we need to accept the argument down here we could do as the type c. infer how does that syntax look I'm just going to steal it from from here C am I doing something wrong with the syntax here [Music] um okay yeah there there we go so now we get the data the data is email name password password confirmation data is declared but value is never R okay so I know the first thing we should validate the date on the back end so validated data equals the Reg [Music] schema. parse we could use parse and we're going to parse that data we could console log this and see what it gives us validated data um let's go to the front end real quick and let's actually just submit a form it's going to keep loading because I never set the state off and it shouldn't do anything else let's check the console in our um server validated data email name password password confirmation so it's actually giving us um the the data and it's validating it through the parse so it's actually giving us a back okay let's just do a check I guess if there is no valid dat data let's return an error and then we could just say um invalid input data okay next we could do is I'm going to write the comments above so we know what's going on we're going to validate the input data then we are going to if the data is invalid return an error next we should um destructure the validated data so we get email name password and I think we get what is it password confirmation yeah I might change that name I kind of don't like it uh it's not bad okay so we revalidated the but we destructured the validated data next we're going to say we got to check the passwords I guess so if password doesn't equal password confirmation we return passwords do not match that's good so we could do a check on the passwords check it check if passwords match and if they don't match we're going to return an error um and if they after that yeah we can hash the password that means everything's good we yeah con has password equals a weit b cry. we get the password and we pass in 10 which is I think the default value for the hash and then we can insert the user into database um we we actually need to check we need to do another check check to see if user already exists so we're going to do cons user exist equals a weit we could use the database. user do is it f first I kind of want to know the difference between find I think there's a fine oh no there isn't wait yeah there isn't so it's a find first okay cool find first find many find unique oh yeah it's going to be fine first and then what we could do here is where and it's email let me just make sure so we go to our schema I'm gonna look in the user because that's the only way they're getting created when they actually register their account uh hey what's up Loco wouldn't it be strict does not equal um let me check you saw um you saw file not find I don't i s oh I typed file no I typed um there's no find it's F it's either find first find Manny find unique so find first I'm assuming and then you're saying this should be strict uh yeah it could be strict wait no it can't be like that though that's the wrong syntax I'm you have it like that equals yeah no problem Aman I'm I'm glad it helped I know I messaged you in Discord and you said you got it and I forgot to respond you actually yeah I could help you um I could help you what on whatever project you need help on as well yeah I don't you know what's a cool feature if do you guys have gith help co-pilot if you do say yes if you don't say no because this feature alone might like change your mind let me see who has it who doesn't okay while I'm waiting for you guys to respond to that um I'm going to highlight this code here and then I'm going to right click and then we have co-pilot right here this extension so co-pilot's like kind of um no no co-pilot it is a paid um pretty much extension it's a paid extension for um your VSS code but it gives you pretty much so many different features so if you actually highlight some code you go over to co-pilot and you could click explain this and then right here on the left side of the screen it will explain the code to you pretty much like if you put in a chat GPT so all of it is in one area and I mean you could do your whole component copy and then explain the code and it'll explain the code so for that operator the operator in JavaScript and typescript is the strict inequality operator it returns true if the operand are not equal and are not of the same type and in this case it checks password and password confirmation are not exactly same including both value and type I mean it gives you a whole explanation on um pretty pretty much the code that you highlight and that's just one feature of many obviously it finishes the code for you um and obviously it's not always always right but it's definitely learning and getting better let me go back what is you making um I'm making a SAS product that's pretty much gives the use the ability to create a chat bot on their website so we're a little widget so I'm going to show you exactly kind of how it looks so if you ever been on a website here at the bottom right you got a little widget and it's a chatbot so any person who has a website would kind of need this and we're going to give them the ability to pretty much easily create a chatbot without any code and we're going to send them a script tag so they can implement it into their head um on their code either if it's WordPress Wix whatever it is and then they'll have a chat boss set up in a few steps on their website so that's what we're creating hey what's up inspector appreciate it appreciate you guys joining insector Oaks hey BR it's good to see you here it's good to see you too man um but that's what we're creating we're creating the widget so we're going to have to create a script tag for our users so they could just implement it on their website um but that this one right here the one that you see on my website here that's actually from I keep voice flow so if you know voice flow they have a software like that as well um I know this isn't code helpful but have you heard of virra code what it is is a lature that joins characters or to make it look cool I actually haveen it I can look it up real quick but um and then have it on my screen fire code it's a font no it's an extension okay so it's like a font style okay cool I'll keep this tab up though I'm G to have so many tabs when I'm done but um let's go back to the code and my um development server so if you guys are joining this is what we've already created we created this register component if and we're working on the backend um logic right now so if you enter email password we register and it just goes to loading but if you look in our console and our backend I actually took the console log away we are just validating the data taking it through and we're doing checks for now so right now we're checking to see if the user already exists and if they do we're actually going to if the user exists we're going to have to return an error so you see all this code right here that's it's giving me recommendations this is gith help co- pilot like I said it's not not right all the time but it's pretty good and I think it's definitely worth it so if the user exists we're going to return an error that user already exists and obviously you could change it I just press tab if you press the tab button it it displays the code so after we do the checks we make sure the data is valid we destructure it we check the passwords match if they do match we hash the password then we check to see if the user already exists and if the user exists we return an error um next we just got to pretty much put the user in our database now so we're going to create the user and look how easy CL p is I've done this kind of code before so it it's trained based on what I've coded in the past so we are going to store the user in a user variable we're going to use the database. user. create we're going to create the email the name and the password we don't have to send the password confirmation no point we just got to make sure it checks and then make sure we send it back as the hash password okay so we're gonna test this out and let me do let me do a return real quick we are going to return let's return the success message and then we're going to say user created successfully and then there's a way we could actually display the success messages and error messages onto the client s for better user experience but let's test this out and see if we actually create somebody in the database let's open up our um development server what I want to do is I want to open up mongodb so we are using mongodb as the database um you can sign in and if you guys are joining now for the first time um this is episode 2 in episode one we did create the database so if you want to go back you can look at it and I do have videos as well so make sure you sign in um after you do that make sure you're on your project you can see here at the top left we're going to browse the collections and I just want to make sure that we have no users so we have a user based on the account because that was the Google provider and then we also have the user as well based on that account so it's kind of let me show you it through the prism schema real quick so if you look at our schema. prism if we get an account say an account is created on the Google provider it has all of these properties on it and then we made sure we have a relation field to the user and if we have an account created it automatically creates a user so the user model is technically going to be where all of the users are no matter if they sign up with the Google provider or with the credentials provider so I'm I'm going to do is I'm just going to delete everything just from our database delete the account delete the user and we're going to try to register with a credential provider so let's refresh this page we could use this email that's not my email but we could use it do a password let's do a password that doesn't match and then let's open up the console one two three and then we're getting something here a component is changing an uncontrolled input to be controlled this is likely caused by the value changing from undefined to defined decide between using controlled or uncontrolled input element for the lifetime of the component so I got to look at that error but for now it's not going to affect anything but let me register this real quick with two different passwords that don't even match passwords must be at least six characters long so it catches that up first so let me do that so it's loading and it should be in the network so we have 200 status back let me see if there's a response so as you can see the password is 1 2 3 4 5 6 and the password confirmation is one two it's like random numbers so they don't match um let me make sure it didn't create a user because if it did then our catches don't aren't working so no user was created but I don't see the message let me just make sure let me close all this okay so if the password doesn't match we return an error passwords do not match that should be in technically if we return an error that shouldn't that be in the response so it's there's the payload we got 200 response let's click it again we get another register there we go the passwords do not match okay I don't know why I didn't do the first time Let me refresh the page and try again just to make sure this check is working and then obviously we're going to have to display this to the user which we will okay so let's go to the network tab again which we're on click register register error password to down match so I guess maybe I didn't refresh the page but I thought it would be either in the response or the preview which it is okay so pretty much stops the code there so now let's actually use one where passwords match so 1 two 3 4 five six 1 two 3 4 5 six register it's going to keep saying loading we actually should have probably set the loading to false after but um that's fine we should have got a s user created let me see if the user was created okay so the user was created with the name an email and a password that's hashed so that worked I just don't see the success message maybe it's cuz I had to refresh it it again but we will make sure to display the success the success message to see if it's actually working but we successfully actually registered a user with the credentials provider so that is working let's Now work on actually displaying the messages if it's an error or an success and to do that we have to go back to our register form and we're going to create two components and we are going to create these components components we are going to create them actually right above the button yeah we're going to create it right above the button so this will be a form success this is a component self-closing tag which we haven't done yet and then we're going to do this as the form error and it's going to be like that so we're going to get an eror Throne which is fine we have to create those components and then we're going have to pass um like the pretty much the success or error message in the the components so what we're going to do is we're going to register to the data we're passing in the data that we get from the register schema then we could do do then we could call this um what can we call that we could just call that response I don't like Rees or I mean I guess we have to let me see no we don't but I'm gonna I'll keep it as RS which is the response and then we could do I guess if response. error then we could do we could store the error and state and update it like that let me do that real quick let me see something so we're going to create two states we're going to say cons if we could do error and set error and then it'll be success and um set success and it'll be an empty string to start so if if it's a response. error let's set the error to the response. error and the reason why we're doing error is because inside of of um these returns it's an object with a perimeter of error so like error or do success and we have two errors because we haven't created those components which is fine and then let's also set the loading the false to pretty much stop the loading I'm trying to see if we need anything else okay so response set loading and then let's do another if you can do else if you want but we're going to do if response. success then we could set success to rest assess and set the loading to false so that's that works great um are you guys following along kind of what I'm doing do you guys need me to repeat anything if you do just let me know I don't mind but that is so far our onsubmit and that is right here inside of our handle submit so I actually wrote notes down earlier so with the shaten UI form I'm going to create a video on YouTube that's going to be obviously uh better and more organized and just clean cut to the point but if you look at when we create the form I know where is it so the on submit function contains the logic to be executed on the form submission so that onsubmit function pretty much is the backend logic that we're creating to be executed on the form submission and the handle submit method takes a callback function as the argument which is called only when the form is valid and being submitted so that's pretty much straight from the docs and if we do look at this the handle submit function on the form which the form is defined up here from the use form hook so this handle submit is only going to run if the data is valid so if the data seems valid then this onsubmit function is going to fire off and it's going to run this function right here um so let's see if this is actually working which we're actually not going to be able to see yet so let's set the error and what we can do is let's console log the res. error and then we could console log the res. success and try it out so I'm going to do an error one first oh I gotta comment this out real quick one sec let me comment these two out okay so let's do like Tom Tom one two three four five six seven and then one two 3 four five six seven eight okay so we are going to try to register and then we're going to look at the let me look at the console on the client side because that's where I'm doing it so register passwords do not match perfect so you see now we can actually take this and display it on the screen let's make sure the passwords match five six and let's just remove the name let's register oh oh it doesn't even let us register because the name is required so the use form um validation doesn't even let us register it so that's perfect so let's do Tom and I don't even think this is going to let us registered either yeah so we have to do a valid email but let's do an email that we already done so it was that Brett 1@gmail.com so this email is actually associated with the user in our database so let's register and user already exists perfect okay so I'm just going through all the checks making sure everything's kind of working good um and it looks like everything is working good let's just do a random user and let's register it and user created successfully so the success mess is working as well okay perfect uh so where's the most common place to display the air um you could I guess it depends on your liking but I know a lot of people use like toast notifications so they could do like a toast notification top right bottom left you could do um a notification above the button which is what we're going to do which is in the form that's where their eyes are so kind of doing a notification where their eyes already are is good but toes notifications like top right or bottom right is good as well so that's what I'd recommend and they do have a toast component if you look inside of shaten so as you can see it pops up right there I never moved myself back in the corner let me do that real quick but um that's I'll say those are pretty much the common places for errors or success so let's uncomment this and let's create these real quick so I'm going to create everything inside this Al folder in the components new file we're going to say form success. TSX and then I already have a um component that's very similar to this but I'm going to code it out for us I'm just trying to see what I named it okay I named it form success cool okay so we actually have a package a icon package that is comes with shaten when you actually initialize the C and it should be Lucid react or it's another icon Library depending on the if you pick New York or default so what I'm going to use is I'm going to use a check check icon and this is from Lucid react and this is going to be for the success it's pretty much just an icon we're going to make it green and then obviously if it's an error we'll make it um we'll make it red we're going to have to set props in here here and then let me just export cons form success we just make an arrow function it could have used the snippet but whatever and then um we need to actually pass in that state so what we console logged and then we stored in state into this component here so we're going to go back to the form success I'm going to remove this console log hey what's up man hello how you doing uh shihar is that how you say it welcome we're just going over the register um Logic on the back end so I'm going to remove the console logs and we set those console logs inside of State we either set it in the error um variable or the success variable so we could say message equals success and then we're going to get an error because it can't find the name success so let's import it and then we're going to get in other error um pretty much saying that um it's type is void blah blah blah type message string is not assignable theistic value property message does not exist on this so we have to go inside the form success what we could do is we are going to accept a message and technically it is going to be optional so you have to chain on the optional operator which is a question mark because you might get an error message not a success and we're goingon to have string right here and then what we're going to do is we have to accept it in the props here so we're going to do message and then we're going to tag along the form success props cool okay so we're going to create a parent div for this component get that check check icon and then let's give it a class name of width of four and a height of four as well and then we could actually do the text and there if you wanted but it's not um yeah let's do the text Emerald 500 and when you do it you can see the text color here so you can see it you can see all of the properties when you hover red it I'm using uh tail and a Telly sense it's like an extension so if you type that in I think it just shows you all of the properties when you hover over them and let's style this real quick so let's style this to make it look good and I'm going to just put this side by side real quick so when we style stuff I like looking at it side by side I think it's this one oh let me comment out the form error because technically we're getting it and then we're getting an error on form success still cannot be used as a jsx component did I import it right yeah looks like I imported it right and then we got the message equals success huh let me see oh I don't have a return that's why if no message and then I need a return because it's actually not return turning anything so I'm probably getting an error off that that's why it's kind of good to use Snippets sometimes and yeah now it's working cool perfect okay so what we are going to test is the success message so technically this should be good and we should let's um do another account so Mike one two three four five six two three four five six we're going to register and then we have this check icon here it's very hard to see that doesn't look that good um and we need to display the message too which will help so let's display The Message In A P tag underneath hopefully it stays there okay user created successfully perfect so let's make this a flex um do you guys use Gap or do you use space X like whatever so like space X4 because it gives some space item Center I think because you could tell they're not like centered it's not like straight up there we go we're going to do a BG of emerald 500 and then we need a opacity on it because you see it's too dark so maybe like try 30 maybe 20 let's try 20 use Gap back four yeah I've seen a lot of people use that I used to use um I use Gap x for [Music] um is there a Gap X for it but space is also fine I wonder what the difference is I don't even know what the difference is honestly um the text isn't being Emerald there so let me [Music] um there we go cool um there's not enough padding let's do a padding all the way around of like two maybe looks good rounded maybe large that's pretty good um other than that it looks pretty good user created successfully okay so that looks good I'm just going to copy this over and then we're going to create the a one to too oh let me not copy that with flex box and grid Gap yeah I how how can you even tell which one looks better though I feel like it's like really hard to tell maybe I guess if you do different um viewports you should be able to tell I'm not 100% but let's create another file called um form error. TSX I'm just going to paste this all in here we're accepting a message a message let's rename the component to form error instead let's look for a different icon like maybe an X I don't know oh let's see if x works X blah blah blah um let's change the color so the text is going to be red let's do 500 and the background should be red 500 with the 30% opacity and then everything else should look the same okay let me refresh the page let's do the same email again initi should say my emails are the same or something like that or maybe the password is different because I think I might actually typed in a different password oh we didn't even we didn't even pass in the um so we got to uncomment the form error which would help let's import the form error from the file we just created and then we must pass the message message of where we stored it which is going to be in the error variable like that and then let me make sure everything's good here we accept the message it's optional okay looks good let's try now user already exist looks pretty good um I think there's another variable I could use yeah this one's better let me do this one I don't like the X doesn't look that good oh it's from react icons um why don't we make the eror components outside all so we can use it in different forms do you mean um do you mean just take them out the all folder or like just make it more General I kind of I'm going to use the react icons package too so I'm going to mpm install react icons let's see how this one looks you mean a generic one yeah we could we could um e. prevent default any good messages than user already exist why don't we make the air component outside off I mean a we can make a generic one I'll keep these for now but we can make a generic obviously with the help of you guys we could definitely make a generic one e. prevent default where are you saying put that in the onsubmit function um AOS n yes more General any good message then user already exist um I guess we can make yeah true so we can use it if the datbase server not what what do you still name it um form success and form error or would you just say just totally not form form success I don't know if you do the e. preventive fa for this um can't find the name e I think I looked at the documents earlier for the um use form hook and I don't I think it just prevents it by default that's built in on the use hook form I don't think you have to pass in the event I'm not 100% sure but correct me if I'm wrong and then we could create a form error I guess yeah we could do that let's create a form error inside of the components so form or because we need it for ER handling instead of well I technically I already have a form error so wait why would I H so you're saying keep the form error because you said form error but I already have a form error. TSX or would you just put like an error. TSX form error for what exactly um the form error is just for um the errors that let me I'm going to minimize this screen now so the only errors that I'm sending based on the form technically I can I just do um you said if the database doesn't exist if it goes down cons user exist so the form error just pretty much shows these errors I'm showing here in this server action so if it's not validated invalid input data instead of user already exist you're saying use a different message I know that was one of the comments I don't know if there's any other good message the news already exist maybe uh email already is in use please try another one let's say user enters a form data and the database server is down so we have to show the user something went wrong how how would you check to see if the database went down so like say if we're using um prism orm like what method would you run to make sure so like server error 502 is that what a is that what a database server error is would they automatically get a 502 or do you have to create that custom I think can't you just do um so if we go back to the code up here we go to our register form and then we could can we do another statement so can we do if it's a 502 though for sure you know what I'm going to do I'm gonna use chat GPT see what it gives me we are going to try that I am using nextjs one being able let me see if I could do this um what is AR it's it's like some extension on chat CPT that I was trying to do for like but I think I was only using the free version and they have like a pro version it's like some extensions people create I don't really use it honestly so I don't know if it's like something you actually do so this is what they're saying to handle 502 error when accessing the database you can wrap your database related code and try and catch block and handle the error accordingly in the catch block you can set an error that can be displayed to the user here's an example of how you can modify your register function all in a try and then the catch that makes sense um how did I install that extension you got 503 Google search engine GPT wait so it's not a 502 I just I just searched um arpm and you just install it I think through the Google Chrome Store yeah 503 service unavailable okay that makes sense okay so we're going to do that we're going to do this method right here so I'm going to on um just have this catch there's that okay errors of type unknown so 503 is the best code but we can send the user to 503 ping sorry request not available so you're saying create a custom 503 page I know this one you see fix using co-pilot that's really good so error is type ofn and you accept and then it fixes the type error code string code AS string we could do this because I guess for now and then we could always create a custom page but I guess what chat GPT says was run a tri block for all of this code and then underneath run the catch you could console log the error database error whatever the error is and then if the errors is this code ETI timed out unable to connect database please try again later if it's a 503 service temporary temporarily unavailable please try again later and then else an unexpected error occurred please try again later so those are three checks I guess if the database gives us an error so and then obviously it'll display as the error message that we created here so I think that should handle um yeah res. ER res. eror res. success that should handle all of the um X I feel like for the register form let me just make sure everything's working though successfully I'm going to delete all the users that we created real quick and then after this we're going to go to the login functionality okay let's go to this page oh no I'll add that in a second let me let me test this out so Brett one Brett one two three four five six two three four five six register successful and it's there so it's working okay so everything looks like it's working good I do want to add pretty much soon after we do the login functionality we we send like the user verification token they verify their email and then they could be able to log in which I've watched a video on how to do it so I could show you guys how to do it as well um that's why we have this verification token model right here with parameters that we've already pretty much came up with and made in episode one um okay let's go back to our code and let's we are done with the register the Google one works too but I'm going to create a button when we do the login so let's work on the login functionality so we're on the login page and we have a login form and for this login form I think it's honestly going to be almost the same as the register page when it comes to the UI so the first thing we should do is we should create a schema called the login schema so export cons login schema this is going to equal the Z doob and what we can do is we have to figure out what we want them to log in with I think they should be able to log in with the email and the password I mean that's pretty simple so email z. string so it's going to be a string and is also going to be checking for an email cool and then the password I think we only have to do um we don't have to do a minimum check because if the password was checked in the register we don't have to check the minimum here so it just has to be a string I think like that I think that's all we kind of need let me look at my other files to see yeah that's that's pretty much all we need I think okay and then let's do airor message messages so message we could do yeah please enter a valid email sure and then we could say password is required why are we doing that object L made only specific no passwords and messages not exist in type I guess it doesn't exist in the string which I feel like it would but let me check so yeah let's just do the minimum we'll do it one and then we'll just do please enter a password yeah please enter a valid password okay so that's good for the login schema next what I want to do is go in the login well let's go into the register form and creating that card wrapper is good because we could just I'm going to copy this whole page this this is the register form page we're going to do a new file called the login form. TSX I already have it okay I just didn't create anything and we're just going to paste it let's rename the function to the component to login form move this to login form as well and then we are going to Let's see we are going to actually use the login schema we are going to use the card wrapper we're going to use the use form hook we're going to use the form we don't need the form description I'm not using that we need the card wrapper we need the Z resolver the login schema the input we do need we need Z from Zod we need the button we need the use State we need we don't need the register because we're going to create a different one we could do form success and then form error I don't I guess we could do form success I we could definitely do form a do you guys think we should do form success or just navigate them to like the dashboard this is going to be a login schema instead the schema that we're going to go off of is the login schema and then we don't have a name because we don't have that in the schema that we created we have an email and password this is going to accept the login schema and then what we're going to do down here we have the card wrapper we're going to have a header label this is going to going to be log into your account into your account the title is going to be log in the back butt if you don't want to be on this page is going to be alt SL register and the back butt label is don't um have an account register here you're saying not really navigate to nashbar dashboard yeah that's what I was thinking I'm just going to navigate I'm going to use the form error but not the form success there's no point of showing the success message and then sitting there still on the login page doesn't make sense but um so the first field email which is good form label email we have the input oh this form message to this component right here inside the form field for the shaten form this is actually showing the message of the error based on the form so that error we created in the register schema that shows it right here below the input what we could do here is we can remove this whole form field we'll keep the password one and let's oh we'll keep the password one and let's remove the password confirmation one let's remove the form success we'll keep the form error and then it's either going to be loading or login so I'm just literally changing all of this to match up with the login form so we do have two errors which is this right here so let's remove this for now and then we could actually instead of theed let's create another action real quick let's create a login. TS file and let's just do export how did I do it here let's see yeah X Port cons login it's going to equal in a synchronous value oh asynchronous component Arrow function and then let's just [Music] return user logged in successfully just for now and let's import it here inside the login form so let's do login and it's a server action and oh let's mark it as the use server we also have to import all from Zod so thank you g help co-pilot um other than that I think we are good with the login page so the login page displays the login form the login form pretty much it says expected zero arguments but got one so we have to actually import we are going to be using database function so we need that from Prism we need to actually use bcrypt I think I'm not 100% let me see let's do that and let's import the login schema from that schema's folder and what we could do here is we could do what did we Nam it in here we named it data okay so data z. infer type of login schema so we're pretty much validating the data with this z. infer method from Zod and I actually have it pulled up here so we could go to the docs and let's just look for the infer schema method or it's actually not a method what is it I don't know what it is it's somewhere but look if we look at the parse to given any Zod schema you can call its parse method to check data is valid if it is a valid value is returned with the full type information otherwise an error is thrown the value return by the parse is a deep clone of the variable you passed in so the they're creating a variable called string schema equals z. string if this string zema parse is fish then returns fish if it's a number then it just throws an error so that's what it does example so we're going to use the parse because we could parse the data to make sure it's good so yeah validate the input so we're going to do cons uh yeah validated data equals the login scheme emma. parse and then we're doing the data that we get and then let's um console log the data just to make sure everything's good okay so let's test this out what we have now our server is running let's save this our login form is going to have error so let's actually uh let's remove this okay so now we have no errors let's go to our login form now um I already have an account we click it it should go to it now we have a login don't have an account register here perfect and the reason why it's working is because that card wrapper it's a um reusable component that we made depending on the page we're in so log into your account log in register create an account so if we log in nothing should work but we should get a console log in the back end loading it's just going to stay loading and then yeah we get email right here and then the password as well so we're actually validating the data and logging it to the console successfully so we're good there um next step I want to do I guess if the data is invalid return an error yeah so invalid input data we could probably name this something better but for now I guess we could leave it it's not crazy big deal okay so next let's [Music] actually let me see the difference between pars and safe pars so we have a parse which throws an error and a safe parse if you don't want Z to throw errors when validation fails use the dot safe parse this method returns an object containing either the successfully pars data or a Zod air instance containing detailed information about the validation problems that's the same thing I mean I guess we could do a save parse it's not a big deal okay next thing I want to do is um like we did with the other thing destructure the validated data so we have the email and password and it's just coming from the validated data or it's not property p password does not exist on type safe parse return type okay let's just do parse then let's just make sure we actually getting these destructured so email and password let's go back to the form do we have the other console no we don't refresh the page and yeah we're getting them right here destructure too okay cool so we're actually getting that D structured nice and the next thing we need to do is we need to check if the user exist with a given email so what I watched a video um from cod with Antonio he creates these functions in separate files which I like it keeps everything organized so he actually has inside of I'm going to close all this up we could create a data folder on the root layer of our project and inside that we could create a user. TS file and we could do functions here so we could do import of database from lib SL prism and what he did was create two functions he created one called the export cons get user by email and it is an asynchronous function because we are quering our database what we are receiving is obviously the email hence the name get user by email and inside the code we are just running a simple cons user equals await database. user do it's going to be F first or find unique and then we email and then all we're going to do is return the user and then one thing I was running into my other project when I did this is is I just want to make sure this is how it is done let me just really quickly check so I'm going to create a user real quick and I'm gonna explain as I do it okay so I'm going to create an email like Tom but I'm going to use a capital T and I want to see if this T is undercase or lowercase when they actually check it so Tom because that was caused me a lot of issues and I had to do a two lowercase so let me check so we're going to check the user so that it is an uppercase Tom gmail.com saved in the database and what I did in my other code was I did cons new email equals email. to lowercase so the reason why because um when I was typing in the emails we have to make sure to make sure everything is lowercase we might as well send the email in the database lowercase and then make sure this is lowercase so we have no issues because I know being uppercase was causing an issue so let's do that yeah I'm going to change all the strings to the database to lowercase I'm pretty sure that's what I have to do so in the register every email email is unique yeah true so could beut uppercase I feel like by default all emails just go lowercase but I could be wrong yeah no you're right it could be so what I'm going to do is um when we destructure this we're going to see if the user exists and if the user exists then we throw an error then if not I want to say const um I need to name this something uh lower case email and then email equals email to lowercase and then just do do a hash like this and then put lowercase email and I'm going to try it again with the capital let me see okay save go back let's do Mike 11@gmail.com with the capital and let's see if it actually lowercases it in the database I just want to see register user created successful and yeah it did lower cases so perfect I do want all the emails to be lowercase it'll just make it a lot easier when we're actually trying to request stuff so I'm going to do that let me minimize this um I was running into the issue um Loco when I had my voice fusion though so when when I was trying to retrieve a user I kept getting null and then let me move this code over and then when I did this constant email equals email to lowercase to get the user by email I was actually able to get the email successfully only when I was able to pretty much put the email in the lowercase with that um JavaScript method that was the only way I was able to actually get it working so I think I'm just going to send all of the emails lowercase in and they could type at uppercase if they want input but when we log in and see and then we try to find the actual user I'm just going to make sure it's lowercase as well so we're going to say cons lower case email equals email to lowercase and then we're email equals lower case email like that and then just return a user so that is getting the user by email now um oh you're agreeing with me oh my fault I thought you weren't I mean even if you weren't it's not a big deal I like bouncing ideas off people so that is um and then we're going to get the user by ID as well this will be asynchronous this is going to take in the ID which will be a string it be an arrow function and what we are going to do is we could do cons user [Music] equals oh wait database. user. find unique where the ID is that we're not going to use this now because obviously this is more for I think backend we're going to use it later but um we're going to get the user by email inside the login so we want to check to see if there's a user so check if a user exists and this is where we're gonna use that function instead of writing this which we could have actually wrote this but it's not a big deal we could have our own functions in a separate folder which I feel like is um it's cleaner it's a lot cleaner for sure so what we're going to do is cons user exist equals a wait and then we named it get user by email and then pass in the email and then we're going to say if the user does not exist does not exist return an error oh true so if there's no user exist then we return an error so we have to do actually I think we have to make it null so let me do a try catch real quick try catch I'm G to remove all this up inside the tri block and in the catch let me just return null let me do the same thing with this as well and then I got to actually return the user here and then return null here so if we don't get anything it's going to be um there's going to be no user exist so we're gonna say user does not exist or yeah user does not exist that's good okay next well this is actually because I'm looking at my other code here so if you user exist if no user exists returned in error um okay so here's a problem two as well where we are going to have to actually do so if there is no user or there is no user exist. email or there's no user exist. password I remember doing this because the way it was explained is because a user might not exist no a user might exist let me let me try to put this in the words because I know you could log in with your Google provider and this error you could get hit with if the user does not exist because this login should only be for people using the credentials provider so if there's no user exist then return this this okay so like for example if I'm signing in with my Google provider and that email is going to exist it's not going to hit that return because of the error because it does exist but actually I shouldn't be logging in with that so we have to have an email and password because the Google provider should only log in with the Google provider so that's why we have these three checks I'm going to revisit this but I know that's the right um thing I should do and we're just going to revisit it later but I know the other thing we need to do is inside of our .ts I'm just going to put this Pages sign it will be Au login like that redo that as well we're doing we're spreading all of the properties and attributes of the Au config inside of our next Au we have a session strategy this and then our Al config we need to actually do the credentials provider because on the login page we actually have to run the signin method let me go back up to my code I'm going to go inside of my code real quick my other code and see what I did okay yeah yeah that's what we have to do we have to do the asynchronous authorized callback function let me just go to the docs and check everything out so if we go to Providers credentials um the credential providers allows you to handle signing in with arbitrary credentials such as username password blah blah blah so we have to do the credentials provider the name to display on the signin form sign in with the credentials which I don't think we need that because that's only if it was the um if you're using their pretty much signin page which we created a custom one with obviously shat CN credentials is used to generate a form on the signin page you can specify which field should be submitted by adding keys to the credentials object example domain BL blah blah you can pass in the credentials username password which we we don't have to add that either because I think these three right here you only would use if you're using their sign in form which we're not this is what we need to use right here add logic here to look up the user from the credentials supplied okay so we have an authorized function that takes in the credentials provider takes in the credentials right here okay so this is pretty much doing checks on the login so what we could do is we can actually let me go back to the login right here our login action and what I have to do is so if the user doesn't exist we're going to throw an err so if the user exists we're good we're going to see if the user exists and then let's do a try catch right here so it's going to run all these checks and if it gets here we have to await the sign in and this is coming from at SL I think let me make sure yeah it's coming from here from now um so we have the sign in and then the signin takes in the provider the built-in provider or a string or an object or undefined so the credentials it takes in the credentials provider and then options here form data undefined redirect true or undefine uh I guess it's the form data right yeah that's it so user exist. email and then user exist. password and then I think there yeah there's a redirect and we could redirect this to say dashboard because after they log in we're going to redirect to the dashboard or is that even the type string is not signable to type Boolean UND or undefined so it's a bullan redirect true run toine redirect two dashboard there we go catch actually have a catch right here with an error in it um and this is for typescript only so let me do this it's off eror I think that is from next- it's just part of the typescript because I was getting a type error here so Au error and their docs are kind of weird so like if we search for um let's see Au there where am I right here your next Au um base error class for all JS errors it's optimized to be printed several logs server logs in a nicely formatted way via the logger do error option so type is error type the error type used to identify the error in the logs Al error okay so that's for the console of that and then we do a try Here sign in with the credentials and then just to make sure this is working I just want to make sure everything's working good let's do an async authorized credentials why are we getting an error for this credential authorizer here type credentials is promis void is not signable to type credentials blah blah blah um I think it's got to return a user or null let me do okay yeah that's what it was okay return n console log the credentials okay let me try this and see if I get a console log um let me do it's from Au config file okay let's see if we get something let's save it okay already have an account log in cool one two three four five six log in it's just going to keep loading I just want to see if we actually need a console Au config file email Brett password that call back URL dashboard nice okay the credential sign in read more at errors blah blah blah I mean obviously I'm not done with it but we are actually that's the credentials we are passing it in from this login so this sign in function which I could look up real quick sign in set on a successful oh these are events this isn't sound like successful sign and the message will be an object and contain the user account profile follow is use new user okay that's not it but I we have to go through the docs a little more to actually see what's going on let me see okay so we're going to do that and then we're going to log in and then we need to do the checks here inside of the Au config file so let's do the checks again um validated data or yeah validated credentials equals let's import the login schema from schemas we're going to do a safe parse of the credentials so we're making sure everything's good if it's good it's going to return those same values inside the validated credentials variable now and then or no it's just going to give us uh let me console log this real quick okay let me save it because it get help saying there's a DOT success at the end of it oh it does it gives you a success true and data of that let me see if I do parse if that's even different parse loading okay I think it should do it so safe pars gives you success or not and then parse doesn't so safe parse and parse let me look at this again if you don't want a to throw errors there that's what is success is true data and success is false okay and then the parse will throw an error or just return makes sense nice okay so you do save parse if you want it to be success or not so if there's no validated credentials. success you're going to return null and then we could just say destructure it from the data right let me see what the console gave us yeah data email password yeah get it stores it in a data object so like data Billy and then true on error okay that makes sense and then what we're going to do here is yeah we're going to use that function we created a wait get user by email and then pass them the email so that means if there's a user so if there's no user or there's no user password that equals the password then we return no no let's see how this check's going to do so if there's a user it's going to show up here so we're going to say if there is no user or and there's no user. password then let's return no because I think you only could return null and stuff I'm I'm going to try with erors too and there's no password there we go okay and then we're going to say cons then we got to check if the passwords match then passwords so that means there's no user return all cons passwords match equals a wait bcrypt import compare from bcjs is that how the import is or no b b from bpjs like that okay there's the method. compare and then we're doing the password and then the user password right so we have the password that we get from where they typed and then the user passord password and then compare method a s only compares the given data against the given hash okay the string and then the hash okay makes sense yeah so let's do a check if passwords match then we return a user else you're going to pretty much just stop there and then then it's going to return null then satisfy everything here okay I think we pretty much got everything for the login we don't need database here actually anymore and we might not need in the register anymore let's see no we need it for to create a user okay let's try it out we're going to try everything from the beginning and test it out okay so we we're RNA BR one oh let's let's create an account so Brett at gmail Brett one two three four five six five six user creat successfully let's check should be BR Gmail with the hash password perfect um let's already have an account Gmail um before I do this let me make sure I have everything showing if oh wait no never mind if it's successful it's good but let me make sure the error one's working so we go to components Au login form oh we got to do the login data right here so we pass in the login data dot then if we get get a response Let's do an error Arrow function so if there's a if response. error then we're going to set the error to res. eror and set the loading to false else just set loading to false because we're not showing a success message so we don't need this we just have the error and then passing the message in as the error and then the form error so it's okay and what errors do we throw invalid input data user does not exist let's do a user does not exist I want to see if that works um user does not exist perfect okay so the eror is working so now let's actually try to log in and if it logs Us in successfully it should actually just redirect us to the dashboard let's make sure though sign in calls in the sign in function goes through credentials the credentials then looks at the alt config redirect to dashboard okay catch and let's just um for now let's create a new folder inside the app called site and inside of the site let let's create another folder called dashboard and then a page. TSX create a react functional component I'm going to call this dashboard [Music] page and then I know just to make sure we could console log it be I I want to make sure it's all working correct we are we have to use this alt right here inside of our alt. TS file so let me just import at the top and then we're going to be able to create a function from this too at SLP authos decar never read import Au oh it must be like that okay cool then what we could do is we could console.log to O Okay we could try that let's try that let's try it if we get mistakes we'll just fix it so we have a Brett Gmail one two three four five six log in invalid credentials was that the right let me make sure that was the right password I don't even know the password I typed two three four five six okay already have an account put four five invalid credentials and that was 100% the um let me make sure that's the right email yep it's the right email so we're getting invalid credentials even though we're logging with the right information so let's see what's going on a login we're getting this return right here so whatever this is is not working [Music] um let's check let's try we got to console log some stuff if you guys are in the chat um any recommendations would be nice so we're getting this console where it says invalid credentials and if we go to the O config if it's not success return all let's console log the user and then if no user or there's no user. password return n let's console log the password match as well this should all be in the server so let's see if we actually get it password's match is false okay so that's where our problem is right now so it's actually firing this function and then it's just return null and then when it returns null it just runs this catch trying to um so it's going to here it's awaiting bcrypt bcrypt from bcrypt js. compare it's password and user. password password's match is false so the user. password is hashed that's for sure let's try console log in that password that password is Hash too so we're trying to compare a hashed password with a hashed password so we're getting the credentials h oh I think it's because we're passing in the wrong password Here user exists. password gets it from there it should be the password that's what it is and it doesn't have to be it could just be we could do it like that almost 100% positive this is why it's not working let's try it again okay now we're getting a different error it did take us to the dashboard page and on the dashboard page I think I console logged I want no it's con how do you get the user from the Au I I know it's a certain way let me check real quick oh yeah con session equals a wait o and this has to be a synchronous and then let's do console.log the session and yeah we're logged in right there so we are logged in um it's kind of weird it threw an error let me see what the error was I gotta log us out okay actually I don't even think it's might be in cookies have all these cookies okay let's see if we're getting any errors nope I just want to see if we're getting any console log errors as well let's do Tom 11 gmail.com Tom okay now we're getting an error right when we start doing confirm password let's see let me redo that again so the confirmed password is throwing us an error the component is changing an uncontrolled input to be controlled this is is likely caused by the value change oh I think I know why because we don't have the default value um for that that is in the register form I remember our default values we got to put password confirmation as an empty string and then we have to go to the register okay I think everything should be good now let me refresh Tom 11 Tom one two three four five six one two three four five six register user successful no consoles I already have an account yep Tom 11 it's showing a quick error what is that error passwords match true session blah blah blah yep everything's good I'm G to um con like just let me just comment out these consoles because I do want to have them for future use because they're really good consoles actually passwords match that's a good console that's a good console this not really we know we're getting there um yeah I think that's good so we're logged in um and then let me see so it doesn't store anything in the Local Host nope but in the cookies we have this Au cookie value delete delete let's refresh the dashboard page sessional okay so it just stores cookies from the JWT and if there's know those cookies then it just logs you out um next thing I want to do which is probably to be the last thing for tonight this and episode two is I want to add the Google button the Google provider button so we can log in with Google as well so I have this up here of how I actually styled it so we are inside of the Au we are going to create another file called Google login. TSX this we will create this as a used client because it is a button we're going to import the sign in function and that is from next o SL react which actually no it's not we are going to use the sign in from at slash o right and then we're going to importa Lo no that's not even um they have a react icon Library the react icons Library they have a fc Google it's a little nice little Google icon we're going to use we're also going to import the button from Shaden slash components slui button and then we also are going to that's pretty much it we actually don't even probably need to use client let's see if we can do without export cons Google login let's do a return let's do a button we could do that for now this on click we're going to have an arrow function it's going to be signed in with the Google provider so it's either Google or credentials that you put in the signin function so if we do this it gives you a bunch Google HubSpot um Instagram identity server 4 node mailer like there's so many but obviously we're just going to do Google because this is for the Google provider we can make the button size large uh variant I guess outline class name for sure maybe like with full let's see how it looks and then let's but first let's import it so we have the Google login and that should be right below the button on the login form and on probably the register form it should be probably right below that [Music] form so I'm in the login form let's see if it actually took place that where it should be so Au slash login yeah it's just not styled good but let's we can style it real quick and then we could test it out as well and this um Logic for signing in with Google is actually not hard all it is was a sign in and then you pass in the string Google so it's pretty easy for that so we go to the Google login we made this a reusable component let's do space y let's try three oh no that's that's doing it for the wrong thing this button let's try margin top three okay space X3 maybe it's pretty good that separates the icon and the login with Google and that looks pretty good honestly let's click it one error invariant headers expect to have request a sync storage none available is it supposed to be an asynchronous um call huh let's okay maybe just have to use the client because I am using a use um an on click let's save it refresh nope invariant headers expect to have a request a sync storage none available huh does anybody in the chat know why this error is getting caused right here invariant headers expect to have a async non available what do that mean control C sign in with Google our all config Google client blah blah blah we have the EnV let's chat she it see seems like you're encountering a JavaScript error related related to promises and expected function called headers the error message also mentions something about request async storage not being available here are a few things you could check consider it looks like there might be an issue with accessing or using async storage in your code ensure that you have set up and configured asnc storage correctly if you're using Library framework the LI asnc storage make sure it's properly in Gren oh Google provider return all the profile information need the only true required fi's ID to be able toy the account when it added to a database this is an example of how to enable automatic linking automatic account linking it's crazy because the code I have above it works it's a little different let me try the syntax of that code up there so what they do it's a weird error H so we have a onclick and then this onclick above I just created a on click um sign in with Google function and then what we're going to pass here is Google we could copy this maybe because I have to do a weit let me see I wonder if that's why it might be honestly okay okay pretty sure it's got to be used client with an on click something about invariant headers the provider is Google and then the response is a promise which was rejected invariant headers expects to have a reest Quest acing storage oh the other thing that I have up here is it from a different package which could be it next Das slash react there should be no reason for a function it should just be an onclick with the sign in with Google use client okay and it's from a different package this might work and it does work nice so make sure if you're using the Google provider it's coming from from next- SL react so it can't come from the .ts so this sign in looks like it's only for the credentials because I'm using it here sign in from at o and it works and I know it's console log in the credentials yeah okay so now all we have to do is just add that to the register now too so underneath the form inside the card wrapper we're just going to do a Google what did I name it Google login yeah Google login from here okay so let's make this full page already have an account cool perfect so now we have the login and register page completely done thank almost done it's it's the only things I want to add is I do want to add a forgot password so if they forgot the password we are going to want to send them I think we created the model already let me see we want to send a password to reset token with the ID an email a token and expires so we want that and we also want to send a verification token so they could verify their email if they sign in with the um credentials provider and then other than that I think that's pretty much it with the authentication um change the login to sign in oh yeah sign in with Google you're talking about uh Google login sign in with Google or login don't have an account register Here sign in with Google already have an account okay cool um authentication that definitely it's it definitely takes a lot and especially since we're using next auth not using clerk um it's going to take us a little bit longer but like I said I just I just think it's worth I don't know I think it's worth putting the time in to do it and have a really polished authentication system that allows us to track users because we we we're going to use stripe to obviously hook up user accounts to see if they're Pro members or not um we're going to have to create the open AI assistant or use something from chat GPT open AI apis to create the chatbot which I haven't done yet um wait no I only meant for the register page not login I don't I don't understand what you mean I only meant for the register page not the login when when you sign in with Google regardless if you're on register or um login it it would be sign in won't it oh yeah async way it's not supported yeah let me click that off okay but um other than that for sure next stream we are going to do the verification token and the password reset token that will be the first business we do and then after that we will actually create a navigation bar and make sure all of our routes are set up correctly and just make sure all of our code is clean as well and then we'll keep continuing from there so this this ass is going to take us a while for sure but it's definitely a good process to follow a lot of good skills we've been already implementing and I mean this is definitely one of the more modern Technologies and Frameworks out there to use right now but other than that thank you guys for sting around sticking around on a Friday night to watch me live streaming code really appreciate it but other than that I'm either going to live stream tomorrow night or Sunday for sure so one of the other ones I'll make sure to obviously schedule a live so you guys could be updated so make sure you subscribe to my YouTube join the Discord just stay updated with all the notifications and if you do have any messages hit me up on Discord that'll probably be the best but other than that you guys have a good night
Info
Channel: Brett Westwood - Software Engineer
Views: 503
Rating: undefined out of 5
Keywords: nextjs, next.js, next.js 14, auth.js, mongodb, next.js tutorial, next.js server components, auth.js version 5, authentication, frontend developer
Id: ur8a68d-Vd0
Channel Id: undefined
Length: 157min 5sec (9425 seconds)
Published: Sat Feb 24 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.