Next Auth V5 - Advanced Guide (2024)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey there my name is Antonio and welcome to the out Master Class where we are going to be learning OJs the new name for next out version 5 in this course you'll learn how to set up out using both credential and social providers like Google and GitHub but we are not skipping the musthaves either you learn how to set up forgot password and email verification and yes we're doing two Factor Authentication and showing you how to manage different user roles like admin and user in this course we're not just learning Concepts we're actually building a whole toolkit we're going to create a set of reusable components Hooks and utilities that you can use everywhere in server components client components models Pages API routes and server actions think of it as building your own toolbox for authentication we'll start start with the userfriendly login and logout buttons and then move on to robust registration forms after that we're going to tackle how to handle errors and user verification but we're going much further than that and for the curious minds we'll take a peek at how to use the nextjs middleware and also how to tweak next out sessions callbacks and events it's like giving your out system a personal touch in this course you'll see real examples using server and client components and how to handle admin only stuff we're talking about showing different things to admins and keeping some API routes and server actions just for them finally on the settings page we'll go through how to change emails update passwords and even switch user roles plus turning two Factor authentication on or off so without further ado let's get started so let's get started and let's set up our project here on the right side I've prepared the nextjs documentation and installation instructions and here on the left side I prepared my visual studio code which is going to be my editor of choice for this tutorial so the first step is to confirm that you have the necessary system requirements to run nextjs so make sure that you have no node 1817 or later so let's go ahead quickly inside of our terminal so if you use Visual Studio code like I do you can go into the lower left corner and you can select the terminal option from here and then you can simply write node DV and you're going to get the version of your node if you have lower than 18.7 you have to upgrade your node and you can do that simply by clicking on this link right here or use the link into the description to go to no Js homepage and install long-term support now let's go ahead and let's set up our project using the automatic installation uh Command right here so I'm going to copy this command and we're going to paste it inside of our terminal again but before we press enter we have to give our project a name so let's do the following write the command as follows so npx create next app at latest and then go ahead and give your project a name so I'm going to call this out tutorial and now let's go ahead and answer some questions so we are going to be using typescript in this project so make sure you select yes you can also select yes for esent make sure you select yes for Tailwind CSS because we're going to be using that to style our components select no for the source directory and very important select yes for the app router so we're going to be using server components so make sure you select yes for that and lastly it's asking us whether we want to customize the the default import alas I recommend that you select no because I'm going to select no I'm going to leave it as it is and now just wait for all of those to install after your project has been installed you can go ahead and open it in this location right here so I'm going to go ahead and do that I'm going to click on open right here and there we go I have a folder called out tutorial I'm going to click open and if you get this big model you can feel free to press yes I trust the authors and inside of here you're going to have a couple of config files like Tailwind config TS config next config but also the app folder and inside of the app folder you're going to have a page. CSX layout. CSX and global. CSS file before we run the app I want to add one more thing inside of this project and that is shaty nuui Chet CN UI is going to be our well not exactly a component library but as it's written here a collection of reusable components that we can copy and paste inside of our apps so go ahead and visit shaten UI you can use the link in the description or go to ui. shen.com and now what we're going to do is we're going to go ahead and follow the installation instructions so once you go to the installation here make sure you select nextjs for the framework option and now let's go ahead and see what we have to run so you can see that we've already run this command we already created our project so no need to do this again the second thing we have to do is open our project inside of Visual Studio code and then run this Command right here so I'm going to copy this for npm and let's go back inside of our terminal make sure you're inside of your project and run the following command npx shat cnii at latest in it like this and now we're going to have to answer a couple of questions as well so again it's asking us whether we using typescript or not since our project is using typescript it makes sense that our components will also use typescript so select yes for the style go ahead and select New York style and for the color go ahead and select slate color it's asking us where is our global. CSS file if it's G if it's telling you appg global. CSS that is correct so you can just press enter uh it's asking us whether we want to use CSS variables for colors you can select yes here it's asking us if we're using a custom Tailwind prefix you can just leave it blank so just press enter it's asking us where is our Tailwind located and here's a little trick here so this is actually an incorrect uh placeholder here because if you take a look in our project we have Tailwind doc config dots but not JS so what you have to do is press the Tab Key and then modify this to go tots and simply press enter and you can leave the import alas to be exactly as it is at/ components so just press enter and same thing for Libs and it's asking us whether we're using react server components we know that the answer is yes because we selected the app router option in the beginning and finally confirm all of those options and now wait a second for all of those things to install great after shatan has been initialized in inside of our project you're going to see a couple of Chang es so primarily you're going to see a new lib folder with the utils inside with a very simple CN function we're going to be using this throughout the project to dynamically add classes next we have a components folder which for now is completely empty but later here is where our buttons are going to be our models our dialogues our drop downs everything else and inside of the app folder inside of globals you're also going to notice a change but if you didn't open the file from before you're probably not going to know what changed exactly but it doesn't matter all you have to know is that now we have shatan inside of our project and we can now follow the components from that package great so now let's go ahead and let's actually run our project so let's go back inside of the terminal here and let's do mpm runev this will start the project on Local Host 3000 so let's go ahead and visit our project go to Local Host 3,000 right here and you should be seeing a similar landing page something like this depending on whether you're zoomed in or zoomed out great so what I want to do now is clear this entire screen so because I know how routing Works inside of nextjs I know that I can find this file inside of the app folder inside of page. CSX don't worry I'm going to go ahead and explain in the next module how I know that this is the exact page that I have to modify so we are going to have a small little crash course on routing inside of nextjs of course if you're already familiar with that you can just skip or speed up that part so go ahead inside of the app folder page. CSX right here and go ahead and select everything inside of this return function and simply remove it so starting with the main element right here all the way to the bottom select everything and simply press delete great and then you can go ahead and write a little paragraph here and just write hello out like this and you can remove this import for the image like that let's go ahead and refresh this page and there we go we now have Hello out right here now let's go ahead and test our Tailwind a little bit so I'm going to go ahead and collapse this and give this paragraph a class name of font semi bold and that will make the font bold as you can see right here and you can see how when I hover on this I have have a little tool tip which explains me which class name sorry which attribute has been given with this class name if you're not having this you can go ahead and go inside of the extensions and write Tailwind CSS intell in sense select the first one and install and that's going to help you with writing Tailwind you can also see that when I write some classes I also have autocomplete so if I'm not sure which one exists I can use the autocomplete option like this and one thing is that when I give my paragraph a color for example text green 500 you can see how I have a little box to indicate which color it is great so make sure that your Tailwind is working like that and the next thing I want to try out is how to add a component from shaten UI inside of our project so shaten UI is not like your usual component library because well as you've just uh read from the introduction shaten is not a component Library it is a collection of reusable components that we can copy and paste inside of our apps and it's based on The radic Primitives so let's go ahead and find a component that we are going to need first of all I already know that we're going to need the button component so go ahead and find the button component right here and in here we have the option to manually add it to our project or we can use the command line interface so let's go ahead and do that I'm going to copy this Command right here I'm going to go ahead inside of my terminal here and if you want to you can shut down the app or you can just open a new terminal for myself I'm just going to shut it down and go ahead and write npx shat cn- UI at latest add button and press enter and now that is going to initialize the button inside of our project so if you've shut down your app make sure you run mpm run Dev again so you're running on Local Host and now let's go ahead and look inside of our components folder and in here you will see the UI folder with button. PSX and this is the cool thing about shat CN UI instead of storing the component inside of Nod modules like most component libraries do this one is inside of our components folder and we have full access to the typescript we have full access to the props we have full access to display name we have full access to component name to button variants we can change every single class name in here we can add new variants if destructive outline secondary ghost and Link are not enough we can go ahead and add a third one to whatever we want and modify it and style it how we want same thing is true for sizes if we need an extra large size we can go ahead and simply write an additional class name for that so that's why I love shat nuui it is a true Library well I don't know uh if they prefer to be called a library but it is the best solution to write your own component library inside of your project great so just make sure that you have this little button here and now go back inside the app folder page. TSX right here and let's go ahead and import that so whenever I import something I'm going to be using the import alas so I'm going to start with the add sign and this is the equivalent of me being in the root of my application so the next folder I can go into is components slui and then I can find my button and now I know that I have to import the button export like this now let's replace this paragraph with that new button here and let's right click me let's go ahead and revisit our Local Host so just refresh right here and you should be seeing a button which says click me yours might be a little bit smaller if you're not zoomed in like I am and now you can go ahead and play around with the properties that this button has for example you can change the size to be large you can go ahead and change the variant like this for example let's give it an outline variant and there we go and let me just show you how easy it is to modify this so if you go back inside of your components UI button right here and if you go go inside of the variants go into the single variant object right here find the last one which for me is link and you can simply go ahead and add your own variant for example I'm going to call this custom and I'm going to say BG Sky 500 and text white like this so just a very simple new variant here make sure you have a little comma here after the link variant and then what you can do is go back inside of your app folder page and take a look at the variants now you can see how it autoc completes our custom variant here and when I select it there we go my custom variant is here so that's why I really like this package and I think it's going to be of great use of us of great use for us inside of this out project so just go ahead and remove this custom variant we're not going to need it and now you can see how we immediately have an error here so you can remove that from here as well great so I hope that this kind of introduced you to nextjs and our component component Library if you want to you can explore all the other components which chatan UI has because we are going to be using quite a few of them here but don't worry we're going to go through all of that together in the next module I'm going to be explaining how routing Works inside of nextjs so if you are familiar with that you can speed up or skip that part great great job so now I want to go over and explain how routing Works inside of nextjs more specifically the app router if you already know this you can speed up this chapter or skip it completely so how did I know that in order to modify this screen and add a button I need to go inside of page. vsx that is because I know that nextjs uses folder based routing and has the following file convention names for specific layouts Pages errors and stuff like that so I knew that if I want to find the root page of my application which is is just Local Host 3000 which is technically localhost 3000 slash right I know that that file that route segment is represented in the first page file that I can find in the app folder so that's how I know that this is the file I have to modify to modify this screen and if you're wondering where did I find that out well it's in the nextjs documentation and if you plan on exploring this documentation yourself just make sure that here in the sidebar you select the app router because if you select the pages router you're going to be viewing at the old documentation so in here you can see a list of some other file conventions like the layout file which we also have here but this is the one that I was talking about page is a file which makes unique UI of a route and makes the routes publicly accessible so let's go ahead and scroll a bit up because in here we can see that even better so you can see that we have this app folder which by itself represents the root page so inside of the app folder this page represents the root page that's how I know where to find that and if I go ahead and create a new folder and name it absolutely anything inside of the app folder and then put another file inside of it called page. CSX then that's going to be rendered as dashboard and same is true for as deep as I want to go so let's go ahead and take this concept and actually create that so I'm going to go ahead and I'm I'm going to create a new folder inside of my app folder here called dashboard and just by now if you try and go to SL dashboard on your Local Host you're going to get a 404 so why is that well remember we need to do some file conventions here in order to turn this folder into a route we need to give it page. DSX like this page. vsx and here's an important thing about page. vsx so the only thing that matters is that the file name is page and it doesn't matter if it is jsx or TSX right so it's just it matters that it is Page and the other thing that matters is that you do a default export for example I'm going to call this a dashboard page like this so just make sure that you don't accidentally do this export con without the default so if you do this it's not going to work but if you keep the uh default export that's going to work let's go ahead and return dashboard page like this so if I go ahead to Local Host 3000 dashboard now there we go I am on the dashboard page great and now let's just confirm that I can create some even more nested routes so inside of this dashboard folder I will create a new one called settings and inside of it a new page. CSX and let's go ahead and do the same thing settings page and let's return a div settings page like this so now I'm going to go to Local Host 3000 SL dasboard SL settings and there we go I am on the settings page great so what did we learn well we learned that in order to turn a folder which is the default routing mechanism of nextjs into an actual route segment we need to use a file convention called page and inside of that page it doesn't matter what our component is named it can be named anything like this all that matters is that we do a default export and if I refresh there we go everything is still working so remember there is a file convention called page which needs to be inside of a folder which you want to turn into a route segment but there are some other things you might be interested in for example what is the layout file let's go ahead and see what the official definition says so in here we have a layout file convention which is a shared UI for a segment and its children and you can see more about that right here you can see how it works on this very example that we have here so we have the dashboard folder right and if we create a layout file then that code inside is going to be shared both in the dashboard route segment but also in the settings route segment so layouts are very useful if for example if I go on Local Host 3000 let's imagine that this is our homepage right and then on the slash dashboard I want to go ahead and add a little knv bar so the perfect place to do that is well the layout file because then it's going to be shared across the settings page as well because right now you can see that if I go to SL dashboard SL settings there isn't many much difference between them right you don't even notice that this is a child of dashboard sometimes this is exactly what you want but most of the time you're going to want to give your users some kind of indication that you are in the dashboard route segment and layouts are perfect for that so inside of the dashboard folder here I'm going to go ahead and create a new file layout. CSX and let's go ahead and learn some things about layout so you will immediately get an error like this because we missing a default export here so let's go ahead and call this a dashboard layout and let's return a div and just write layout inside and what happened now as you can see we are not longer rendering the contents of our page. vsx and I am on localhost 3000 dashboard if I go to/ dashboard SL settings same thing happens the route is obviously working but nothing is rendering here that is because whenever you are working with a layout file you have to remember that this is a file convention right so this is a reserved file next JS is going to render this in a very specific way so here's what you have to do every time you use a layout file you have to extract the children so I'm going to go ahead and just quickly extract the children here and just for now I'm going to give them a type of any right it doesn't matter usually they are a type of well I am going to write it now they're a type of react. react node like this and then what we do is we just render the children like this and what happens now if you take a look there we go we can now see our slash dashboard SL settings normally and if if I go back we can see our dashboard page so what did we achieve by creating this layout file why is this even needed well let me show you let's go ahead and modify this a bit so I'm going to go ahead and give this a class name of uh let's give this a flex Flex call and GAP y4 and then in here I'm going to create a little nvar component like this and I'm going to write this is a shared number M bar for dashboard segment maybe a bit long and let's go ahead and give this a background color of black and text of white like this and let's take a look at it now so we can now see that we have this mock Navar at the top which is clearly in the dashboard page but what happens if I go to SL settings it is also here so every single route that we create inside of the dashboard folder is now going to have this little nov bar so let's try that out so inside of the dashboard folder I'm going to create a new one called uh users for example and inside a new page. vsx let's go ahead and render uh users page return a div users page like that so where is this going to be located at localhost 3000 SL dashboard SL users and the users and the settings and the dashboard which is inside of this page. CSX are all going to share this layout file right here so let's go ahead and take a look at that so if I go to/ dashboard SL users there we go the same thing this is a shared knvb bar for the dashboard segment perfect so I hope that kind of cleared up what a layout is useful for it is especially useful when you want to do something like uh for example this is something we're going to have we're going to have a folder called Al right and inside of here we're going to have uh something like a folder called login and then we're going to have a new file page. vsx and then we're going to have a simple login page with a default export and this is going to say login page right and now what's cool about these layout files is that if I go to local close 3000 slout SL login you can see how this one doesn't have that layout right because that layout that I want is spefic specifically for once the user logs in right when they have the entire sidebar and the nov bar so that's why those layout files are very useful and I hope that kind of cleared it up and here's the thing if you try and look inside of your app folder you will notice that you also have a root layout here alongside our page. CSX here so this is a very important file that gives us crucial structure to our project like HTML and body so you must not remove these files this this one is very important but other layout files which you manually create like this one in the dashboard you can always remove them so if I just go ahead and remove this the page is not going to break but now all of those uh all of these files here will lose their shared Novar right so that's what layout files do and let's just quickly go ahead uh and just take a look at all the other file conventions that we have here so we just explain what the layout is we explained what the page is besides that you have the loading uh loading will be triggered as a suspense around your page if you directly await something inside of page. vsx so if I went and did something uh like inside of the dashboard page. vsx here this is a server component by default so if I go ahead and give this an asynchronous thing and do something like const await uh sorry const uh users await to get users from wherever whoops so just a mock function this doesn't exist of course then if I had another file inside of dashboard called loading then that file will be shown to the user until this is loaded right so that's what that loading file is used for but I do that in my other tutorials if you're more interested in that in this one I'm just going to focus on the out but I still want to give you a little bit of uh well introduction to nextjs and we have a custom not found so that is if you're going to be uh with nextjs does have a default not found but you can limit the not found to a specific route segment as you can clearly see here so you can limit your own not found and customize the not found page using this file convention error is for catching errors and you can go ahead and explore on your own what the other file conventions do great and I just want to go ahead uh and do a just a few more you know tips and tricks that might you might find helpful here so we just learned how we can share a layout using a folder like a dashboard but here's the problem right what if for example you want you let's go ahead and remove the dashboard folder we can do that let's just focus on the out folder so make sure you have an out folder login and page. vsx inside so here's the thing so I want to go ahead and create inside of this out folder a layout. vsx like this and I'm I'm going to go ahead and do a default export of Al layout I'm going to go ahead and get the children we already know what their type is but this is just for demonstration and I'm going to render the children inside like this and then I'm going to go ahead and add a little Navar here and I'm going to write this is Al Novar let's go ahead and give this a BG red and text white and let's give it a BG red of 500 more specifically like this great so now if I go ahead and I don't know copy this login and rename this to register right go inside of the register page rename this to register page and let's render register page we already know what's going to happen both login and register pages are now going to share this out Novar so if I go to slout register we know that these two are sharing the nvar but here's a little problem right you might have already noticed if you're kind of experienced in in routing right the it seems like the only way we can create a shared layout is by creating a folder like out which simply has to be a part of our URL right what if I just want to go to slash login or just slash register without the slash out first is it possible to do a shared layout well actually it is and there is a specific way you can do that so here's what I recommend you do remove absolutely everything uh regarding this out folder so just the out folder not everything and you should be getting a 404 and you can just go ahead and return to Local Host 3000 like this and here is what I'm going to do so I'm going to go ahead and create a new folder but this time I'm going to wrap it in parentheses and I'm going to call it out again and then inside I'm going to create another folder called login and another page and very simple simply I'm going to do the same thing login page they login page without out prefix like this so can you guess what this does well I think you kind of can guess because of this text which we wrote how do we access this page now well I'm going to give you a tip we are not writing Al anymore so this wrapping in parenthesis is a folder convention in nextjs which tells the router that this is a specific segment right so this can hold its own layout just like our previous out folder could but one cool thing is that this will not be visible in the URL segment so if you go ahead and go to localhost 3000 SL log directly there we go so this helps us both organize our routes better especially if we're going to have a lot of out routs like a login register forgot password this that right so because of that these kind of Route groups are especially useful and here's another cool thing of course if you create a layout. THX file it will still work so I'm going to go ahead and create out layout here I'm going to go ahead and extract the children and I'm going to Simply write a div here a Navar this is navbar without out prefix let's give it a class name BG red 500 and a text of white and let's render the children below and there we go so you can see how we are still sharing the layout but look at our URL it is just localhost 3000 SL login so I just wanted to clear that up there's a lot of possibilities that you can do inside of the uh app router right you can read the documentation and find so much more things that you can actually do but I'm explaining some Concepts that I will be doing in this tutorial so I just want to make sure that you're not getting confused Ed when it comes to doing that uh great and there's just a couple of more things I want to show you so I want to show you this so if you go ahead and create a folder inside of the app and let's call it components for example and inside if you have a file called page. vsx right and if you accidentally do an default export like components page and a div components page you already know that this is going to become a route right but look at how this looks we technically don't want this to be a route right this looks like it should be an inner components folder but if I go to my local host 3000 SL components look at this it renders the components page that is definitely not something we want right because if you write it like this you're probably bringing in you know some habits from single page applications because you used to write it like this so here's a little tip that you can do which is similar like this route groups but what's different is that it completely it tells the it tells the router to completely forget about this to never put this in the router you can do that as well by adding an underscore like this and you might get this like like weird one unsaved file inside of your next types if that happens for you just click on it save it and close it that's it and let's go ahead and check it out now look at this now localhost 3000 is a 404 page that's perfect so that's how you can omit the folder from the router if you for any reason inside of the app folder want to have a file called page but don't want it to be a part of the routing system you can do that as well and you're going to see me use this convention undor components whenever I I'm creating some components which will only be used once so not reusable I'm going to keep my reusable components here where the shatan component uh buttons are uh great so if you're having any trouble with this next folder which you know might happen here's another little tip that you can do so inside of your terminal just shut down the app go ahead and remove the next folder and just do mpm run Dev again there we go you don't have to worry about the next folder because that is just cache and it will regenerate every time you do mpm runev great so I hope you kind of understand how routing works and some tips and tricks here and I just want to go ahead uh and show you the difference between a client and a server component to wrap this up so we can remove theore components folder and we can remove the out folder so just like we started uh a globals file a layout file and a page file so right now if you create any file be that an error or page or layout or components inside of the app folder by default that's going to be a server component what that means is that if you go ahead and do a console log here and I'm going to say Where am I logged like that you might be expecting to see that log inside of your inspect element but no matter how many times I refresh it's never logged here instead you can find it inside of your terminal that's because by default this is a server component there we go where am I logged so if you want to turn it into a client component what we have to do is Mark it as useed client at the top like that let's check it out now so now if I go inside of my uh inspect element there we go we successfully converted it to a client component so when is one going to be more useful than the other so client components are your normal react components so inside of these components you can add a use effect for example so I'm going to add a little use effect here here with an empty dependency array and I'm going to console log mounted like this and if I go ahead and log this there we go it says mounted right here but what happens if I remove the Ed client which will turn it back into a server component you will see that I'm going to get an error and it's very clear what it says you're importing a component that needs use effect and that only works in client components but none of its parents are marked by used clients so they are server components by default and you can of course click here on this link to learn even more about that so you just figured out that client components are useful for interactivity right for use effects on clicks all of those things but server components cannot do that kind of stuff what they are good at is being asynchronous so you can turn any server component into an asynchronous function and then what you can do when we connect with the database you can do something like const users to be aw and then imagine we have a database dot well something like this right you can actually call the database inside of the server component and then you would probably like return it to a client component like this data users something like that and then client component would be all nice and interactive so you can imagine server components like an API route like a get route something like that great I hope that kind of cleared it up so uh just go ahead and turn this back into a server component so this is the only thing you should have inside in my app folder I reverted everything to the original so I only have page. CSX right here uh great so you figured out how routing Works inside of nextjs if this is your first time doing this I would suggest you kind of practice on your own a little bit before continuing forward confirm that you know how this works and what we're going to do in the next module is we're going to go ahead and connect to our database and create our Prisma schema and then we're going to start incorporating next out version five great great job all right so if you sped up the last part or if you skipped the last chapter completely I just want to show you my app structure so I didn't add any new files I did add them during the explanation but then we removed those files the only thing I believe is different inside of our page. CSX I added the asynchronous tag here so if I remove it it should be exactly the same as your file because I was explaining something about server components here so I mentioned by the end of the last chapter that now we're going to connect to the database but that's actually not what I want to do immediately first I want to do something else so let's go ahead and let's go inside of our ad folder global. CSS and let's go ahead and and add HTML comma body comma column root and let's go ahead and add height 100% like this so all of our pages are at its full height once we've done that let's go ahead and let's create our landing page which is going to have our first out component called the login button which is then going to open or redirect to the out form so let's go ahead inside of the app folder inside of page. X right here and let's go ahead and remove this and let's add a main element here let's give it a class name of flex Min height screen actually I believe we can just do H full here let's give it Flex call like that items Center and justify Center so everything inside of this main element is going to be centered right here in the middle and let me just turn off my co-pilot here so it doesn't confuse uses all right uh and here's what I want to do next I want to add a specific background color to this main element so if you want to you can do BG uh Sky 500 for example and that's going to give you this nice background color but I want to use a specific gradient that I really like so if you want to you can write along with me uh so you can see how Tailwind can do some very specific gradians if that's what you want to learn so I'm going to write BG Dash I'm going to open Square brackets again this is completely optional right you don't have to do this you can just use the BG Sky 500 so I'm going to write BG and inside of the square brackets I'm going to write radial Das gradient I'm going to open parenthesis I'm going to write ellipse underscore atcore top then I'm going to add a comma and I'm going to write underscore VAR I'm going to open parenthesis again I'm going to write D Das TV tww sorry Das gradient Das stops like that and then outside of this square brackets I'm going to write from Sky 400 to blue blue 800 like that and there we go so this is the gradient that I like of course this is just for fun you don't have to do it like this you can simply write BG Sky 500 or red whatever you prefer now inside of this let's create a with a class name of space y 6 like that so what whatever whichever elements are inside are going to be equally spaced by a value of six which you can see the full calculation here great and now inside I want to add an H1 element and I want to write out inside and I'm going to give it a class name of text 6 EXL font semi bold text white and drop shadow medium like that and there we go we have a nice out text here in the middle and if you want to you can add a little Emoji here so I'm on a Macbook so I have this little shortcut uh which can open my emoji tab here and I can add a little uh key lock icon right here you don't have to do that right uh great and below that I'm going to add a paragraph and I'm going to write a simple authentication Service and let's give this paragraph a class name of text white and text large like that and there we go we have our nice little uh landing page here if you want you can add a text Center inside of here so all of the text is centered nice and neat like this great so what I want to do now is give this Al uh a special font called Poppins so I want to show you how to add a custom font you can do that by importing the font you want font for example Poppins from next font Google so it uses Google fonts and then you can do const font to be Poppins subsets Latin and let's give it a single weight of 600 because we know we are using the semi bold option and let's go ahead and let's import the util CN from at/ Li utils so now we can combine this existing class name with our font so let's let's wrap the entire class name of the H1 element inside of curly brackets like this so make sure this class name is inside of curly brackets and then add a CN wrapper around it so like this wrap the entire thing in CN and I'm going to use this existing class name as the first argument and the second argument is going to be this constant font and then we're going to extract the class name from that font like that and that should give our out just a tiny bit bit prettier font great so what I want to do next is go below this paragraph and I want to go ahead and create a div and I want to render a button component we should already have the button imported from here so make sure you have that and let's write sign in let's give it a variant of secondary let's give it a class name uh W full actually we didn't have to give it let's go ahead and simply give it a size of large like that there we go so right now when you click on it nothing will happen so what I want to do is I want to create our first out component called login button so let me go and close everything here and let's go inside of the components and not inside of the UI folder but just inside of the components create a new folder called Al like this so you should have the UI folder and the out folder and inside of it create a new file login button. CSS X like that let's go ahead and Mark this as use client because it's going to have some interactive elements let's go ahead and create an interface login button props it's going to accept children which can be a type of react. react node it's going to accept a optional prop called mode which can either be a model or a redirect and let's also give it a third optional prop actually the second optional prop but third overall and that's going to be a Boolean like that so let's go ahead and write export con login button here and let's extract this props so login button props let's get the children the mode and the as child like this and what I want to do is set the default mode to be redirect if the user doesn't pass anything it's going to be redirect like that and then what we're going to do is we're going to Simply return a span with children in inside and let's give this span a class name of cursor Das pointer like that and now let's create an onclick function so Con on click it's going to be consol log login button clicks and let's give this an on click and pass in the on click function like this there we go we have our first login component sorry our first out component called login button and now I want to go back inside of my app folder page and I want to wrap this button and turn it into a component that in the future is going to serve as the login button great so it doesn't have to be a button it can be whatever we want so let's try this out now if we've done this correctly once I click on this in my uh inspect element here I should see login button clicked and I have perfect so now we have a little util so that we can turn any element we want be that a button or something else inside a login component right but obviously we don't have the actual uh model mode finished here so this is what I'm going to do so inside of the login button where I'm here right now let's write if mode is model for now I'm just going to write a little span here which is simply going to say too Implement model like this so if you go back to page and give this a mode of model it's just going to say to do Implement model right great so we're going to come back to this later what I want to do now is actually add this on click functionality so in order to do that let's go ahead uh and let's import use router from next navigation make sure you don't import it from next router so inside of the app folder we're using next navigation and let's go ahead and add our router so con router is used router like this and instead of this console log what we're going to do is router. push to slash out slash login so that's going to be our login route in the future great so let's go ahead and try this out now uh make sure in your page you don't have the variant model so just leave it as it is and when you click you should be redirected to a 404 page great so we finished our uh homepage very simple screen here and what we're going to do next is start building the form components and then when we finish the register form that's when we're going to add the database so that we can actually send those values from the form to our database and store it great great job so now let's go ahead and let's actually create this route which is currently a 404 so when we click here we get redirected to a 404 I want to fix that and I want to show an actual box so inside of our app folder we have to create that route and we know the URL the URL is local CL 3000 sloulin so exactly what we've written inside of components out login button right here so we're going to create this very route go inside of the app folder and create a new folder called out and then inside another folder called login and let's go ahead and give it a page. vsx so just like we practiced in the second module let's go ahead and do a default export here of our login page and let's create a div login page like this and there we go we should no longer be getting any errors so when you click from your homepage to here you should see the login page great now let's go ahead and let's add a layout to this out folder so that every single route that we have be that login register new password forgot password all of those things will share the same layout so create a layout. CSX file like that and let's export default out layout let's go ahead and extract the children and the type for the children is react. react node like that and if you want to you can collapse them like this so it's just a bit more readable great and now let's go inside and render the children like this and nothing should change for now so what I want to do is give this div a class name with a page full Flex items Center and justify Center and now our text is in the middle of the page and now I want to add it a background color so we can do that you can either simply write BG Sky 500 like this or you can copy if you've written like I did in our homepage in app page you can just copy this BG gradient and the from sky and the two blue like like this so I'm going to paste that here instead of this and there we go now I have the exact same uh background color both on my homepage and here on the login page like that and we are done with the out layout nothing more we have to do here so let's go back inside of our login folder page. vsx right here so in here we're going to do a very simple thing instead of returning a div we're going to return a login form component which right now does not exist so let's go ahead and let's create it so we're going to create that inside of components out so we will be able to render the login form either in the page or if you remember inside of our components login button we have a model to implement so we're going to have we're going to be able to reuse the login form either in a separate route or in a model if that's what we prefer great so go inside of the out folder in the components and create a new file F login form. CSX like that and let's go ahead and Export const login form so we are not exporting default here because this is just a component it's not a page and let's go ahead and return login form like that and now we can go back so I'm going to close everything we can go back instead of the app folder out login page. CSX and we can import the login form from components out login form and you should see that rendered right here what I want to create next is a card so every single one of our elements like uh login register new password verification all of those things are going to be rendered inside of the identical card model so we're going to create a f a file called card wrapper in order to do that we have to go inside of our terminal first you can either shut down the app or open a new a new terminal like this and write npx shat CN UI at latest add card like that and that's going to add a card component inside of your project that's it you can close this terminal make sure you have npm runev running and just refresh your app to make sure everything is synchronized great so now let's go inside uh of the components out login form and inside of here we're going to go ahead and we're going to wrap the entire thing inside of a component called card wrapper which also does not exist yet so if you save you're going to get an error so let's go inside of the out again inside of components Out Create a new file card wrapper. vsx like that and let's go ahead and Mark this as use client component and let's create an interface card rapper props let's give it a children of react. react node let's give it a header label which is an required string let's give it a a back button label which is going to be a string let's give it a back button hre which is also going to be a string and let's give it a show social which is an optional Boolean and now let's export con card wrapper here and let's go ahead and extract those props so card wrapper props like that and now we can destructure the children the header label the back button label the back button hre and the show social like this and now inside of here what we're going to do is we're going to return and render a card from do/ UI card you can see how I added this import here so you can either do it like that the reason it can imported from here is because we are already in the components folder so it's this one that we're working with card wrapper so it goes back one file back another folder and it goes inside of the UI card or you can do add/ components UI card if you want to be consistent throughout the project both will work just fine and besides the card we're going to need a couple of more elements so we need the card we need the card content we need a card footer and the card header like that so let's go ahead and wrap this inside of a card let's go ahead and give this a class name of with 400 pixels and Shadow medium like that and inside render the children like that now go back inside the login form here and you can import that card wrapper from SLC card wrapper and there we go you should have a little typescript error but you should be able to see your login form inside of a card this time great so let's go ahead and give this card wrapper all the props it needs so the Heather label is going to be welcome back the back button label is going to be don't have an account question mark the back button HRA is going to go to slout SL register and we're going to have a prop show social so we show the login buttons using Google and GitHub like that great and we no longer have any typescript errors and it should still be rendering just fine now let's go ahead back inside of this card wrapper component and let's style it a bit more so what I want to create is a reusable header component so let's go ah head and do the following inside of the out folder in the components create a new file header. CSX like that let's go ahead and import popins from next font Google let's go ahead and let's import CN from lib utils let's define the font using the popins import and just as we did in the landing page we're going to give it a subset of Latin and a weight of 600 like that and let's create an interface header props here to accept the label which is a string and let's export con header component let's go ahead and extract the props so header props label like this and inside very simply we're going to return a div with a class name of uh with full Flex Flex call Gap y4 it Center and justify Center and inside an H1 element which is going to say Al like this and if you want to you can add a little Emoji like I am doing right now great let's give this H1 element a class name which is going to be dynamic so let's use the CN library and first let's find the default class names which is going to be the text 3 Excel and font semi bolt and then let's pass in the font. class name here like that and below that we're going to add a paragraph which is going to render our custom label which we're going to reuse for different types of login components let's give this paragraph a class name of text muted foreground and text small like that and we are done with our header component now we can go back inside of the card wrapper component here and we're going to use this header label to render our new header component so instead of rendering the children here above that add a card header which we already have imported so just ensure that you have this and inside of here we're going to render our reusable header component which you can import from do/ header like this or if you want to be consistent you can use components out header like that and there we go you should be seeing our nice out text right here so let's go ahead and give this header a label which is going to be header label like that and there we go we have a nice text which says welcome back perfect so let's go ahead and see what else we have to do let's wrap these children inside of card content like that there we go you can see how now the text is indented and it's no longer all the way to the side of this border perfect and now what I want to do is I want to create the social components and the back button components so let's go ahead and do this if we have a prop show social go ahead and render the following we're going to render a card fotage which we also have imported so you should be using all of this here and inside of here we're going to render our social which currently is not defined so let's go ahead and create that so inside of the out folder create a new file social. CSX let's go ahead and Mark this as use client and let's export cons social and let's return a div with a class name of flex item Center full width and again Gap x2 in between the elements which we're going to have inside and in order to render the Google and GitHub icons I recommend that you install a package called react icons so let's go ahead and do mpm install react icons like this let's wait a second for this to install and refresh your page you should still be getting this error here in order to get rid of the error we can already go back inside of the card wrapper component and import the social from do/ social if you want to be consistent you can change it to components out social the same thing we did with the header because all of these components are in the same level in the components folder out right here so outside of the app folder let's go back inside of the social. CSX and let's render those buttons so I want to go ahead and I want to import FC Google from react D ions slfc and I want to import fa GitHub from react D ions fa now inside let's go ahead and let's render a button component from do/ UI button or components UI button like this and let's go ahead and just simply render the FC Google in here and now let's give this a size of large let's give it a class name of withd full let's give it a variant of outline and on click for now can just be an empty Arrow function like this and let's give this FC Google a class name of H5 and width five like that and we can copy and paste this button one below another and give this one an fa GitHub like this there we go we now have our social logins of course we will add the functionality later but this is very cool because we will reuse this card wrapper and we have the props to hide or show the social buttons depending on how we need so let's take a look at this now there we go we have beautiful GitHub and Google Icons right here and if you go inside of your uh login form here so inside of my components out login form and if you remove this so show social there we go they are hidden if you bring it back they are shown right here great so uh let's go ahead uh also if you want to you can change this to add/ components Al card wrapper so I just like to be consistent with this import alas it doesn't really matter great so now let's go ahead back inside the C C wrapper component and what I want to create now is the last component we need which is the back button component so let's go ahead and add another card footer here and inside we're going to render the back button component like this and let's give it an HRA of back button HRA and let's give it a label of back button label so you should have both of these props the structured from here great and you should be getting of course an error because our back button component does not exist yet so let's go ahead and create it inside of the components out folder back- button. CSX like that and let's go ahead and let's mark this as use client and let's export const back button and let's return a div which uses the button component like this and I will just change the import to use component cui button now let's quickly create an interface back button props to accept the back uh the hre which is a string and the label which is a string like this and now we can destructure those props so back button props we can get the hre and the label like this great now let's go inside of the button here and let's go ahead and add a link component from next SL link so make sure you add this import and we're going to give this an HP of hre and inside we're going to render the label like that uh my apologies so I just uh exited the back button so we were here so label like this uh and let's go ahead and give this button a variant of Link let's give it a class name of font normal and with full let's give it a size of small and let's give it an as child property so we can properly render the link component inside like that great now we can go back inside of the card wrapper and we can import the back button component from slashback button or components out back button and there we go we should now have our back button when we click it should be a 404 page because we don't have that hre yet perfect so we created a reusable component and now we are ready to set up our form great great job now that we have our reusable card wrapper let's go ahead and let's actually implement the fields which make the form in order to do that I want to go inside of my terminal here and I want to add a package from shaten so let's go ahead and write MPX shat cn- UI at latest ad form this is going to add a couple of elements but also a couple of packages inside of our app and let's also well let's take a look at everything it added right so we can see that it modified our package Json so when I click here there we go it added hook form resolvers some radx UI Primitives for the label it added react hook form and Zod for validation so we have the form and the label but we are missing uh one specific field here so let's go inside of the terminal here and let's add npx Shaden dasi at latest add input like this so this one does not add the input by itself so we have to manually add the input great so once you do that make sure that you have npm runev running refresh your Local Host to ensure everything is working now let's go ahead and let's go inside of our components out and let's go inside of the login form right here and the the first thing I want to do actually is I want to create a form schema which I'm going to use inside of this form and I'm going to keep all of my schemas in one place so let's go inside of the root of our application and create a new folder called schemas like that and inside simply create an index.ts so from here we're going to do the validation on the front end but also on the back end by easily importing it from this common folder here so let's go ahead and import everything as Z from Zod which we have installed and let's also uh well no need to import anything else instead we can export const login schema to be z. object like that and let's simply give it an email which is z. string and a type of email and let's give it a password which is simply going to be z. string in the register form we're also going to add uh a minimum value of six but for login I don't recommend you do that because remember your password standards can can change right so you might have some users which uh created their account before you updated the minimum length of your password so so it's kind of a good recommendation from me to you that you don't limit uh the minimum length of the password on login on register that's fine for new users right but on login make sure you don't block anyone if they have an old password which you allowed at the time so just leave it like this great so now we have our login schema and let's go ahead and let's import inside of this login form everything we need to create our form so we're going to need use for form from react hook form we're going to need Zod resolver from Hook form SL resolvers SL Zod like that and let's also go ahead and import everything we need from s/ components UI form like that so we are going to need the form itself the form control we're going to need the form field form item form label and form message like that and now let's go ahead and let's define our form here so I'm going to write const form to be use form like this and let's go ahead and give it a type in order to give it a type we have to import Zod so let's import everything as Z from Zod and let's also import our login schema from at/ schemas so just make sure that you exported this constant like that and then you can use the combination of those two so this is going to be z. infer open pointy brackets again type off login schema like that and now let's go ahead and give it a resolver to be Zod resolver which we imported and pass in login schema again and let's now give it default values and because we added the types right here you can see how it will autocomplete the email to be empty and the password to be empty like this great so we have our form hook right here and let's go ahead uh and let's see if I need to mark this as Ed client I believe to get rid of these errors yes so make sure you mark the login form component as use client you can see how when we don't have that we have uh some errors and they're not exactly clear what's going on right but I assumed it's because the moment you use a hook inside of something you probably need to add well you definitely need to add use client at the top so just ensure you have that and your page should be well working right and now we can use this form to actually uh create our elements so let's go inside of the card wrapper and let's add the form with the capital F right here so we imported that from this make sure you have all of these imported because we're going to use all of those from components UI form and and what we have to do in this component is spread this entire constant so let's go ahead and simply spread the form and that will give it all the props it needs except the children which we are going to write now inside this form wrate write a native form element here and give it an onsubmit to be form. handle submit my apologies form. handle submit and you can just give it an empty Arrow function inside like this so form which comes from this constant handle submit and then simply an empty Arrow function we're going to change this with an actual submit function later and let's also go ahead and give this native form element a class name of space Y6 like that so this is going to separate the inputs from the login button and now we're going to create a div which is going to hold all the inputs and that is going to have spacing of four like that great so let's go ahead and let's create our email field so let's use the form field which we already have imported and form field is a self closing tag like this so make sure you have form field imported and make sure you use it like this let's give it a control or form. control let's go ahead and give it a name and you can see how it only gives us these two options because it knows our schema and then let's use the render field to extract the individual field and immediately return a form item component like that inside of it a form label component which will say email and below it let's add a form control component and finally let's add the input which we forgot to import so let's go ahead uh right below here and let's import the input from at/ components UI input like this great and there we go now what we have to do is we have to give this input controls which match our form so we can simply spread the entire field prop and that's it this is now a controlled component let's give it a placeholder of John example.com and let's give it a type of email like this and there we go we have our first field right here which says email great and you can see how we have some validation you can see when I press enter here this one uh has an error right here but we are missing the actual message so you can try and press enter inside of the field when it's empty and you should get a little uh error here so what you can do is go outside of form control and add form message I believe we have this imported as well form message there we go and you can see how now I have an error so if you go inside and press enter you're going to get invalid email here and if you ever want to change those errors you can so for example if you want to change the one for the invalid email I believe you can simply go inside of here get a message and write email is required for example let's see if that one is that and there we go I just changed it to email is required so if you want to you can always modify uh I believe for every additional chain you have the message object but if you want to modify the first one then it doesn't have the messages you can see but it does have invalid type error so in here you can say must be a string or something like that if you want to explore Z more you can play around with it I'm mostly going to leave the error messages as they are great so now what we have to do is we have to copy and paste this field and give it to our password right so go ahead and copy the entire form field like this so here's where it starts and find the end of the self closing tag and inside of this div with space y4 spacing simply below it copy and paste it and you should now have two email Fields let's change the bottom one to have the name of password let's give it a label of password and let's go ahead and change the placeholder to be 1 2 3 4 5 6 in the uh stars number right and type is going to be password like that and there we go we now have our email and password Here what I want to do next next is I want to add a submit button so let's go ahead uh outside of this div right here but still inside of the Native form and let's add a button component so we need to import that as well I just did it automatically fromt do/ UI button or components UI button however you prefer all right make sure you added this button here and I want to go ahead and write login like this and I'm going to give it a type of submit and the class name with full like this and there we go now this is our submit form and you can see how it has uh that something is an invalid email until we give it a proper build right here uh and yeah let's go ahead and just add I told you that you don't add anything here but just add a minimum value of one at least right and you can modify this message to say password is required so we are not explicitly going to instruct the user that it needs to be six characters because this is not a registration form right they already have a password we cannot instruct them what their password must be because they could have created this account a long time ago when we allowed three characters or something like that so I believe now there we go it says password is required because if you don't add this message then it's going to tell you that a minimum you can see the string must contain at least one characters it's it's kind of a weird error like this so you can uh give this a password is required and I'm also going to modify the email then message to be email is required like that great so now if I try and submit an empty form there we go email is required and password is required looks much nicer great so how about actually submitting the form how do we go about doing that well we have to create this empty Arrow function which we started doing right here so go ahead and simply write Con on submit or handle sorry onsubmit let's do it like that and in here we have access to our values and the values are going to be a type of z. infer open pointy brackets type of login schema and if you console log the values and add this onsubmit function here instead of this empty Arrow function here so form. handlesubmit and then inside we pass in our onsubmit so this wrapper will pass in the validated values right here so let's try it out so in here I'm going to open my inspect element here I'm going to give it a name uh of example mail.com and 1 2 3 4 5 6 for the password and there we go we have an email and we have a password right here great so there's a couple of more components that that I want to create before we go into actually submitting this and that's the form error and form success components so let's go inside of our components overall so this time not inside of the out folder because this this this isn't exactly uh tied to out so just inside of components add a form uh error. CSX like this and let's go ahead and let's import from at radic UI react icons so in the beginning of the project I told you when we set up shaty and UI to choose the New York style if you chose the New York style then this is the package you're going to have by default uh for icons otherwise if you chose the default style you can try Lucid icons or Lucid react I'm not sure what it is but if you watch my previous videos you're probably familiar with it basically this is just to get the icon we also have fa icons so you can choose any icon you want from here I'm going to export exclamation triangle icon meaning that something is going wrong exclamation triangle icon like this I will create an interface form error props to optionally accept a message and let's export const form error like this let's destructure the props form error props like this let's get the message out and if there is no message simply return null otherwise we're going to return a div with a class name of BG distructive sl15 padding three rounded medium flex oops where was I in the form error Flex items Center Gap X2 text small and text destructive and then inside I'm going to render the exclamation triangle icon with a class name of height four and width four and I'm simply going to render a message inside of a paragraph like this great so make sure you have this little component and now we can go back inside of the login form and this is where I'm going to keep them so I'm going to keep them above the button here so if I add form error from do/ form error you can see how it automatically imported it here or components form error if that's what you prefer like I do you can see by default nothing is shown but if I pass in a message to be something went wrong this is where that's going to pop up right or for example email taken something like that or invalid credentials so this is we're going to keep those errors and I prefer it this way rather than a toast notification especially when it comes to you know notifying our user that we've sent them a confirmation email or something like that I want that to stay here we're can use toast notifications later for different stuff but for this one I want it to be like this and besides form error I also want to have form success component and luckily for us it's almost exactly the same so just copy and paste this here and rename this to form success and we're just going to tweak the colors and the icon a little bit so rename this instances to form success and let's go ahead and change the icon to be check circled icon or you know if you're using react icons just import whatever you like from here or use an emoji it really doesn't matter uh and now let's just change the colors do not be BG destructive but instead uh Emerald emerald 500/15 and text is going to be BG Emerald 500 as well so just don't misspell Emerald you can hover over a class name if you have the Tailwind extension to confirm that it exists great and now we should have the form success component so I'm going to copy and paste this and call this form success from do/ form success I'm just going to change this import to use components because I prefer it this way and instead of invalid credentials we're going to say something like email or something like that and there we go you can see how this is going to look like most of the time only one of those are will be available so either the success message or the error message like this and just to clear this up let's just go ahead and simply remove this to be an empty string like this great so I'm going to wrap it up for now what we're going to do next is we're going to create our first server action and get a little bit familiar with how we're going to send the data to the server you of course don't have to use server actions for this tutorial it's just something that I prefer if you prefer API routes that's perfectly fine this project does not depend on server actions at all so you don't have to worry about that great great job so what I want to do now is find a way to transfer these values from our client component to the server for that I'm going to be using server actions that being said if you do not prefer them you don't have to use them if your project uses API routes this authentication Service and everything we learned today will still work just fine it's just a way to pass something from the client to the server and my choice for that will be server actions which are built in rpes in next js14 and I'm just going to show you exactly how simple they are so let's go ahead and do the following I'm going to hold all of my actions inside a new folder in the root of my application so let's go ahead and create a new folder called actions like this now inside I'm going to create an action called login. THS and the first thing we have to do when building any action is Mark it as use server this way our server code will never be bundled with the client code so this is now as uh equivalent of an API route so let's go ahead and Export con login let's accept the values for now let's give them a type of any and let's simply do conso log values like this that's it this is a server action a completely valid server action what you can do now is go back inside of your components out login form and inside of here what you can do is call the login from actions login so make sure that you add this import where is it there we go import login from actions login make sure that this is us client like that and simply pass in the values and that's it this is a server action can you guess where this will be logged on the server that's right so prepare your terminal right here like that and let's go ahead and enter some values so fake email and 1 2 3 4 5 6 and there we go we have successfully passed our values to the server server actions can be as simple as that I know there's a lot of examples going on about how complex they are with all the new hooks use form status use form State we're not going to be doing that that is for Progressive enhancement and while that definitely has its pros I feel like that's a whole module that we have to go over before we can even touch out so I'm not going to be doing Progressive enhancement in this tutorial I'm simply going to be using them as an extremely simple way to pass something from the client to the server right so that's what we're going to be doing today uh that being said if you don't like server actions you could just is easily done you know axio that post your API route and simply pass in the values and then then and do catch right it doesn't really matter but I am going to be using uh the server uh actions in this tutorial great so how do we get the pending state from uh This Server action right well there are a couple of ways we can do it we can manually set pending you know let's imagine that we have a US state here and then you know do finally here we would call it and change it to set pending false but there is an easier way which is by using the builtin use transition from a react so add use transition from react here and let's add it here to the top and we're going to exp extract is pending and start a transition from used transition like this and then what you can do is go inside of your own submit function and simply wrap this login inside of a start transition like this and then what you can do is go ahead and use this is spending to disable all the states you need for example I want to disable this input while it's pending like this I also want to disable the password input while it is pending and I want to do the same thing for the button so disabled is spending and I believe that now it will only be a very quick second but you should see a blink happen right that is the disabled field so why do it this way why use start transition well you didn't have to use start transition but it will be very useful if you ever do any of the next cash or revalidation or redirects here so if you happen to do to revalidate path or revalidate tag right which are nextjs cache functions uh usually you couldn't exactly catch the end of them by using do then or something like that but start transition can do that so start transition start transition can tell you exactly when something like this has ended so that's why I prefer using it like that and it works just as fine if you don't use it if you don't use uh those inside so this is going to be the way I'm going to be passing things from the client to the server again you know you're not required to do this if you prefer AP routes sure thing uh and what I want to do now is kind of establish how we're going to validate the fields on the server so you can imagine this code AS exactly what you would do in your API route again if that's what you're preferring so first things first our values are not a type of any they are a z. infer and in order to do that we need to import everything as Z from Zod and we don't need this and we need a login schema from schemas like that so z. infer type of login schema like this and there we go now our login form has no errors because this is exactly what our server action is expecting right here and what I want to do now is actually validate these fields because remember client side validation can always be bypassed it's very easy to do that so what we're going to do here is ADD const validated fields to be login schema do save pars and again validate the values but this time on the back end where no one can manipulate it and then we're going to write if validated fields. success sorry if not so make sure you put this exclamation point here so if we didn't get back a success field from this in that case I'm going to go ahead and return an error invalid Fields like this so if you were doing this in an API route this would probably be something like return response uh I'm not exactly sure is it ajon or something like that basically you would return back with this kind of object uh and let's go ahead and give it a default of success to be uh email sent something like that so just mocking these things for now great so but now we know that our login schema here is validating our Fields so let's go ahead and do the following what I want to do is find a way to use these errors and the success messages and display them on the form and we can do that thanks to these fields which we've set up form error and form success and I'm really not going to complicate this so I'm just going to add two State Fields one for error and one for Success so let's go ahead and pass in con error set error to be use state from react with a default value of an empty string so let's go ahead and see uh where did I import this there we go use State and use transition from react I'm going to copy and paste this and the lower one is going to be success and set success like this and then inside of our onsubmit on then I'm going to get the data and I'm simply going to set error to be data error and Set uh success is very simply going to be uh data. success like that and let's just see uh if I'm uh doing anything wrong here so login yeah is also supposed to be an asynchronous function like this uh and does that fix it data oh yeah yeah so sometimes the error can exist and sometimes it doesn't right so here's what I did so make sure that the login function is an asynchronous function I mean the server action make sure this is an asynchronous function and in here in order to fix this typescript error we have to be a bit more specific with the type of our uh error and success which can be a string or undefined like that and we should no longer be having any typescript errors and every time we hit a new submit let's go ahead and clear all errors and let's clear all success messages like this uh great and I believe that we should already be seeing something and what we have to do is now just pass the error message to use error and success message to use success like that so let's for now let's manually just throw throw an error first because I believe our validation will pass so let's try it with with an error first so just return an error object so if I try anything mail and any password there we go I get an error in valid Fields perfect and now let's go ahead and enable this back so make sure you bring this back we we are only going to throw an error if our backend Zod validation fails otherwise we're going to throw this success message so let's try that now and there we go now it says email sent perfect so this is our first server action you can see how simple it is to use and you can see how easy it is to control the errors the success messages and get the pending State using start transition and this is completely safe this is just as it as as you would write you know your own API thanks to this use server Clause so this code is never bundled with the client so you don't have to worry about any secrets being spilled here great uh and what I want to do now is well create a register form and the reason I want to do it because we can't log in into any anything right no there's nothing here I can write anymore except just you know throwing these errors so let's go ahead and create our register form so the first thing we have to do is we have to create this currently 404 route so when you click on don't have an account it should lead you to slash out/ register so let's go ahead and resolve this so it's not a 404 page so go inside of app Al and you can just copy and paste the login and rename it through register like this and that should resolve this I believe if I refresh there we go now both my login right both out register and out login will show this login component but don't worry we're going to go ahead and resolve that now so go inside of register go inside of page let's go ahead and rename this to not be login page but instead instead register page like this what I want to do now is I want to go inside of my schemas so let's go inside of schemas index. Cs let's copy and paste this schema here and let's create a register schema so we're going to have an email we're going to have a password but the minimum value for the password is going to be six because uh well because this is a register form so we can tell the new users the new instructions and instead of password is required here I'm going to write minimum minimum six characters required and besides email and password we're also going to have a name which is going to be a a string with a minimum value of one and let's give it a message of name is required like this there we go so make sure you have the email the password and the name and now what I want to do is I want to create a register form so in order to create a register form we don't have to do much because we have most of our reusable components so that's going to be inside of components out in and inside of here so let's start by copying the login form and pasting it inside inside of the out folder right and let's simply rename it to register form. CSX like that and go inside of the new register form so make sure that you are inside of the register form in your tab here and simply rame this to not be a login form but instead a register form and we are no longer going to be us using the login schema so find the import for the login schema and remove it and instead import register schema doing it like this will help you see all the errors you have so you know where to change it so I know I need to change it here to use the register schema I know I need to change it here and here in the onsubmit as well and I already know that inside of my default values I'm going to have one more which is a name so I can simply add a name here as well like that and let's go ahead and modify this card rapper so instead of welcome back it's going to be create an account the back button label is going to be already have an account with a question mark and it's going to lead it to out login and I I'm going to keep this show social as well because they're going to work equally on login and register components great and there there's honestly just one more thing we have to do here is copy an existing form field like an email and paste it and change this one to have a name of name and a form label of name and the type doesn't matter and the placeholder is going to be John do like that and now what we have to do is use this new register form so go inside of your app folder go inside of out register page and remove this import and instead add a register form from components out register form and let's use it here and there we go now we have a login form on out register we have a back button that leads us to the login form and this one leads us to the register and we obviously have to modify a a few more stuff you can see here I have the button login so let's change that so go inside of the register form inside of components out let's find the login button there it is and let's change it to create an account or register whatever you want there we go now when I click here I should be getting this error so minimum six characters required email is required and name is required perfect so I'm going to go ahead and just prepare an equivalent server action for this as well so it's not going to be using the login action instead it's going to be using the uh register action so instead of actions well you can just copy and paste this one right and let's rename it register like this go ahead and remove the rename the expert cons to be register as well and remove the login schema and import the register schema so now you know where to change them and there we go it can stay exactly the same now go back inside of your components out register form here and go ahead and find where you import the login action and change it to be the register action from actions register and now you're going to have this little error the on submit and there we go the types should be completely fine so if I try this now Antonio test and a password there we go I have a success message that email was sent perfect so you've just learned the basics of server actions and you just saw how fast we created our register form so that's how handy it is this little card wrapper which we created so we can easily change the label the back button and where it leads and of course well it's easy to copy and paste this form Fields as we need them as well perfect so what we're going to do next is we're actually going to be using this actions in the register to create a user inside of our database and encrypt their password in order to do that of course we're going to have to connect to a database and uh well start creating some Prisma models great great job so now it's time for us to transfer these values which we've success ful put on the server side now and add them to our database in order to do that we first have to set up Prisma which will be our omm for this video so let's go inside of Prisma and we can shut down the app sorry let's go inside of the terminal and we can shut down the app and first let's install Prisma so we have to install this inside of Dev dependencies so mpm install D capital D Prisma like this after Prisma has installed go ahead and install npm install at Prisma SL client like this and after this has installed we're going to go ahead and we're going to create our Prisma util so let's go ahead and do the following so make sure that you have both of this installed the Prisma client in your package Json and Prisma in your Dev dependencies here now let's go inside of the lid folder and create a new file called db. CS like this and inside of here let's go ahead and import Prisma client from Prisma SL client let's go ahead and declare actually let's not do this immediately because I want to show you why we are doing this so first this is what we're going to do expert constant database to be Global this. Prisma or new Prisma client like this and you can see that we have this little error here we're going to fix that with what I started writing here but I decided we're going to do it later so I can explain why we're doing that and now let's write an if Clause if process. environment node environment is not production in that case let's go ahead and assign Global this. Prisma to be the database variable like this in one line so we have to add uh types for Prisma in global this now so let's go ahead and do that we can fix that by adding declare Global VAR Prisma to be a type of Prisma client or undefined like this and you can see that now we have no errors in global dis. Prisma and you can see how we have the type for it so why are we doing this well it's because of nextjs hot reload so as you can see we could have easily just done this so imagine I didn't write any of this and just wrote export cons DB to be new Prisma client this is what's going to happen in production but in development mode we need a different thing we need this to be working and the reason is because of nextjs hot reload whenever we save a file nextjs will run a hot reload and what that would do is initialize a new Prisma client every time and then you would get some warnings in your terminal that you have too many active Prisma clients so what we do is we add a if Clause if we are not in production in that case we're going to store the database variable inside of global this. Prisma and then when hot reload fires on the next iteration it will check if it has Prisma already initialized in global this and then it's going to use that otherwise if we are running it for the first time it's going to just initialize a single Prisma client the reason Global this the reason we store it in global this is because Global is not affected by hot reload like that uh great so what I want to do now is the following I want to go ahead and I want to go inside of GE ignore right here and go ahead and find environment. loal and below that just add environment or just add it anywhere in this file so just add pure. environment file here like that great and what I'm going to do next is I'm going to go back inside of my terminal and I'm GNA run npx Prisma in it like this there we go and you should get this success message kind of and what that's going to do is it's going to create the Prisma file and also inside of your environment file you can see that it's going to fill it with a fake database URL so you know this is where we have to put our database URL and we also have the Prisma folder where we have a schema Prisma set up for us like that so make sure you have all of those files what we have to do next is we have to obtain an actual database URL for that we're going to be using neon dote which is a completely free uh postgress database and you don't need a credit card for it it's completely free no need to uh do anything here so this is what we're going to do let's go inside of neon do like this and go ahead and find the login button once you're logged in you're going to be prompted uh with a similar query like this to name your project so let's call this outm class or I'm going to call it Al tutorial like that and database name can be exactly the same it doesn't really matter you can choose the region closest to you and click create a project here and in here you're going to get your connection string or you can go ahead and select Prisma here to see exactly what you have to put inside of schema Prisma and what to put inside of the environment file so let's first do the schema. Prisma so I'm going to go ahead and copy this and I'm going to go inside of my Prisma schema. Prisma select everything and paste it here and there we go so we just need a data source DB with postgress SQL and database URL and a direct URL and now we have to add this inside of our environment file so you can click on the little I icon so it's going to show this keys or you can directly click copy here like that then go inside of your environment file and replace this database URL with what you've just copied and there we go we now have a database URL and a direct URL connecting to Neon dote using pogress equal or pogress however you want to call it great so now that we have this you can go ahead and close this and let's go ahead and add a model here so I'm going to write model user for example and give it an ID and inside of here uh let's make it a type of string let's get make it ID and a default value of uh CU ID like that and I'm also going to give it the name of string for example and then what you can do is go inside of the terminal here so just make sure you've saved this model user inside of schema. Prisma and then you can run npx Prisma generate so what this is going to do uh oh you don't have any generators defined so nothing will be generated uh my apologies I think that I forgot a generator yes because I've just just copied this for Prisma uh right so do this add a generator client provider to be Prisma client JS like this so we also need this inside of our schema Prisma my apologies I remove that once I've pasted uh from neon this uh code let's try this again so make sure you have the generator client here and let's try again npx Prisma generate and there we go so now this user model has been successfully generated and we can do now is using this lip folder database we can access the user model for example if I go inside of app layout here so just for fun I'm going to add a user to be8 I'm going to turn this into an asynchronous function I'm going to import the database from at/ Li database and then you can see the out completion of user here so if you're getting an error here that means that you you you didn't do npx Prisma generate successfully so make sure that you don't get any errors right here after you run npx Prisma generate so that's what that command does so make sure you don't have any errors and that you have the autocomplete for find many or anything like that so I'm going to revert this back to how it was and I'm going to remove this import from the database in my layout just as it was before what we have to do now is we have to push our uh collections right here in the neon database because if you click in the databases here uh well basically you can't find anything right so let's go ahead and do this now let's go inside of our terminal again and just like we've run npx Prisma generate we're now going to run npx Prisma database push like this perhaps this already does npx Prisma generate for us I'm not exactly sure but what it should definitely do is synchronize your Prisma schema if you get an error here that it could not reach this database uh that can happen sometimes so just go ahead and run it again and if you ever see an error that your database could not be reached just try whatever command you're doing or just restart your project again uh all right and I think that now we should be able to find this schema so I'm going to refresh here and try and find this I think you can click on tables and there we go we have a user table of course it's completely empty but we have the actual collection with the ID and the name inside of it great so we've successfully connected to POS SQL or pogress uh using Prisma great so what we have to do now is we have to create a proper user model inside of our schema Prisma and we can find the exact model we need from next out themselves so our next step is to go to the next out documentation page now here's what you have to keep in mind there are two out well two next out documentation pages one is called .js which I will put the link in the description for which is the correct uh documentation and there is an all documentation for nextjs and you can see that it's an all documentation because here in the nov bar you're going to have a little Banner which says that we're looking at next out version 4 for the new documentation go tojs dodev so don't be on the one which says next out be on the one which says ejs and you will also have a banner here but it's just going to give you uh well you're basically in the correct page right so what I want to do here is I want to kind of explore this and I want to find my Prisma database adapter and in there I can find my schema so let's see if that is perhaps in the getting started here and I'm going to click let me zoom in so getting started I'm going to click on database providers uh adapters sorry and in here we have a lot of adapters and here is Prisma so go ahead and select Prisma and here's what we have to add we have to add this Prisma adapter so we already have Prisma client we already have Prisma so let's go ahead and out add the out Prisma adapter because we're going to need it not immediately but later so let's just already ensure that we have it so go ahead and run uh whoops mpm install at out SL Prisma adapter like this so just make sure you have this installed because we're going to need it later when we set up next out properly there we go mpm install out Prisma adapter and conf confirm in your package Json that you have in your dependencies out Prisma adapter like that great so let's see what else we have to do so of course we have the actual instructions for the setup but I'm going to skip this for now and I'm going to go immediately and find this uh create the schema create the Prisma schema from scratch so make sure you are on this page right here or you can pause the video and copy from my screen if that's easier so the first thing I want to do is I want to find the user model and and I want to copy it and paste it inside of my Prisma schema so we're not going to be using the exact uh model that they are we're going to modify it a little bit but this is a good starting point so let's replace this user here that we have with whatever they uh provided Us in this documentation so you should have the ID the name which is optional email which is optional and unique email verified which is an optional date time image which is an optional string and two relations one for the account and one for the session and the one thing you can immediately remove is the sessions we're not going to use that we're going to be using we're not going to use the database session for this one so now you want to go ahead and find the model account inside of this documentation and copy the model account like this and what I want to do is paste it below the model user like that and there we go now this error should go away and let's take a look at this model account so you should have the ID the user ID which works as a relation with the user that's what we no longer have these errors here you should have the type the provider the provider account ID refresh token access token expires at token type scope ID token and session State and a unique rule for the combination of provider and provider account ID and you can go ahead and save this file and here's the thing if you take a look further inside of this you can see that we also have the session you can see that we also have the verification token but we not going to be using uh those models we're going to implement our own verification token because this can be kind of misleading because you might think that this can be used for credentials provider but it's actually intended to be used with the email provider which is the direct or magic login link which I'm pretty sure you've probably seen somewhere but honestly it's very easy to implement and uh I don't see it being used that much across the internet perhaps I could be wrong and I just don't think it makes such an interest in tutorial to teach you how to do that instead I'm teaching you how to do it with credential providers so you can actually register with your name email and password and then we're going to create our own model verification token which is going to confirm that uh users's email when they register uh great so we've set up that and now what we have to do is we have to push that inside of our database so that's what we should have next so make sure that your model account exists and it's exactly the same as mine is and make sure that your user exists and it only has a relation with the accounts like this and then go back inside of your terminal here and run npx Prisma generate like this so that's going to add it to your node modules and to your database util and then npx Prisma database push so this is going to push it to Neon dote so let's see if this succeeds or not I believe everything should be just fine uh and yeah it's telling us that we have a unique constraint on the email and it's because we already pushed that old user so if you get this warning you can just ignore them by pressing the Y button like this so just ignore it it doesn't matter if it resets the database because we don't have any records after all there we go and you should get a message your database is now in sync with your Prisma schema like that and let's try it out now so I'm going to refresh this tables here on neon and there we go I I have my account right here and I have my user right here great so we are now finally ready uh to uh create our register form but I believe something here is missing you could you probably notice that we don't have a password filled that's because next out by default does not exactly recommend using the credentials provider but it has full support for credentials provider if that's something that you want they have their own reasons why they don't do credential providers I personally don't like them too much as well but I do understand that it's something that each developer needs to know how to implement so that's why I'm doing this tutorial so in the user model let's go ahead uh and after the image let's add a password which is going to be an optional string as well so why optional well it's going to be optional because if we use oou providers like Google and GitHub well in that case we don't have a password right so we need to allow the adapter which we will later connect to create this user model without requiring a password so every time you add something new to your schema Prisma like we just did with the password field you have to go back inside of your terminal here and do npx Prisma generate and after that you have to run npx Prisma database not P but push like this npx Prisma database push and that should add the password filled uh to your tables collection so if I ref refresh here one more time go inside of the user expand it there we go we have password filled which is a type of text great so now we are actually ready to revisit our actions right here register and in here we're going to take the values which user provided and actually fill that user model with our first record great great job so in order to save the user inside of our database we have to find way to encrypt the password for that I'm going to be using a package called bcrypt so let's go inside of our terminal here and let's do npm install bcrypt like this and by default it doesn't come with types so we have to additionally install its types so let's write npm install DD for Dev dependencies at types SL bcrypt like this so now you should be able to import this in your project and let's just check it out so inside of your package Json in the dependencies you should have bcrypt installed and inside of Dev dependencies you should have types bcrypt like this so let's go ahead and let's import bcrypt from bcrypt like this and now we can use that uh we can use this to encrypt our passwords so let me just make sure that I am running the project so I'm going to run mpm runev here uh and for now I'm just going to refresh the Local Host make sure you are on the register page right here so what we have to do after we confirm that the fields are not invalid we have to go ahead and extract the validated Fields so you can use validated Fields uh. data like this and in here you can get the exact email password and name which we have def in our register schema and which of course the user has to enter so let's get the email let's get get the password and let's get the name and the first thing we're going to do is we're going to Hash the password so con hashed password is going to be a wait bcrypt do password and give it some salt which is going to be 10 in my case if you hover over the hash function here you're going to see different ways of using it so if you want to you can uh generate sold differently and then you can store that in the database as well uh or you can simply pass in the salt rounds like I'm doing right here in a very simple way great so now that we have the hashed password what I want to do is I want to confirm that this email is not taken so let's go ahead and write well first let's go ahead and import our database so import database from at/ Li database which is this little util which we created and then in here we're we're going to write const existing user to be await database. uh user find unique where we have an email matching like that and then we can say if we have an existing user that means this email is already taken so we're going to return an error saying email already in use like this and if that is not true we can continue and create our user so I'm going to write await db. user. create and I'm going to give it a data of name email and for the password field make sure that you pass hash password so this is very important do not accidentally use the password like this make sure you're using the hashed password you never want to store plain text password inside of your database so make sure you're encrypting this first great and what I'm going to Simply write here is I'm going to write a too uh send very verification token email so we're going to do that later for now I'm just going to write a success message user created like this great so let's check this out now so I'm going to refresh this inside of my neon database I don't have any anything inside of my user model here so let's go ahead and give this a name of Antonio let's use a mail example.com and let's go ahead and give it a proper password and once I click create an account here I believe we should successfully connect our database and we should get the user created message right here so inside of my neon uh database here if I refresh I believe in my user there we go I have uh an ID I have a name of uh Antonio I have an email uh I don't have anything for email verified because well we didn't verify the email I don't have an image and you can see that my password is a hash so even if someone breaks into our database there is not much they can do this they can do with this string right here so our passwords are encrypted great perfect so now what we have to confirm is that if I try and do this again so find the email which you've used so for me is mail example.com so let's try this again new user let's use the same email and let's try creating a new account and there we go we say email is already in use perfect so what I want to do now is I want to create a little util for this existing user here by email because we're going to be doing that a lot so for that I want to create a new folder in the root of my application and I'm going to call that data and inside of here go ahead and create a new file user. CS so this is going to be specific user data and let's go ahead and let's import the database from as/ lib database and let's export con get user by Emil email to be an asynchronous function which accepts the email which is a string and then in here let's open H and Cat block inside of the cat here you can just return null and inside of here you can get con user to be await database. user find unique where you have a matching email property like that and simple return the user like this and let's go ahead and copy and paste this and I want to create another useful util here get user by uh ID and instead of email being the prop it's going to be the ID and we're going to be simply using the matching ID of the user so very simple and we're going to use that inside of our out callbacks later where we need more information from the database great so now let's use this inside of our register function here so instead of this it's going to be await get user by email and we're going to pass in the email so let's go ahead and import get user by email using the at data user and the structure get user by email and here's a quick little tip for you some people have reported that bcrypt is causing them errors in the app so if you want you can use an alternative version of bcrypt I'm going to install it and demonstrate it just in case you're having any issues so mpm install bcrypt JS like this and just as in the previous one you also need to install a Dev dependency of bcrypt types sorry of add types SL bcrypt JS and I believe they should work exactly the same so you can import from bcrypt or bcrypt JS and I think it should be exactly the same so let's go ahead and try this if I go in npm run Dev here I'm going to create a new account here just to confirm that everything is still working so new new example com let's go ahead and create an account and there we go user has been created and if I refresh this I should have two users inside of my user model here and there we go you can see how they have uh of course different encryption but the encryption is still fully working great so now that we have configured that what I want to do next is I want to start implementing uh our actual next out setup and then we're going to come back to this to send the verification token email so the reason I don't want to do this immediately even though it's very simple to do that is because uh I want to demonstrate to you how we can first log in and then how we can restrict users which are not which have not verified their their email from logging in because it's one thing for us to disallow that for example in the login function here right so we can just simply check if the field from our Prisma schema called email verified doesn't exist okay just break the function and don't allow the user but keep in mind that this is this function is just a wrapper around next out so if somehow the user finds a way to log in we need to tell next out directly never allow this user to sign in completely right instead redirect them to verify their password to verify their uh email right great great job so far so we're finally ready to add next out inside of our project and for now we're simply going to implement the login functionality the same way we just implemented the register functionality so in order to enable login we have to install next out version 5 inside of our project so head to the ejs documentation here and in the guides section all the way to the bottom you're going to find an upgrade guide to version five so first of all let's install the proper version of next out so if you're watching this into the future perhaps it will not have this sign and it's just going to be next out all that matters is that the version is higher than four meaning minimum five so let's go ahead inside of our terminal here let's shut down the app and let's run npm install next- out like this and after you've run this go ahead and run your project again and confirm in your package Json that you have next out beginning with the version five like this great so now let's go ahead and see what new features we have so this is the one I like the most the universal out previously when you use when you wanted to access the currently logged in user in server component you have to use uh well different kinds of methods right we had get server session we had get session we had without get token use session all of those things now they have all been replaced with a universal app so I think this is a great change in here we also have some breaking changes like the import being deprecated so the next middleware jvt adapters none of this exist anymore and now we finally have the configuration so let's go ahead and do this so in the root of our application create a new file called out. CS like this so a very simple name what I'm going to do is copy this snippet from here and I'm going to paste it inside like that what we have to do now is we have to add the get and the post inside the API for next out and you can see that in here we export this Universal out lib which we can then later use in server components to get the currently logged in user session or get no session at all if we are logged out so let's go ahead and use this get and post to add them to our API routes so in here we have to create an API folder inside of the app folder then an out folder then a catch all next out route and finally route. THS inside so let's go ahead and do that so inside of here I'm going to go ahead and collapse everything go inside of the app folder create a new file new folder called API then another folder called out inside and then another one where you spread next out inside of squared brackets and then route. yes and inside I'm simply going to copy and paste this snippet from here like this and paste it here and what we have to do is change the import to go to the root so at slou like that because our out file should be located in the root of our application where is it there we go .s and this is optional and I'm going to remove it because we are not working on the edge because we are using Prisma which by default doesn't support the edge and then what you can do is go to localhost 3000 SL apiou SL providers and in here uh oh we have an error as you can see missing secret I believe we can also see that inside of our terminal here there we go you can see that the moment I added this uh out file it's saying that we have an error missing secret so you can see that we have this link here which we can click on and open it like this and in here we have instructions on what we have to do so we have to add our secret environment variable so let's go ahead and do that so I'm going to go inside of my environment file and I'm going to add an Al secret and in here you can write whatever you want for development purposes so you can simply write just secret and then if I try and do go to this route again/ API out providers and refresh there we go you can see that it uh noticed that we have a GitHub provider inside of our .ds file right but for production uh it is recommended that you either generate a uh your own secret using op SSL but that is only available on Unix systems like Linux or Mac so you can run this in your terminal if you want or you can simply click here and that's going to generate a random one for you so this is for production right you don't want your out secrets to be this simple but in development it's completely fine and if I refresh it's still working perfect so now that we have this done what I want to do is I want to set up the middleware and in here you have a nice little table showing what has changed from version four to version five if you want if you're interested in that so you can see that get server session with the out options had been replaced with a universal out call in the middleware we no longer have without and middleware we now just have out use session has stayed the same for client components but you can you can see that everything else uses the new out universal call so I really like this change so now let's set up our middleware so inside of the root of our application here create a new file middleware docs and here is an important thing to understand about the middleware so middleware is not next out specific middleware is nextjs specific so please don't misspell the name of this file otherwise it's not going to work and now I'm I'm going to copy this snippet from here and I'm going to paste everything inside of the middleware like this and here's an important thing for you to understand about the middleware so I've seen a lot of misconception about this config matcher right here a lot of people don't understand exactly what it does some people think that this is where you want to put your private routes some people think that this is where you should put your public routes the truth is everything that you put inside of here will not be used to check whether it's public or private private it's simply going to be used to invoke the middleware right so if I go ahead and add for example slout SL login here this is not going to be protected or public this is simply going to invoke this function right here or if I write a log long regular expression uh for a bunch of different things then everything will invoke the middleware right so let's try this out so if I go ahead and add a a console log of request next url. paath name here and I'm going to give it a little uh string here so it's clearer to see and let's make sure that our app is running there we go it's running and if I go inside of my uh out slash login now there we go you can see that it says route out/ login but if I go on register you can see that I don't have have that conso log so the middleware was not invoked but if I go ahead and add SL out/ register here as well then in the terminal when I refresh the register page there we go you can see the route is slout SL register so that's how the middleware works right so it's not uh black and white where you have to put your public routes here or when you have to put your private routes here it is simply a mat for anything you want to invite the middleware and as you can see from the documentation in here in next out we have a regular expression to invoke on every single thing except this specific regular Expressions which we don't want to invoke but in my experience this is not the perfect regular expression there is a better one and you've probably used it a lot of times if you followed my previous tutorials and that is the regular expression from clerk so I'm going to paste the link in the description so you can find this page right here where you can find this matcher which I really like which is perfect for this project the reason I like this mecher so much is because well if you've used clerk U then you probably know that they are really the creme Dela Creme of developer experience and authentication so what I'm trying to do in this tutorial is come as close as possible to using clerk but in next out of course so let's go ahead and copy this matcher from here if you cannot find it in the documentation you can also immediately go to my GitHub and find it there so I'm going to replace my existing matcher with that matcher and now let's go ahead and see what's going to be logged inside of our terminal so I'm going to go ahead and refresh the register page and as you can see the register page is locked if I go to the login page now the login page is locked if I go inside of Slash then the slash is locked if I go inside of of/ API out providers you can see that API out providers is locked so what did we achieve here we achieved that every single route except uh specific next static files and next images are going to invoke the middleware and this is the perfect use case for us the reason I want it like this is because I rather want to manual I want to invoke the middleware everywhere so both on uh authorized routes both both on routes used to log in both on private routes and also on public routes and then in the Middle where I'm going to decide what I want to do with those routes right so you can see how we can easily get the is loged in status using request. out and we can turn that into a Boolean by adding two exclamation points here so I'm going to add a new console log is logged in to be is logged in like this so let's go ahead and go inside of our terminal now and let's refresh the landing page and there we go you can see that the route is Slash and is logged in is false if I go to out you can see that the route is SL out SL login and is logged in is false so I'm going to use the combination of the path name and the logged in status to decide what to do with the route that the currently logged in user is on and this is another structure that I plan to use for this app I want my entire app to be protected by default the reason I want that because I feel that most applications work like that right so you are most likely going to have fewer public routes than private routes so it doesn't make sense that we have to write every single private route instead let's consider the entire application to be fully protected and in need to be authorized to access it and then we're going to separate just a couple of routes like a landing page the documentation something like that to be able to be accessed uh for non-authorized users so that's what we achieved with this middleware here and uh well you just saw how easy it is to get some tokens from here all right so I hope that kind of cleared up what the middleware is used for so it's not used for explicitly private routes or public routes it can be used for anything you want to invoke the middleware if you want wanted to you can of course manually write every single route that we have inside but it's better to use a regular expression for this uh specifically because of this uh app folder API out and in here we have a catch all meaning that we don't exactly know uh which future routes or sub routes could be inside so by using a regular expression we made sure that we will invoke the Middle where every single time any of those routes is being touched what I want to do now is I want to go back to the upgrade guide here and I want to scroll a bit down and in here you're going to find something called Edge compatibility so as you know we are using Prisma which by default does not work on the edge which means that we are not going to be able to use a lot of callbacks and events inside of the .ts files uh which we would usually be able to if our database supported the edge but thankfully there is a solution for that and that is to separate out config and then use the config in the middleware so the middleware is the problematic part because middleware works on the edge so we cannot use Prisma here so what we have to do is we have to create a file out. config docs so let's go ahead and do that so I'm going to create uh on the same level as Out Create a new file out. config CS like this and let's go ahead and copy and paste this snippet here like this so we get the provider we get the type next out config and we export default an object with the providers which satisfies the next out config what we have to do next is go back inside of out. Cs file and now we can safely add the Prisma adapter which does not work on the edge so that's why we have to separate those two files so we're going to use this file instead to trigger the middleware and not this one which will use the Prisma adapter so let's go ahead and change what we need we no longer need the GitHub import and we no longer need the providers instead we're going to import out config from do/ out config or if you want to be consistent you can use the add sign and let's simply spread the out config like this there we go but we still have to add our Prisma adapter so let's go ahead and add the Prisma adapter from out Prisma adapter make sure that you have this package installed so if you don't you can simply go into the termin Al uh and run uh mpm install out Prisma adapter like this but I believe that if I go ahead and install this we already have this I think we did it in the previous module so you can of course always confirm inside of your package.json uh it should be first out Prisma adapter like this so we have the Prisma adapter and we also need our database util from /li database or at/ Li database so so let's go ahead and add the adapter to be Prisma adapter and pass in the database and we also have to change the session to use a strategy jvt we cannot use the database session strategy that's why I didn't add the session model inside of our Prisma schema because with Prisma we cannot use the database session because it doesn't work on the edge we have to use jvt strategy here and now that we modified this we also have to modify our middleware here so it doesn't use this out where we clearly use the non-edge supported Prisma adapter so instead we have to use the out config file to extract the out middleware from it and we can do that very simply by following the instructions here so inside of the middleware we have to import out config from do/ out config and we have to import next out from next out and then we can destructure the out from next out and out config let's go ahead and do that we no longer need this import instead we need the out config from /ou config or at out config and we need next out from next out and then what we can do is write const next out and pass in the out config and then inside simply get the out and there we go everything should now work exactly as it worked before so if I go ahead and open my terminal here and if I do let me just close this one so make sure you have npm runev running if I refresh there we go ralth is SL out/ login and is logged in is currently false because we are not logged in perfect so everything seems to still be working but what we can do now is we can of course uh do some callbacks I'm going to talk about callbacks later when we actually start you know implementing them but callbacks are extremely useful when you want something to trigger uh specifically on some next out actions like sign in authorized sign out redirect things like that right but we're going to explore that a bit later what I want to do now is I want to go ahead and I want to attempt to use this out. CS file specifically this out constant uh export to see if I can get the currently logged in session obviously we are not logged in so I think I already know what that's going to look like but let's just try for fun so inside of the app folder I'm going to create a route group inside of parenthesis called protected and then inside I'm going to create a new folder called settings so that's going to be our protected route in the future for now let's just give it a page. vsx here and let's go ahead and Export the settings page and let's write a div settings page page so you can find this by going to localhost 3000 SL settings directly no need to go for the protected I just want to have an organizational folder where I'm going to keep all of my protected routes so I know visually that they should be protected so now go to Local Host 3000 SL settings here and you should just see the text which says settings page like this so now what I want to do is I want to turn this into an asynchronous server component and I want want to import out from at slou and then what we can do is get the session by using a wait out and to render it here I'm simply going to use json. stringify inside of curly brackets so json. stringify and pass in the session like that and there we go you can see that the current session is null like this exactly as it should be perfect so let's go ahead and do the following if if the user is logged out I don't want them to be able to access this settings route so here's what I want to do I want to go ahead and I want to create a new file in the root of my application called routes. CS so on the same level as out middleware completely out of outside of any folder that we have so far and inside of here let's go ahead and do the following let's export con public routes so in here we're going to write all the routes which we will allow logged out users to visit so obviously that's going to be the landing page for now like this if you want to you can write a little uh JS document here let me just uh find how we write that like this so you can write an array of routes that are accessible to the public like that these routes do not require authentication and you can give it a type of strings so we're just practicing JS docit and now let's go ahead and do this let's export con out routes so these are the routes which will be used for authentication so for now that is slout SL login and slout SL register so let's copy and paste the JS document here if you want to you obviously don't have to so this is an array of routes that are used for our authentication and let's go ahead and write these routes will redirect logged in users to slash settings like this uh and let's go ahead now and let's write another one here export const API out prefix that's simply going to be a string SL API slou so that's going to represent this file with which we created here API out so inside of our middleware it's important we're not going to add that manually to public routes but it's going to be a special case so that we never block this API route it's important that this is always allowed to logged in or logged out users they need to be able to access SL API slout so we can add a JS document for that as well to explain it briefly so this is very simply going to be the prefix for API authentication routes like that and I'm going to write in here routes that start with this prefix are used for API for API authentication purposes and the type is just a string without an array like that and to make our code a bit better let's also add export con default login redirect so this is going to be the place where we're going to redirect whenever the user is logged in unless specified differently so let's add a little JS DOC for this the default redirect path after logging in and the type for that is a simple string like that there we go so now we have defined our first routes Here and Now what we can do is we can go back inside of our middleware CS here and let remove everything in side and instead let's go ahead and let's import everything we need from our routes so import from at/ routes we need the default login redirect we need API out prefix we need out routes and we need public routes like this and then in here in the Middle where I'm going to go ahead and destructure the next URL so it's easier to access I'm going to check if we are currently logged in by using a Boolean of request. out and then I'm going to Define if we are on out route so uh actually first let's do is API out route so const is API out rout so next url. PATH name do starts with API out prefix like this let me try and expand this a bit more and you can see that because of our JS doc we can clearly see what this means the prefix for a API authentication routes these are routes that start with this prefix and they are used for API authentication purposes so we always always want to allow this routes that's why I want to have them in a special constant so whenever the middle work hits any of those routes which are the following routes for example SL API out providers there is no reason for us to protect this obviously next out needs it to work properly right so make sure that you don't accidentally protect those routes so always confirm that your API out prefix is correct right here great now let's go ahead and check if we are on a public route so const is public route that's going to be next that's going to be sorry public routes. includes uh next url. paath name so if the next url. paath name is any of the following so you can see that public routes is an array of routes which are accessible to the public these routes do not require Authentication so this is how we're going to know if the user is trying to access a route which is completely public and we are always going to allow that and lastly let's add con is out route so that's going to be out routes. includes next url. PATH name like this so if it is out route that is an array of routes which are used for authentication these routes will redirect logged in users to slash settings like that so basically if the user is already logged in and they try to access the login screen we're not going to allow that we're going to redirect them back to the settings page but we're going to do the opposite if the user is logged out if they are logged out and they try to access the settings page we're going to redirect them to the out login page so you can see how powerful the middle work can be when you allow it to be invoked on every single route that you can imagine so now let's write this logic so first thing we obviously have to allow is if is API outout we don't even have to check if we logged in or not in here simply return now meaning do not do any action regarding this and you can go ahead and try this again by going into localhost 3000 API out providers and this should still work just fine now what I want to do is check if we are currently uh on an out route so let's go ahead and write if we are on an out route is out route and then by default we're always going to allow people to visit the outright right but before we do that let's check if we are logged in so if is logged in in that case what we're going to do is return response redirect new URL and in here we're going to use the default login redirect so the reason I want to put that in a constant is so you can easily change it later if you change your mind and don't want to redirect user to the settings if you want the dashboard to be the main route you can easily do that here and we're carefully going to use that in all the correct places and whenever you use the redirect in the middleware and the new URL Constructor you also have to pass next URL as the last argument here so inside of the new URL Constructor make sure that you pass the next URL so it doesn't matter if you manually wrote you know/ settings like this you would still need to pass next URL and the reason need to do that is so it creates an absolute URL because this is not an absolute URL but when you combine it with a second parameter which is next URL inside of this then that will create it into uh Local Host 3000 settings which is what we need so you can use that and I'm going to bring this back to use the default login redirect here like this so just by adding this I believe nothing should be changed yet so if I go back to my homepage here and if if I click sign in there we go I can still visit the out route why can I visit it because I am not logged in so I'm not getting redirected to the settings page because I'm genuinely not logged in and I just want to log in first and then uh also the order of this if Clauses matters so make sure that you uh do it in this exact order so first allow every single API route and then go ahead and check the out routes so it matters because while the out routes are technically public routes remember we did not include them here right so we have to check them first before we check the public routes manually otherwise you're going to be left in an infinite redirect Lo so when you added this make sure you've confirmed that you can go to Local Host 3000 API out/ providers then when you added this make sure that you can visit your out page right here this is how you're going to help yourself if you have any errors if you can see the exact thing that I'm seeing everything is going fine and now let's do the following if we are not logged in and if we are not on a public route in that case we are going to return response redirect new URL slou slash login and pass in next URL as the second argument and then outside of any if Clauses by default we're going to allow every other route so this is how we're going to use our middleware as you can see we're going to invoke it on every single client and API route but on specific routes which we Define inside of our file here like out login register or a slash page in that case we're going to go ahead and do some different Behavior right so you can see that we return null here which basically means allow this don't do anything if this happens so if the user is not on a public route uh is on a public route we're just going to fall back to this meaning that there's nothing we have to do here right it's completely fine but otherwise it's going to start checking for logged in if it's not logged in and it's not on a public route we will redirect the user to the login page perfect so let's try this out now here's what should happen you should see you should be able to see outl normally you should be able to see out register normally you should be able to go to/ apiou providers completely fine but here is a route that you should not be able to visit Local Host 3000 SL settings if I go here I am immediately redirected back to the login page so make sure that inside of your routes you didn't write the settings page in the public routes but here's what happens if I add it to the public routes so if I add settings to my public routes now I can go ahead and visit the settings page there we go I can now visit the settings page so I believe this is quite a useful middleware which we' created just remove the settings from the public routes and we have quite easy controls outside of the middleware itself because I feel like it's too cluttered to keep it all together inside of here I believe it's complex enough to have this great so I really really like this middleware and I think we've pretty much mastered the middleware now right so I believe you know what it's time for it's time for us to go back inside of out. THS right here and to actually add uh well not here my apologies the config and to actually remove the GitHub provider for now and instead add the credentials provider which will finally allow us to call this login function and once we log in we will be immediately redirected to the settings page and once we log out from the settings page we're going to get redirected back to here first things first let's remove the GitHub provider we don't need it like this instead let's go ahead and let's import the credentials from uh next slout SL providers SL credentials like this and let's move this to the top right here and now I want to import the login schema from / schemas so we already use the login schema inside of our login form and inside of our uh login server action here right but I'm going to use it one more time in the credentials provider because remember uh in next out just because we have this server action for login doesn't mean that every user will always use that there are definitely some users which can bypass our server action and not use this login screen at all right they can manually uh send information to the app API out if they want to so that's why we also have to do the login schema check here in the providers so in the providers go ahead and add the credentials open an object inside of here and let's write an asynchronous function authorize like that and it's going to give us the credentials in the props so inside of here I want to go ahead and validate the fields again so const validated fields are going to be login schema do save pars credentials like this and then if validated fields are a success in that case let's go ahead and let's destructure the email and the password from validated fields. dat like that and then what I want to do is I want to check if that the email which was passed in the credentials provider is actually connected to any you know user in my database so I know that I can you know check the password so const user is going to be await get user by email from data user I'm going to change this to the add sign and pass in the email and then I'm going to check if there is no user or if there is a user but there is no user. password in that case I'm just going to break this F function so how can it happen that the user has no password well it can happen if they logged in using Google or GitHub so if they create an account using Google and GitHub and then they come around and try to use the credentials provider we're not going to allow that because they don't have a password and in order for credential provider to work we need to compare the hashed password inside of our database with the password that the user just passed so if this passes that means okay this user registered using their name email and password so what I have to do next is check if the passwords match like this so let's write a wait and we have to import bcrypt here so let's import bcrypt from bcrypt JS or bcrypt I found in my development process that bcrypt JS has less errors because I actually had an error when I used bcrypt but you can try it out if you want to but I believe that I also use B script JS uh inside of my register action so just confirm that you use it in the same place so in the register I use bcrypt JS and in the out config I use bcrypt JS and just confirm that in your package Json you have bcrypt installed uh I mean bcrypt JS installed and also the types for bcrypt JS in Dev dependencies all right so now that we have that we can do is await decrypt.co compare and we're going to compare first the password which the user just entered and then the hash from our database using user. password because remember that is a hash so this way we are confirming that they an they they entered the correct password without us knowing what the actual password is because we're just comparing the hash we have no idea what is the actual password of the user perfect and if passwords match return the user like that and then go outside of this if function here and return null by default there we go so what we have to do now is we have to go inside of the out. Cs and the same way we can export sign in we can also export uh sorry the same way we can export out we can export sign in and sign out and this can be used in server component components or server actions that cool yes so now let's go ahead and do the following let's go inside of our actions and let's go inside of login. THS so this is the place where we have to uh what we have to call that login function so first thing I want to do is remove this return here and instead let's use the validated fields. dat and let's destructure the email and the password like that and then let's go ahead uh and let's attempt to log in so I'm going to go ahead and import sign in using at slou so make sure that you added uh an export for that here and then I'm going to wrap that inside of a try and catch block so I'm just going to uh to do this and all we have to do in the tri block is wait sign in give it the type of sign in which in our case is credentials here and go ahead and give it an email and a password and let's go ahead and write redirect to to be default login redirect from out routes from at/ routes like this so this will be the settings page like this so later what we're going to do is we're going to have a call back URL or that so that's why I'm manually defining this here so we don't have this yet but later when we implement the Callback functionality we're going to add that here so that's why we need this field usually I believe this is still going to work if you just don't add a redirect to but if you have a redirect to and the call back your L is null then it will not redirect so it's just going to be weird right so that's why I'm adding redirect to default login redirect and it's explicit so I like it it's like telling me all right when you log in this is where you will be redirected too so I don't have to think you know okay I have to think about my middleware now and I have to think okay so once they get logged in this is what will fire and then that will redirect me to here right technically I just know that because we just wrote it but in here it's more explicit so I like it this way and then in here we have to check if error is the instance of out error is it out error uh out error I'm just not sure where we can import this so I think that we can import out error from next out there we go so import out error from next out so if the error is an instance of out error we can open a switch case on the error. type here and if the case is uh let me just see is it cas yeah without the column so if the case is uh let's see why is it not autocomp completing there we go so you can see we have a bunch of different cases that you can cover but I'm just going to focus on the credential sign in here so if this is the case I'm going to return an object with an error invalid credentials like this let's give it a default case to return an error of something went wrong like that and what's important when using sign in inside of server actions is that inside of the catch function at the end of this if Clause you also throw the error back otherwise it will not redirect you so make sure you add throw error they do this also in the official nextjs uh course so I'm not sure if this is a bug or a behavior but yeah you have to throw an error otherwise it will will not redirect you to the login redirect which in our case is the settings page so first I want to test the invalid credentials one out so I believe that this is technically already working but let's just try it out so I'm going to write a random email here and a random password and now I believe I should get an error invalid credentials there we go it says invalid credentials so if you remember your email and your password you can enter it I believe I have an email new mail.com or new example.com and my password was 1 2 3 4 5 6 and I think there we go you can see that this redirects me to the settings page so it means that I'm officially logged in and you can see my session here because remember in the SE in the settings page if I go inside of app protected settings in here you can see that we evade out and Json stringify the session meaning that I am logged in and now if I go and man if I go and try and go to the landing page I can still see this because this is a public route but if I click sign in you can see that I'm redirected to the settings page that's because of that part inside of our middleware file so inside of where is it middleware right here if it is the out rout and if we are logged in we redirect the user back to the settings like that so we handled so many cases with our middleware I really really like how we did this what we have to do now is we have to add a log out button so that you we can actually clear our cach and stuff right so inside that's going to be very simple so make sure that inside of your out. CS you added an export for sign out and then inside of your uh app folder protected settings page. CSX go ahead and add a form here and add a little button which will just say sign out give it a type of submit and give this an action to Be an Arrow function make sure it's an asynchronous arrow function add and US server here and simply call await sign out from at slou as simple as this so this is how you can use the sign out function in server components yes you can also use that in of client components but not by importing from here so this is exclusively for Server components server actions and stuff and basically all side side server things but don't worry later I'm going to show you how you can also sign out and sign in using completely client components so no need for Server actions at all uh great so I believe that if I click sign out here I should be redirected to the out page and there we go and if I try and go manually to SL settings again I'm redirected back to the settings page great we officially implemented login let's go ahead and create a new account here so I'm going to call this test testmail decom 1 2 3 4 5 6 create an account great let's go ahead in here let's use test mail.com 1 2 3 4 5 6 7 that should give me invalid credentials and if I remove one that should log me back in there we go you can see my exact information here perfect so what I want us to learn next is how to extend this session object with a couple of more stuff right because name and email is not enough we also need the ID we also need the role we need a bunch of more things inside of our session and thankfully next out has callbacks which can do that so that's what we're going to learn in the next module this was a very long chapter but I hoped it cleared up some doubts that you had in the middle middleware and how all of that stuff works so great great job and see you in the next chapter so what I want to do now is find a way so that we can extend this session of the currently logged in user so let's go ahead and just confirm one more time that this is working so I will sign out I will refresh I will try to go to/ settings manually I'm redirected back here and if I go ahead and add new example.com com 1 2 3 4 5 6 I think that's my login and password I might be uh doing something wrong no this is the correct one great so we can go ahead and explore the following items so inside of our out. CS file here we don't have a lot of things set up besides the adapter and the session but in here we can do something called callbacks so above the adapter go ahead and add the Callback like this it's going to be an object and add a comma at the end and in here we can Define different types of callbacks so we can visit the OJs documentation to learn a bit more about callbacks so this is located uh in the guides Basics callbacks right here if you want to read some yourself so as you can see here callbacks are asynchronous functions which we can use to control what happens when a specific action is performed and here are a couple of them so we have this sign in back which can be used to decide whether we are going to allow the user to sign in or not so even if they successfully create an account we can still completely block them from ever signing up inside of our account and this function is way more powerful than doing that logic in for example our actions log in right so in here I can technically do the same thing if email is some user I can block them from signing in right but if you write that inside of a call back then it doesn't matter what method someone is using to log in whether they use an API endpoint or our server action next out is never going to allow them to log in if we write that inside of our call back here so that's one example next we have the redirect so we are not going to mess around with the redirect it works fine from default and I believe you can read more about the redirect call back right here so it's called anytime the user is redirected to a call back URL for example on sign in or on sign out by default only URLs on the same URL on the site are allowed and we can use the redirect callback if we ever want to customize that behavior so this is how it looks on default right so if we ever want to modify it this is where we can do that in our case this works perfectly fine and I believe in most applications as well so we're not going to play around with the uh redirect callback too much and now we have the two important callbacks jvt and the session call back so the session callback is actually what returns our session which if you remember inside of our app folder when we created protected settings page we use that right here so that's the session that comes from this call back session this return session is what we get right here and as I've just mentioned we have to find a way to extend this session because this is not enough information to us for us to work with but before we can extend the session we have to extend the JT which returns our token because the session uses the token uh to actually generate the session so let's go ahead and explore that a bit so I'm going to go ahead inside of my out. CS file and first thing I'm going to do is I'm going to try and modify my jvt callback so for that you can write asynchronous jvt and go ahead and extract the token from the props here and in order to get rid of the error you always have to return the token at the end like this and then what I want to do is conso log the token like that and you can wrap it inside of an object if if you want to find it easier in the terminal log so I'm going to go ahead and prepare my terminal here and make sure that you are logged in right and you can see how when I refresh here this is my token so the name is new the email is new at example.com my picture is null and this is interesting this is my sub which is actually my user ID so this is exactly what I can find inside of my database so you can either go to Neon DB and look at your tables or here's another way you can look at your database if you're using Prisma you can run npx Prisma studio and that's going to launch it at Local Host 55555 so in here if I go inside of the user model here I'm going to go ahead and see a couple of users that I've created and there we go take a look at this ID clq 81 and if I take a look at inside of my other terminal here there we go clq 081 right here so this is a matching ID of our user great so we already have the ID inside of here and here are some other information inside but this is not enough this is not everything that we need but token is not the only thing you can extend from this jvt session right here if you hover over here you're going to see everything that you can extend you can extend token the user account profile trigger e new user and session so you can go ahead and play around for example uh let's go ahead and log the user let's see what that's going to look like so if I go inside of my terminal here yeah and I don't know exactly how the user is filled I believe that this might only be not undefined the moment you log in right so I don't think that this user field is too reliable to use and I think the same thing is true for the profile for example I don't think we even have profile for this one there we go you can see how it's undefined right but if I bring it back to the Token you can see the token is much more reliable when we have a logged in user so for that case uh we're going to use the sub from the token to actually load our user from the database inside of this callback and then we're going to pass more information to the final session right so first we have to go ahead uh and use this token specifically we have to use token. sub and pass that to the session callback so for now let's leave this as it is right actually you can leave the console log so that you you can follow the flow of information going on so this is the Callback that we have now let's go ahead and add another one so asynchronous session which can extract the user besides the user it can also extract sorry not the user to token and session that's those are the props it has and the same as in the token you always have to return the session for this to work and inside of here we can conso log the token but I'm going to write it as session token so we know the difference all right this is the session token so let's go ahead and look at our terminal here and there we go you can see that now I have the session token which is identical to the Token from our call back below so here's what we can do now if inside of this token I decide to do this token. custom field is equal test like this and if I go inside of my terminal there we go you can see that that is now passed inside of session token right so it's both available in the original token this is the token callback but it's also available in the session token so this is my custom fi test and then what I can do so let's do some uh another thing here so I'm going to write session token to be token and I'm going to write session well to just the session right so now we can keep track of both of those there we go so now I have the session that user is name email image null right here's what I'm going to do I'm going to go ahead and I'm going to write uh session. user Dot and let's write custom field again to be uh well we can actually try transfer it from here right so we can now use this token token. custom field like this and let's just go ahead and write if session. user just so we don't have the error accidentally like this and now I believe if I refresh here there we go on the settings page you can see how now I have name email image and here is my custom field fully working inside of my server component so I think this already gives you an idea of how we can transfer the ID from the token inside of this user session right so if we want to of course of course you can always write something you want here so it doesn't matter you don't even have to use the token to extend the session if you want to you can use it completely like this you can see how now the custom field is anything but here's what I want to do what we want to achieve is we want to get the ID for for the current user which we've just established that inside of the token or session token is sub so let's go ahead and do this I'm going to remove this conso log I'm going to remove this token so I'm just going to return the token in the jvt Callback and then inside of here what I'm going to do is I'm going to write if we have token. sub and if we have session. user in that case session. user. is going to be token. sub like this so as easy as that and let's take a look now there we go we officially have the ID inside of our session so now every single place where we use the session be that a server component or a client component we can always have access to the ID of our user but this was quite easy right because we already had had the ID inside of token here but what about a completely custom field right what if we want to add a new field inside of our schema for example well we actually do need some new Fields so let's go ahead and do that so I'm going to go inside of schema pris Prisma schema. Prisma right here go inside of the user here and after the password uh let's go ahead and let's add a role for our user and let's make this a type of user role which we don't have we're going to create it in a second and let's give it a default value of user like that so in here above I'm going to write enum user Ro and I'm going to give it a type of admin or a type of user like this there we go so now we have a Anum of user roles which are a available for a user model so make sure that you save this file give it a default value of user and now what we have to do well first I recommend that you shut down your app completely and then run npx Prisma generate so this will add it inside of our uh node modules and I think it's best that we clear up our entire database uh a because I want to teach you how to do that and B because I don't want to have any old fields which don't have the user rle so before we do that let's actually do this let's do mpm run Dev and let's just sign out since we're going to remove some users I think it's better that we don't mess with the cookies so let's go ahead and sign out uh of course I believe this isn't a problem for next out I'm pretty sure they can handle deleted users but just for development I don't want you to have any problems while you're doing this so make sure that you are signed out make sure that you've updated your schema Prisma and now let's run npx Prisma migrate reset so what this is going to do is going to reset the entire database so it's going to give you a question to confirm that so all data will be lost of course only do this in development don't do this in production and now that the database reset was successful we have to run npx Prisma database push so every time that you reset your database you have to run npx Prisma database push and after this has been done let's go ahead and do mpm runev like this and let's go ahead and refresh the login page here and if you want to you can also either keep open the neon database or npx Prisma studio so one of the two just so you have an overview of your application so my users are completely empty as you can see here so if I go back here I will not be able to log in because I don't have any account so I'm going to create a test account here with the password 1 2 3 4 5 6 I'm going to create this account and this should add a new user inside of my database there we go we have a new user with an encrypted password and there we go we have a default role for our user and you can see how it has an enum so that I can change it to only one of the two here and now if I go ahead and log in with this user so test at example.com 1 2 3 4 5 6 you're going to see uh that I have I'm logged in with this user right here great so what my goal is now is to extend the session so that I can actually have access to this role user right here so how can I do that well we can do that quite easily we have to go back inside of our out file right here and we have to focus on the token session so we first have to pass this to the Token the reason I want to pass that to the Token because we can get access to the Token inside of our middleware from the request right here and then it's going to be useful for us to know whether someone is an ad admin or not inside of the middleware because then we can write something like is admin route and then we're going to write the same logic if is admin route and if you are not an admin redirect the user back so we can create role based access right Ro based Access Control using the middleware and the token extension so here's what I want to do I want to go ahead and I want to import get user by ID from data user so just make sure that you have get user by ID it's very simple it's very similar to our get user by email of course you can use the get user by email as well but keep in mind that that's going to be a very expensive query because ID is a primary key so obviously the query is going to be much faster for that so now inside of this token here uh what I want to do is I want to go ahead and fetch my user so I'm going to write the following first if I don't have token. sub that means that I'm logged out so I'm just going to return the token right no need to do anything here then I'm going to go ahead and write con existing user to be await get user by ID to be token. sub then I'm going to write if there is no existing user I'm going to go ahead and return the token again and finally we can go ahead and assign the RO to the Token so token. roll is going to be existing user. roll like this and let's go ahead and conso log the token in inside of our session now so I'm going to write session token to be token here and if I go inside of my terminal here inside of my uh original mpm runev there we go you can see that my session token now has a role of user great so what I can do now is the following I can do if token. roll and session. user session. user. roll is going to be token. roll and for now now just ignore this typescript error but let's take a look at our app now if I extend this there we go after my ID you can see that I can find a role of user inside of my session so that's how we can extend the session inside of next out it's actually not that complicated you just have to know the flow so first it starts with the token right in the token we already have the ID which is stored in the sub field uh and then what we have to do if we want to get more information uh is get the user from our database apparently you can also use the extracts from user and profile but honestly they are always undefined for me so I'm not exactly sure how we are supposed to use them uh if I learn of course I'll I'll make a video about that but for now I completely rely on something like this right and this is also why we had to separate our out and our out config because in these callbacks we're using Prisma which is not working on the edge so if we had callbacks which were defined in out config then that will be going through the middleware and then it will break the app because it's not supported on the edge but I believe that inside of out config we can freely use Prisma inside of providers like credentials because this doesn't run on the edge uh this is simply run once the user tries to sign in so I think that's why this is working completely fine here great so now that we know how to extend the role let's go ahead and explore how to modify the typescript or the types for the session and for the token so in order to add a typescript to this user uh inside of our session there actually is a guide for it so let me go ahead and expand the screen so you can find that so it is in getting started typescript session right here and you can scroll down here to the adapters and in here you're going to have mod module argumentation right here and they're going to teach you how to extend the existing session user and add a specific field that you want but here's the thing um this actually does not work for me but we're going to try it out and then I'm going to show you a solution that I use which works for me but still I'm going to give it another shot maybe I missed something so they are doing this inside of out. THS so we're going to try that as well we're going to write our declaration here at the top and we're going to try to fix this error of our role not existing in this user field because by default it doesn't exist here so let's go ahead and do the following so let's add this import from next out importing the next out and the type default session uh let's go ahead and try that out so we already have this actually so we can just add a comma and import default session like that and then we have to go ahead and declare a module out core like this so let's go ahead and declare this module so I'm going to do that here I'm going to close this then we have to create an interface session we have to get the user and then we have to extend it before we write anything inside using the default session and specifically get the user like this and then this is where we would add our role for example to be admin or guest or sorry user right but as you can see it's clearly not working for me so even if I add it as a string or something thing it's not working right so it simply does not exist on type user no matter how many times I decare this module uh this is not working for me so even if I reload my window uh there we go it's still not working so at first I thought okay maybe it's because I'm declaring this inside of this file so let's try the alternative thing let's try this I'm going to close this and I'm going to create a new file in the root of my application next- out. d DS maybe I have to declare it here for example so I'm going to copy this here and I'm going to paste it inside of next out DTS right here and in here let's import next out uh and let's import type default session from next out and I thought okay maybe that will work so if I remove it from here and if I remove this import now but as you can clearly see it's still not working for me so I don't know if this is maybe a part of the migration process or maybe they missed something but this is simply in no way working for me so this is what I'm going to do next I'm going to do the following instead of extending uh our core I'm going to be uh extending next out so this is what I'm going to do now first I'm going to write our extended user so export type extended user is going to be default session user and in here I'm going to go ahead and write rle to be admin or user like this and then inside of here uh I'm going to write uh session user to simply be extended user like this and I'm going to change this declare module to go directly to next- like this so next now looks like it's still not working but if I go ahead and reload this I think that maybe then it will work and okay as you can see now it can recognize it but now we have a problem that uh the token. row doesn't match what we just defined inside of here to be admin or user right so uh what you can do is you can kind of explore even further how you can modify the token but I really didn't manage to do that especially in the next out version five I could do it in the old versions but it's no longer working for new versions so what you can simply do is as admin or uh user for example and there we go now you can see that it's working and you can see that user. roll is the correct one obviously it's not a really clean solution right but I think it works good enough um but if you want we can try an end the token as well so they obviously have instructions for how to extend the token but I believe it's still not going to work but let's try it out so I'm going to go and remove this as admin user right so let's keep this in an error and let's attempt to resolve this so we have to import jvt from alcore jvt and we have to declare the module alcore jvt like this and in here I should just go ahead and add a row go to be optional and added to be as admin or as user like this so now if I refresh this for example so I'm pressing command shift and P to open this little command here and I do reload window it's the same thing as shutting down your Visual Studio code uh and bringing it back up but it's faster as you can see this is not working for me token. roll is just an empty object for me so I don't really know perhaps we can try TR maybe extending next out/ jvt maybe that will be better and maybe we can import uh jvt from next out jvt does not have the jvt alas it does token. roll no if I reload my window I think it's still not working yeah you can see that no matter what I do this used to work in the previous versions but now it's no longer working but you know at least we know know how to extend the session of course this might change in the future they might fix this so that's why I want to show you this guide where they have clearly defined instructions on how to do this right but at least you know these are just types right I know it sounds weird just types but yeah you can technically if you exactly know what you're getting here you can write stuff like as you know uh you can actually import user role from Prisma client directly so user R from Prisma client like this and that's the equivalent of admin or user right so you can use that here but I actually don't recommend importing that here because I think you're going to lose your AO import for the user role so you can try it like user rle from Prisma client and I believe that if I like remove this here maybe I'm wrong maybe it doesn't work maybe I just made it up so I'm just going to write as string for now I'm going to refresh my window and I think if I try to import user role oh it's working okay then maybe you can add it there as well yeah do that replace the admin and user with user role from Prisma client my apologies I it looks like in my development process I got some bugs doing that but looks like that was just in my uh session so we can now import user R from Prisma client in the out. Cs file and we can use the token role to be expected as user R and because we extended the session user with the extended user which has a role property of user role there absolutely no errors inside of our application here and now we can freely uh well nothing has changed here right we were just working with the types now so it's not really important from the functionality of the project but it does make our development experience much better now perfect and if I go ahead and go inside of my uh inside of my app folder protected settings page. vsx right here uh let me just try and do session. user user and I think that you can see how it it gives you the types of user and their role so I can safely have an autocom complete for the role here and an autocomplete for the ID here right so that's what's important for our development experience that's why we care about typescript uh working because by extending this uh it's one thing to just have it accessible and visible here but it's another thing to have type safety so that we know that we are working with that information also one more thing in previous versions user. ID was not defined now it seems to always exist so usually you had to do the same thing in the extended user you also had to add an ID to be a type of string but now it looks like you don't have to do that anymore but if you for any reason have an error it's just as easy as adding it here so id. string right and whatever other fields in the future you might have right so if you can add a complete custom field here and if you go ahead and write session. user dot there we go you have the custom field autocomplete and you can assign anything you want here for example if I go ahead and visit my code now you you should see the custom field to be anything here there we go so I hope you kind of learned how we can manipulate callbacks in jvt and session now so just remove that assignment of a custom field and go back instead of next out and remove the custom field for the ex from the extended a user we were just doing that to practice U great and here's another thing I quickly want to show you while we while we are already here so I'm going to go ahead and sign out now and if I go inside of my Prisma Studio you will notice that I have a field email verified to be null so here's what I'm going to do I'm going to go ahead and I'm going to attempt to block myself from signing in so let's go to the top here above the session and let's write asynchronous sign in and in here we can destructure the user and by default let's return true so we allow the users to sign in and in here uh let's go ahead and see what this user is made of so uh I'm going to write F database or actually let's call it existing user to be await get user by ID to be user. ID like this and then I'm going to write if there is no existing user or if there is no existing user. email verified in that case return false so this way if the logged in user is not inside of our database for any reason if that might happen or if we don't have verified email we are not going to allow the user to log in so let's try that out so while by looking in my database if I try to log in with this user which doesn't have their email verified it should not be allowed to log in so if I try test at example.com 1 2 1 2 3 4 5 6 right here uh I should not be able to sign in let's take a look and there we go something went wrong perfect so we just finished that of course I'm going to remove this for now we're not going to need it we're we're going to come back to this sign in I just feel like it's easier for us to work with uh when we are allowed to sign in so we can fully see our active session uh and everything regarding that uh great great great so I think we did a good job uh uh going over all the important aspects of callbacks I hope you learned what they do and what they are used for uh and what we're going to do next is we're going to go ahead and enable GitHub and Google sign in and then we're going to go ahead and create some email verification great great job so now let's go ahead and let's set up our oal providers Google and GitHub so if you're logged in go ahead head and log out so you can see the login screen right here and the first thing I want you to go through is to localhost 3000 API SL out/ providers and right now the only thing that you should see is the credential providers because that's the only thing that we have inside of our out config right here we have the providers and the only thing we use is credentials as you can clearly see right here so what we're going to do now is we're going to go ahead and import GitHub from next out/ providers GitHub and we're going to go ahead and use this and add it just above the providers here so once I save this and refresh this page there we go now I have my GitHub provider here and we can do the same thing for Google so let's go ahead and copy and paste this one let's import from Google and let's rename this to Google and then we can just as easily add Google at the top here and then when you refresh this page again there we go now we have Google GitHub and credentials great so what we have to do now is we have to obtain some environment keys so first let's do them for GitHub and let's define them inside of these providers here so open an object and Define the client ID to be process. environment. GitHub centore ID and then client secret to be process. environment. GitHub centore secret like that and then copy this first variable and immediately add it to your environment file like this GitHub client ID and then do the same thing for GitHub client secret so just paste it here now let's go ahead and obtain those so you have to go to GitHub and go inside of your profile right here on your settings so you can click in the sidebar here and find the settings here like this then scroll all the way down and go to developer settings and in here go inside of O out apps go ahead and click create new oout app and give your application a name so this is going to be out uh tutorial for me and then let's give our homepage URL so that for me is HTTP Local Host 3000 like this without the slash at the end so just leave it at 3,000 to be the last thing and now we have to find our authorization callback URL so we can easily find that inside of this API out providers we have the call L written right here localhost 3000i out callback GitHub so let's go ahead and copy this and let's go ahead and paste it here and just remove the annotations make sure you have no annotations at the beginning or at the end of your application and go ahead and click register application like this and there we go you can now obtain your client ID so let's go ahead and assign the client ID like this and now we have to get our GitHub client Secret so let's go ahead and click on generate a new client secret and there we go you should now be seeing your GitHub client secret here so copy this and let's paste it here there we go GitHub client secret and GitHub client ID perfect so now let's do the same thing but for Google so go back inside of out config expand this uh object right here and assign the client ID to be process. environmen uh. Google client ID and client secret to be process. environment. gooogle centore secret as well like that great and now we have to obtain both of those so let's add them to our environment files so GitHub client ID and uh sorry Google client ID and Google client secret so in order to obtain those go ahead and Google Google API console and click on the link which goes console. cloud.google.com and and that will open up a console similar to this so in here first step is to create a new project so click on this Navar at the top and click new project let's give this a name of out tutorial and let's click create right here and now just wait a second for this to be created once it's been created go ahead and click select project and ensure that in your nav bar your new project is selected and now go ahead and click the search and Sear search for apis and services so this one apis and services like this and click on this one so it opens the actual page for that and in here first let's define oou consent screen like this and go ahead and select the external user type so anyone with a Google account can test the can test out the authentication give your app a name so out tutorial and go ahead and select your user support email which should autocomplete from your current account you can skip the app logo and app domain and you can also skip authorized domain so we're going to add this after we deploy because right now we cannot add Local Host here and go ahead and add uh a contact developer information email address here and click save and continue and once you've done that scroll down and just click save and continue so no need to add any special Scopes here and no need to add any test users just save and continue and there we go you're going to see your entire uh thing right here and now let's go and click inside of credentials here and let's go ahead and click create credentials and let's go ahead and create o out client ID so inside of here select the application type to be a web application you can leave the name as it is and now we have to add authorized JavaScript Origins and and authorized redirect uh Uris so let's go ahead and write HTTP Local Host 3000 for this one and for the authorized redirect URLs we have to use the one defined in here call back URL so just copy this one go back to uh this and paste it here and of course remove the annotations like that and make sure you don't add uh a slash at the end here or a slash at the end here so make sure it ends with Google like that and go ahead and click create and there we go you now have the client ID so we can copy this so Google client ID and we also have the client secret so copy the client secret as well and let's paste it here there we go so we have everything we need now so what I want to do now is go ahead inside of our app folder sorry components out social right here and now we have to implement the sign in functionality from here as well so you already know that there is a certain way we can sign in by using the .ts from where we export the signin function but we can only use this in server components or in server actions like we do here in the login we import sign in and then we use it here and we specify credentials so we can technically create a new server action which will simply call a wait sign in and then in here it would be uh Google right we can do that but I want to show you a different way of doing it just in case you are wondering you can do it still completely inside of client components without server actions as you could before so for that let's go inside of components out social right here and the first thing I want to do is create this common on click but function here so let's go ahead and write const on click click to accept a provider which will either be Google or GitHub and in here let's go ahead and let's import sign in from next- out/ react so that's what you have to import if you want to use it purely in a client component so go ahead and select the passing the provider param and then instead of having redirect URL redirect to as we have if we import it from out which is used for Server right in here we have a call back URL so let's define the default login redirect from at/ routes to lead to there and now let's go ahead and use this on click here first for the Google button so on click and pass in Google as the provider and in here pass in GitHub as the provider and now let's go ahead and test out both so here I have my Prisma Studio open you can run it by running any npx Prisma Studio I only have one user in my database and now let's go ahead back to our login page and let's go ahead and click on GitHub here and there we go you can see that it's asking me to authorize this website and once I click authorized I should be redirected and I should be logged in on my settings page and there we go and you can see that now I have some new fields for example my image is automatically filled with avatars from GitHub I also have the email which is connected to my GitHub account and I still have the role user and I still have my ID here and if I check my Prisma studio and refresh my users I have a new user here like this and you can see that I also have a link with an account because this is an oou sign in so I have a proper relation with my account where more information is stored like what is the provider uh what is the access token the token type the scope more things if you're interested in that great so now let's go ahead and try this out uh with Google provider but here's the thing if you try and log in with the uh with the same uh GitHub sorry with the same email that you just used for GitHub you're going to get an error so if possible try and choose a different email just to test this out so something you don't have in your database so make sure you try with a different email right so I'm going to go ahead and do that and there we go so I'm logged in with different email here and there we go now I have an image from Google right and I also have the role user and I also have the ID perfect and if I go ahead and refresh my Prisma Studio here there we go now I have three users so it's official our o out providers are now working but here's what I want to do now uh email verification is only going to be needed for credential users because Google and GitHub already do email verification on their own right Google in itself needs to have two Factor authentication to confirm that the user exists and phone number verification and GitHub simply uses a verification email link so there's no point in us doing that as well that's the point of oou providers so that they offer users a Sim as sign in and they offer you security that it's not a spam email so here's what I want to do go ahead and select these two users in your database which are logged in uh using GitHub or Google and go ahead and delete those two records from your database and that is automatically going to delete the accounts as well so if I go into account here you will see that I have no rows once I remove those two users and here's what we can do now so we can use uh we can go inside of .ts here and besides callbacks there is also something called events in next out so let's take a look at what the documentation says about events so events are asynchronous functions that do not return a response they're useful for audit logs or reporting or handling any other side effects which is exactly what we need right now so for example we have an EV sign in so when a user signs in if you add that to the event object inside of uh out you can do whatever you want here right you can also check if it's a new user so if you want to add a different field or something you can do that and that's going to be a synchronous and it's going to be useful for audit logs for example if you want to add some logs here or if you want to do some side effect we are specifically interested in a link account why are we interested in this one well if if this event is ever triggered that means that the user just used an oout provider to create or login inside of their account also you probably noticed that we don't need a special register for oou so it's very simple if it exists it's going to log in otherwise it's going to create a new account so we don't need a this will work equally we reuse this component here right it's exactly the same we don't need a special login for using credentials so where was I here so we're going to use Link account so that whenever someone creates an account using Google orinhub we're going to automatically populate this field called email verified because again there's no need for us to verify an email coming from an oou provider right I mean except if you chose a really you know Shady uh uh uh o provider of course but we are working with Google and GitHub here so we can trust them complet completely so let's go ahead and let's uh do that so I want to go uh inside of .ts here and let's go ahead and let's add events and in here I'm going to use the link account right here and inside of Link account we can go ahead and extract the user and let's also Mark this as an asynchronous function and in here let's go ahead and simply do await database. user. update where we have a matching ID of user ID and the data we are going to update is the email verified field to be new date so it's not a Boolean it is a uh date field so we know where an email when an email was verified so in the future if you we have some new rules for email verification this is going to be very useful because we can simply query and find all users which have not verified their their email in a long time so it's better better than a Boolean which is true or false that's it that's all we have to do and let me tell you what I was talking about see the model user email verified is a date time which is optional great so confirm that you only have one user in your database which should be the credential providers you know email name and password here with the email verified null so now if I go ahead and use GitHub for example to log in what should happen is a new account should be created and besides that if I go inside of my Prisma Studio here and refresh this event Link account there we go has immediately verified the email we know that everything is fine with this account no need to verify anything further here perfect so that works just as we expected but now we have to talk about this little error that we can get so this is my current email which I use for GitHub right so what happens if I go into my Google account and use the exact same email to log in let's try it out well as you can see I'm redirected to this weird page which we've never seen before and you can see that we have uh an error to confirm your identity sign in with the same account you used originally and in my URL I have an error here so how do we first of all how do we not show this page so this is great this is this comes autogenerated from you know from from next out but I want to use my own uh pages I don't want to use this Pages uh it's great that they exist out of the box for sure but how about we use our own well we can do that as well what we have to do is we have to go inside of .ts here and let's go ahead and do the following above events add pages and in here first let's define our signin route so for us that is is slash out/ login so now next out is always going to redirect to this route when something goes wrong and let's also add an error route to be slash out SL error so if something else goes wrong regardless login or just something breaks I never want the users to see this page I want them to see my nicely uh designed page instead so you obviously know that we don't have this page so we have to go ahead and create it so it's going to be quite simple let's go ahead and go inside of app out create a new folder called error and inside a new file page. CSX let's go ahead and import the out error page or error page it really doesn't matter uh and actually not a div what I want to return is an error card which we don't have yet but we're going to create it in a second here so let's go ahead and create the error card by going inside of components Out Create a new file error dcard dosx let's go ahead and let's import the header from do/ header or components out header let's import the back button from slashback button or components out back button and let's finally uh import everything we need from components UI card so that's the card card footer and card header like this and let's go ahead and Export const error card here and let's return a card whoops let's return a card with a class name off with uh 600 sorry 400 pixels Shadow medium and let's add a card header here with a header component and let's give it a label of oops something went wrong and a card fter with a back button component which will simply have a label back to log in and H of out login like this uh great and now let's go inside of the uh out error page and let's import the error card from components out error card so now if you visit Local Host 3000 SL out/ error like this uh oh looks like it automatically redirects us to here and I believe that is because we have to add that inside of our routes. THS here so we have to make that an out route so let's go ahead or even better let's make it a public route actually no let's make it an out rout I think that makes more sense out thereor because it's only going to happen for logged out users yeah yeah so let's make this inside of out routes here so now if you try and go there again out error you should see oops something went wrong like this perfect and I just remembered that I could have probably used uh inside of my components out uh where is it error card I think I could could have used the card wrapper so let me just try it out hard wrapper yeah I think I could have used that so I can just give it a header label of oops something went wrong like that I can give it a back button hre to out log in and a back button label of back to log in like that and in here I can add a exclamation triangle icon from radic UI icons and maybe wrap that in a div with a class name double full items Center and a flex maybe justify Center there we go and give it a little class name of text destructive like that all right that looks fine and yeah now we can remove all the inputs besides card wrapper and I'm just going to use components out like that so just a little bit of styling obviously it doesn't doesn't actually matter for the tutorial itself and we can go back to the login great but let's go ahead and try this again so I'm going to go ahead and use the Google login and I'm going to select the same email that I already have inside of my database here so what probably happened is that you didn't get redirected to the error page instead you came back to the login page well that's an improvement from what previously happened which just redirected us to that weird page which we've never seen before uh but here's the thing if you take a look at our URL we now have the error inside of our URL so we can use that to display the error here instead so the reason it didn't redirect us to that error page is because that's used for something else right but we have that covered as well but let's go ahead and read from the URL now inside of the login form and let's go ahead and show the error inside of our uh little form error box at the bottom let's go back inside of out form so components out uh sorry login form right here oh and we have some errors here okay um well we'll solve that in a second first let's go ahead and let's import use search forams from next SL navigation uh like this let's go ahead and let's get the search perams so const search perams are use search perams and then let's get the URL error to be search forams doget error and now let's go ahead and compare it so if it is our current error in the URL so I'm going to copy it from here which is oou account not link or you can just simply see what I right here so o out account not linked the capitalization also matters so if that's the case we're going to write email or we can write please login with uh or you can just say email already in use with different provider right something useful otherwise an empty URL error and then you can go ahead and use this URL error down here in the form error so make sure that the error goes first and then pipe pipe URL error and there we go email already in use with different provider so I'm going to go ahead and refresh this and clean the error from my login so I'm going to try and login again and see if it appears and there we go you can see how the error is being thrown now and you can see that if I go ahead and continue something here and now I have a new error you can see how it replaces that error so that's also something we want we don't want that error to always be shown there great so now let's go ahead and see uh why we are having this little errors here so I believe we can just easily fix that by adding exclam uh question marks here to the data like this uh success does not exist on property error uh all right let's go ahead uh and check that out why doesn't it exist um all right if it doesn't exist uh we probably didn't get around to doing that yet yeah so it doesn't exist yet we don't throw success anywhere so for now we can comment this out and I will add to do add when we add email sorry to fa yeah success is going to exist later when we add two Factor authentication so in the login function we're going to throw a success meaning the two Factor code has been sent right so that's what we're going to use this for but for now no need for this great so I don't know when we got that error sorry if I didn't catch it earlier I hope it didn't cause you any problems uh but yeah you can just add a little uh question mark here great so we just implemented o out inside of our application so just to wrap up this module you might be asking yourself well should we really get an error for this like I'm pretty sure I've seen some pages which are able to combine different o out providers like it's called automatic link right why don't we have that is it uh good to throw an error here well you have an answer for that question inside of frequently asked questions so in the concepts frequently asked questions here there is one called when I sign in with another account with the same email address why are accounts not linked automatically and in here you have an explanation of why they do that so they are obviously thinking about that uh and there obviously is a certain risk between doing that especially with the amount of providers that they support uh I believe that between Google and GitHub there might be no issue right they're obviously very reliable providers but not not not the same can be said for all of them I guess uh I believe there actually is a little key which you can add to manually link an account I think it's called something like dangerous linking and then you just enable that uh but I would recommend you don't do that obviously if they disabled it they know something we don't uh great so you just wrap that up great great job uh so what we're going to do next is we're going to go back to our register here and we're going to implement uh the email verification for credential users because we technically wrapped up email verification for allou users all right so now let's go ahead and let's create the verification process for credential registration so the first thing we have to do is we have to go in side of our Prisma schema and we have to create a model which will be used to verify our credentials right so let's go below the account here and let's create a new model called verification token like this let's go ahead and give it an ID which is a type of string it is the default ID and the default value of Cu ID and let's give it an email of string and let's give it a token of string and let's make sure that the token is unique and let's give it an expires of date time so we're going to make sure that the verification email can expire right we don't want anyone else to abuse that and let's add a unique rule for the combination of email and token so only one unique token per specific email great so now we have the verification token here and there's no need to create a relation with the user it can live on its own like this and let's go ahead and push that uh where we need to push it so what I recommend you do is that you shut down your app and run npx Prisma generate and then let's do npx Prisma database push like this so now you should have a new collection in your neon database and I believe you can also check that immediately here in nbx Prisma studio so if I run this uh right here and if if I go inside of here you should see a new collection verification token as I have right here so everything is fine great so now let's go ahead and let's create a couple of functions which we are going to use um to create this so the first thing I want to do is I want to create my data lab for the verification token so let's create a verification token here. CS so the same way we did like with user and let's import the database from at/ lib database and let's write export con get verification token by email to be an asynchronous function which accepts the token which is a type of string and inside we are simply going to open a try and catch Block in the catch we're going to return n otherwise let's get the verification token by using await database. verif ification token find unique let me see if I can expand this there we go find unique where we have a matching token like this and then return the verification token and my apologies this one uh should be email right so this is get verification token by email so we are not using the token to search we are using the email to search so where email like this and in this case it's not going to be find unique it's going to be find first like this so email email like that great and let's go ahead and copy and paste this and let's name this one get verification token by token and let's accept the token prop and then here we can use find unique and we can use the token query there we go so make sure you have get verification token by the token field and get verification token by email in here we use find First and we quy by email so make sure you have both of those now that we have this let's go ahead and create a lib which is going to be used to generate these tokens and make sure that you know if an existing token exist uh it gets removed so let's go inside of lib and create a new file called tokens DS so in here I'm going to keep all kinds of tokens which we are going to generate but the first one is going to be export const generate verification token which is going to be an asynchronous function which accepts the email and then inside let's go ahead uh and we have to generate the actual token and for that I'm going to use the uu ID so I ensure that it is always unique and for that uh we have to install mpm install uui ID like that and let's see if we need the types for that so if I import V4 as uu ID from uu ID there we go I need the types for that so I need to run this Command right here so mpm install D- save-dev or just- capital D types SLU ID so we need that as well and that should get rid of this typescript error there we go so import we4 from here and now we can get our token by simply using uh so let's import it as U ID before like this U ID version 4 great now let's go ahead and write const expires to be new date new date again. get time uh sorry plus 3,600 time 1,000 like that so basically we're going to expire the token in one hour right uh this is going to calculate the number of milliseconds in 1 hour and this gets the current time so we add 1 hour from now and we wrap all of that in a new date so we have that uh and now what we have to do is check if we have an existing token already sent for this email in that case let's go ahead and do con existing token to be await get verification token by email because that's the only thing that we have at this point inside of this prop so we're going to use the email one make sure that you have it in here make sure that you use fine first and the email uh query here and if we have existing token in that case we're going to go ahead and remove it from our database so let's go ahead and import our database from at/ lib SL database so in here let's write await database. verification token. delete and where is going to be ID of existing token. ID like that and now we can generate a new verification token so const verification token is going to be await database. verification token. create like that and data is going to be email token and expires there we go and now you can just go ahead and return the verification token like this perfect so now we have to find a place where we're going to run this function generate verification token so the first place we have to send it we have to use it is inside of the registration itself right so let's go inside of actions register right here and we already have a little to do here great so let's go ahead and let's import generate uh verification token from at/ lib tokens right here then we're going to go here at the bottom once we create the user and let's just do const verification token so verification token is going to be await generate verification token and we're going to pass in the email that the user is trying to create an account with like that and then we can change this message to be confirmation email sent so obviously we're still not sending the email but for now we're just going to have the verification token here so let's go ahead and make sure that our app is running and you can also prepare npx Prisma studio in another terminal so that you can see uh when it gets added so let's go ahead and check it out so I'm going to refresh this right here I'm going to pair my Prisma Studio here and right now I have zero verification tokens here so nothing in my Prisma database so I'm going to create uh new uh actually this is my email right so this is verification test it really doesn't matter what's the password and all this is send now is tell me that the confirmation email has been sent and inside of my Prisma studio if I refresh this I should have a new new verification token and there we go you can see that we have the exact email which this verification token is used for and we have the unique token using uu ID and we have the date when it expires perfect so what we have to do now is actually send an email but there is one place where I want to generate this token uh before we do that and that is in the login right so this user should not be allowed to log in at the moment right if I use that email which I have right here and if I try and log in here it's going to work right well first thing we have to do is we have to not allow the user to sign in if they still haven't uh if they still haven't still haven't set up their email verification and otherwise if they try we need to send them a message like hey we sent you an email again here on the login for so if they go away from the register form they need a way to send that email again and they can do that very simply by trying to log in and we're just going to send them an email again so let's go ahead and we're going to do the exact same thing here so let's go inside of actions login in here and let's go ahead and import generate verification token from at/ lib tokens right here and now what I want to do in here with when we get the email and the password let's go ahead and let's try and get an existing user from our database so I'm going to use await get user by email so make sure that you import uh get user by email by data user we already have that and it's very simple we also have the user ID so in here we're going to attempt to fetch the user that the currently the current user is trying to log into with the email and in here already we can check if there is no us user or if there is no user. email sorry existing user or if there is an existing user. email or if there is no existing user. password meaning that they shouldn't be logging in with their credentials instead they should log in using oou in that case we can return an error invalid credentials or you can return something a bit more specific like inval I don't know what will tell the user uh so it's either going to be you know user does not exist or yeah let's do that email does not exist let's do that all right and now let's go ahead and check if the user exists but it doesn't have its email verified so if exclamation point right here user doesn't have the email verified existing user my apologies existing user does not have the email verified in that case we're going to generate a new verification token right here using await generate verification token and passing the user. email uh existing user. email so like this and then we're going to return success confirmation email sent right so we're going to break the function here and we are not even going to attempt to sign in but remember we are not done yet because users can still use the API uh to log in inside of our app so we have to protect them inside of the sign in uh call back so we have to do that as well but we're going to that do that in a moment I just want to test out that the new verification token is being generated if I'm trying to log in with a user that doesn't have their email verif meaning that they just signed up for their account or they waited longer than an hour so the email that we sent them during the registration is no longer valid so they need a new email so one of those so let's go ahead and try that out but just before we try it out I think we have to revisit our components out login form because in here I believe I commented out yeah so I wrote 2 FAA yeah yeah it's actually already so make make sure that you add inside of the onsubmit function inside of out components out login form just bring back set success data question mark. success like this let's just confirm that we actually show the success message we do all right so let's try it again so this time I'm going to go ahead and log in again as this user and I just want you to kind of pay attention to the current token right right kind of try and remember like the last few characters because the only thing we're going to notice is that uh this one this token will be updated and the ID is going to change so try to you know keep an eye on that so I'm going to try and log in now and I should be blocked from logging in and I should get a message confirmation email sent so if I refresh this there we go you can see how the token changed and the ID changed meaning that we successfully created a new expiration well we could have just looked at the expiration yeah uh we just created a new expiration for the token uh great so we're almost there we just have to do the same thing now inside uh of our .ds because you know you already saw that sometimes Al can redirect to that special page which it generates by itself so from there we don't protect anything right so that's why whatever you do in your login or register functions you also have to do an equivalent inside of callbacks because what you do in the register and login actions or API routes it doesn't matter you're doing that well yeah for security but also for user experience but for Total Security you also need to do it inside of next out so you need to have equivalent things inside of next out I could have easily done this you know inside of registration as well but it's easier to do it in this way like I like to my I want I want I like to know that my out is taking care of this so you know when it comes to out you never want to be worried uh that you're missing out on something and this is you know the best way to do it right here so let's go ahead uh and we have to create a call back called the sign in so I'm going to do this at the top here so a synchronous function sign in like this and inside we're going to destroy structure the user and the account by default let's return true meaning we are allowing you to sign in but here's what we're going to do we're going to check uh and we're going to allow o out without email verification so the way we can do that is simply by checking if account question mark. provider is not credentials make sure you don't misspell this so so credentials in that case simply return true that's it so if it's anything other than credentials I'm going to allow this without email verification of course when you start adding more providers in your code you might have to adjust this I'm not sure what kind of providers exist in next out so if you might be want to be more specific for example you can do the opposite thing you can do if account. provider is credentials and in that case you know open the whole logic to check whether the email is verified or not but I'm doing it this way it's simpler for me right and inside of here I'm going to attempt to get the existing user using a wait get user by ID using user. ID inside of here and I'm going to Simply check if not so put an exclamation point existing user question mark. email verified in that case return false so very simple if the email if the user is not has not verified their email I'm going to block them from logging in that's it for now and I'm going to add a to-do comment here add to fa check so we're going to have that later uh great and if you want to you can add a comment here prevent sign in without email verification right so as I said before you know if you add more providers in your code you you have to check if this is still okay because I don't know what kind of providers exist so right now I'm only requiring to uh email verification on the credential uh provider right and and I'm not requiring Google or GitHub so if you're using this you in production and you add some new provider you know make a decision if you still want only the credentials to be checked for email verification if not you know you can go ahead and modify this logic to do the opposite so you can do if account provider is equal to credentials in that case you can go ahead and do this thing for example something like that but as I said uh I know what is the structure of my app I know which providers I use so I want to allow everything to Simply Be able to log in except if you're using the credentials then I'm going to do a check on you to see if you have your email verified so this is what should happen now so go inside of your actions login right here and for now I'm going to comment this out right so I'm not going to generate a new token so imagine that I didn't write this code where we block the user from our login function so this is what going to confirm to us now it should throw an error instead of this because we just modify that inside there we go you can see how it threw an error that's exactly what we want so even without this code in the login function we have a fallback inside of out which will never allow that kind of user to log in if they don't have their email verification so that's why it's important to match the logic which you write inside of your you know be that a server action or an API route match that inside of callbacks as much as you can it's going to highly improve the security of your application great so now that we have all those systems in place and of course make sure that in the login you actually bring this back which if you commented out if you commented it out with me and what we have to do now is we have to set up our uh mail provider so for that I'm going to be using resend because it's extremely simple to set up it has a very generous free tier and it's just it will take us five minutes to do this for this tutorial I'm going to give you some Alternatives as well if you want to for any reason but most of them are uh more expensive to start with and you know require a credit card or something but resent doesn't require anything you can just start using it and you can finish the entire tutorial just by using resent all right so let's go ahead and let's do that so head to rent.com or use the email in the description and go ahead and create an account if this is your first time you're going to get uh prompted to create a name so I'm going to call this out tutorial and create a team and there we go now let's go through this onboarding so first let's add an API key like that great and what great is you can already test whether it's working or not so you should have it should have the email you logged in with right here you can see I created a new email just to test this out and just go ahead and click Send email and if I check my inbox here very quickly it should appear there we go can I hide this sidebar I can't H okay there we go congrats on sending your first email from onboarding uh great so now let's go ahead and let's go uh inside uh the docs right here and let's use the nextjs quick start and first they tell us to create an API key so we already have that so I'm keeping that right here don't close this tab yet and now let's do mpm install resent so I'm going to copy this let's go inside of our terminal here uh I will close the Prisma studio and I'm going to run mpm install resent like that let's see what is the next step so we don't need any email templates here I just want to see if okay so they use resent API key so that's what I was looking for the the name uh for what to save this in so let's go ahead inside of our environment variables after this has installed and let's simply add the resent API key and copy the API key from your on boarding right here there we go uh great so now that we have the uh API key I just kind of have to explain one thing about recent so you can go ahead and find you know the free tier and if you're interested in that I'm not sure where it is is it settings here there we go yeah so you have 3,000 free emails a month uh 100 free emails a day in the free tier right here right but uh right now you can only send emails uh to yourself right so to this email which you can find in emails you cannot find you cannot send it to anyone else uh until you add your domain so that's what you have to do you have to add a DNS record to your domain and no you cannot use versel or herok or something like that no you need to own a domain so good thing uh for tutorial this is more than enough that you can send yourself uh emails but if you want to you know share this with your friends or something and use you know allow these emails to be sent sense to everyone the easiest one is to Simply add a domain I'm going to show you how to do this exactly uh by in the end of the tutorial after we deploy because this is for production only you don't need to do this for development great so just make sure that you have your API key here right if you cannot see it anymore I don't know if you can see it yeah let me just see edit API key uh yeah if you accidentally lose your key you can always click create a new API key all right and just give it full access of course and then you can copy it again and just paste it inside of recent API key great so what I want to create now is my mail Library so let's go ahead uh and let's go inside of lib and in here create a file mail. DS like this let's import resend from resend and let's define recent to be new resent which uses the process. environment. resend _ API uncore key and confirm that it matches here so resent API key copy it from here paste it here make sure there is no typos and now let's export con send verification email here to be an asynchronous function which has the email which is a string and the token which is a string right or I'm just going to collapse this like that so we have the email and the token and then inside of here let's generate the reset link uh sorry the confirm link is going to be HTTP Local Host 3000 slou SL new- verification and then we're going to add a question mark and we're going to add a param for the token so let me just zoom out so you can see this in one line and we're going to add that token at the end so this is the important part well everything is but make sure it goes to SL out slash new- verification and make sure that you add a question mark and a Pam or a query token and then stringify the token which we are passing from the props here so this is the confirmation link which we are going to email to the user and then we're going to create this new verification page and we're going to use it to detect whether the token has expired whether it exists and if everything is okay we are simply going to change the users email verified status in the database to a new date and of course we're going to have to change this later to something Dynamic so it works in production otherwise you know your users are going to get Local Host emails which won't make sense but for now this is good enough and now what we have to do is send the email and now you're going to see how incredibly simple that is with resend so just resend. emails. send from and in here choose onboarding at recent dodev like this to email subject is going to be uh confirm your email and we're going to have HTML open back ticks and you can just write HTML here so write a paragraph like this and I'm going to write click open an a anchor tag I forgot how to write anchor tags okay in here I'm going to write here and let's give this anchor tag an HRA to the confirm link and in here you can simply write to confirm email there we go that's it that's all the code we need so make sure that you have a little paragraph here right which starts here and ends here then open an anchor tag which has an hre open and notations and add a confirmation link here uh and now let's go ahead and use this send verification email inside of actions register here whoa how did they get there there we go we have this to do right here so let's go ahead and import that from our mail so send verification email from at SL lib slma like this and let's go ahead and remove the to-do and use await send verification email and we expect two arguments email and then a token so first let's pass in the email and then actually we can do this we can use it from the verification token to ensure that it's the one that's that's in the database so let's use verification token. email and verification token. actual token now let's try that out so I'm going to go ahead and I'm going to create a new account here so I'm going to call this verific ification verification at mail actually yeah we need to use the actual you need to use your email so make sure that you use the email where you can send the email address to so for me that's this one tutorial mailing it should be written right here below or you can click on emails so make sure you do it with this email because no other emails will work until you add a domain right so I'm just going to go ahead and copy this cop cop Cy right here if you have an account already just remove them from your database so there we go add an email that you can find here in resent let's go ahead and create an account and now I should be actually sending an email so let's see if that's working confirmation email sent and there we go confirm your email and if I click here it should lead me it should redirect me back to login because I'm not logged in and we didn't add this new route which is the out new verification token we did not add that to out routes but it is officially working great so now what I want to do is also send the verification email in the login page sorry in the login functionality so let's go ahead and do that as well so I'm going to go inside of actions login here and now let's go ahead and import the same thing so I'm going to import send verification email from s/ lib mail and in here let's await send verification email first argument is the email and the second argument is the token itself like that so now uh if I go ahead and log in using verification no sorry using the my email here which is tutorial mailing all right so I created an account right but I didn't verify my profile so if I try to log in now I should be blocked from logging in and instead a new email should be sent so let's try that out and there we go you can see how now I have two emails this is the old one and this is the new one uh a minute ago and I can go ahead and click here again perfect so we can officially send emails in our app great so I'm going to end module here in the next one we're going to create that new verification screen where we're actually going to verify the email uh for now if you want to if you have a domain and you know how to add a DNS record you can do that right now if not wait till the end of the tutorial when we get to deployment and I'm going to show you how to do that great great job all right so now what we have to do is we have to create the actual confirmation page so that user can click on this link from their email and that that's going to load and confirm the email here but just before we go there I feel like I didn't do a good job explaining inside of out. THS here we have this asynchronous call back sign in and it seems like I kind of magically new uh to look at this provider here and put the credentials so what I want to do is I want to conso log the user and the account here so we can actually see what's going on inside and how I knew that I have to look for credentials here right so we use the signin callback to First allow any oou logins which is Google and GitHub to log in Freely but otherwise if it's not oou so it is if it is uh credentials in that case we search for the user and first we check if they have their email verified and then later we're also going to do two Factor authentication for credential users because there's no need to do two factor for Google and GitHub users because Google and GitHub has their own two Factor authentication so make sure that you add or you don't have to you can just look at the video so I added the console log in the signin callback to see what we get from the user and the account here so I'm going to go ahead and attempt uh to log in using GitHub here let me just refresh this page to confirm everything is working so I will try to log in with GitHub and I'm going to see inside of my terminal if I have any useful information from that call back here and there we go you can see that I have logged my user there we you can see my user information here and you can also see the account information and in here you can see that the provider is GitHub like this right so I could have also used the type maybe that's even better right but as I said you know there are many providers and not all of them are exactly you know reliable to not have their email version verification so now that we checked how this looks for out providers let me sign out and let me try and log in with another user so I'm going to go ahead and open my npx npx Prisma studio uh just to see what users I have inside of my account here do I have any user which is already registered uh there we go I have this test user which has their email verified null and it should not have any account ation so I know that this is uh email username and password registration and I think I know what is the um I think I know what's the password for this one so I'm also going to go inside of actions log in and for now I'm just going to comment out this code checking for email verification just because I want this to fail right I want this to prevent us and I want to see this conso log here so I'm going to prepare my terminal here you don't have to do this of course I just just want to uh go ahead and show you how this looks so if I log in using this account there we go so I have an error here but if I scroll up there we go so we have my user here with the email with the email verified null and I have an account and you can see the type is credentials and provider is credentials as well so you could have used the type or the provider inside of here so we can now remove this console lock so we could have also done user account. type is not credential that would also work so that's where I got the provider value from if in case you were wondering about that great so let me just revert this so I want to make sure uh that this is now being sent here let me just go back inside of my code here so I will just uncomment this out so if I try this again this should send an email well it will not be able to send an email here because we have not set up a domain uh great and one more thing I want to explain is the recent here so I told you that you can only send emails to this email which you logged in with right that is true until you add a domain once you add a domain you can send emails to anyone and you can also change where the emails come from because if you take a look at our mail service now you can see that I have to specify that it's coming from on boarding at recent. deev but once you add your domain which we're going to do later when we do deployment you will be able to modify this so it sends from you know for example code with antonio.com it will be something like onboarding cod with antonio.com right so no you're not stuck with this email don't worry great so now what I want to do is I want to go inside of routes. THS and what's happening right now is that if user tries to click on their confirmation email right here uh they get redirected back to the login page that's because they're trying to access a page called slout slne verification so you might be thinking all right we have to add that to the out routes and that could work yes but I also want to add this to public routes because remember user will be able to change their email from their settings page and if they are able to change their email from the settings page that means that they are logged in so the best way to the best place to put this route is inside of the public routes so both logged in and loged out users can access this so let's write slout SL new- verification like this and make sure inside of your mail. TS inside of lib folder mail. Ts that you use that exact route so slout Slash new verification so it should match this exactly and now if I try and go inside of my uh mail here and open this page I should get a 404 which is a step towards uh while not being redirected so now we have to actually build this page so let's go ahead inside of the app folder out let's create a new folder new verification and inside create a page. TSX and let's call it new verification page and a div new verification so once I save this there we go we no longer have an error and if I Try Again from mail here there we go you can see how it redirect me to new verification and inside of my URL I have a matching token which I can find in my database great so now what we have to do is we have to build the new verification form so new verification form like this if I save of course I'm going to get an error because that does not exist so let's go inside of components out and create a new file new verification Das form. THX let's mark this is use client and let's export con new verification form and let's return a div new verification form then we can go back to page. DSX and we can import that from components out new verification form and there we go we no longer have any errors and now we are free to develop directly in the new verification form so first things first let's go ahead and let's import part wrapper from do/ card wrapper or components out card wrapper and let's go ahead and replace this div with the card wrapper and let's go ahead and give it a header label of confirming your verification and let's give it a back button hre of slout SL login and let's give it a back button label of back to login like this great and now what I want to do inside is add a div here with a class name of flex items center with full and justify Center like this and inside what we are going to do is we're going to add a little loader so for that we have to install a package called react Spinners so I'm going to shut down my Prisma studio and do npm install react Spinners like this so make sure you add this package and then we can import any loader you like so you can Google react Spinners to see what kind of spinners they all have but I really like the one called beat loader here so in here you can now render the beat loader like this and there we go you can see how this is going to look like so when a visit so when a user clicks from their email here it's going to start loading and automatically verifying this URL link using the token which we have inside of our URL uh just a quick tip if you don't have the token inside of your url confirm inside if your lib mail in send verification email that you have a token as the parameter that you properly assign it to the URL and then find where you use the send verification email so we use it inside of login and register so in here ensure that the first parameter is the email the second parameter is the token and the same thing in the login function the first parameter is the email and the second parameter is the token great so let's go back to New verification form which we are working in it is located in component on out new verification form here what I want to do now is I want to import use search params from next navigation and let's go ahead and add them here so search params from use search params of course make sure that you've marked this as use client so you can use hooks inside and then let's get the token using search pam.get token so how do I know that I need to get the token exactly because of my URL so you can see that this token value is stored inside of a token query right here so that's how I can get my token great so what we have to do now is we have to write an onsubmit function and we're actually going to uh wrap this inside of a use call back because we're going to put it inside of a use effect so let's go ahead and import use call back from react and let's replace this on submit to use callback add a an empty dependency array and in here for now we can simply conso log the token and add a token to the dependency array now let's import use effect from react and let's call use effect here and inside of use effect we are simply going to call onsubmit once like that and now if you go ahead and open your console log you can see the token which is stored inside of my URL being being logged here and you're probably noticing that it's being logged two times you don't have to worry about that that is only because of uh I believe it's called react strict mode uh which in development calls every use effect twice so in reality in production this is only going to be called once right and I believe we might even get some bug here because in this onsubmit we're going to check if the token has expired but once we confirm it the first time it's going to be expired so then when it triggers another time we're going to get a little error here but that's only going to happen in development not in production because in development react calls use effect twice so I just want to bring that to your attention so if you're seeing it twice that's completely fine I have that as well great so now what we have to do is we have to actually uh create a functionality to call the verification so we're going to call that uh new verification action so let's go inside of actions and create a new file new new verification. DS let's go ahead and Mark this as use server at the top here and let's import the database from s/ lib database let's import get user by email from data user and let's import get verification token uh not by token because uh sorry get verification token by token like this from data verification token and I'm just noticing now that I have a little misspell here so let me go ahead and quickly resolve that so you can check if you have that as well so verification is spelled v r i fi and I think inside of my data folder I misspelled it v r fi so I have to rename this to verification by adding a little I here I just don't like typos in my code and now I have to look uh throughout my project and see uh where I am misspelling it so let's see uh I believe this is just some cache this should be completely fine so when you rename your file you have to go through all of your order files to see if they are still using it properly so I'm going to search for uh get verification token here all right so I use it inside of verification token data all right I use it inside of tokens here there we go you can see how I have an error here because I renamed my import so go ins side of lib tokens and in here I have to rename this to be verification there we go so we resolved that Let me refresh this page all right I think that's the only place where we have it get verification toen is inside of tokens and here where we are working in the new action so actions new verification I have to rename this as well to verification token there we go so no more errors inside of my code great so inside of here let's export const new verification let's make it an asynchronous function which simply accepts the token which is a string let's get the existing token using a wait get verification token by token and passing token uh if there is no existing token in the database we are going to return return an error saying token does not exist meaning there is no way we can verify your email and now let's check if token has expired by using new date existing token. expires like that is smaller than new date as of now and if it has expired in that case let's go ahead and return an error token has expired like this and then let's go ahead and find the user we are supposed to validate using this token so await get user by email is going to be existing token. email if there is no existing user in our database connected to that email that could mean that the user changed their email in the meantime somehow so let's just return an error user does not exist or maybe more specifically email does not exist in our database and if all of those tests above have passed we can finally do await database. user. update and in here let's use where ID is matching to existing user. ID and the data we are going to update uh is that email verified is new date but also one more thing that we are going to update is the email to be existing token. email so why am I doing this as well why do we need this update well during the registration process it is not needed but we're going to reuse this new verification ation server action for whenever user wants to modify their email right so when we create the settings page and the user uh adds a new email we are not going to immediately update their email in the database we are simply going to create a token with that new email and send an email to that email and then when they confirm it we are going to update the the email value inside of their database so that's why we need to do this as well so in registration process this is going to be exact the same as it was before so that's why maybe this isn't making sense to you but keep in mind that we're going to reuse that for when user wants to change their email right so that's why we have to update the email here as well great and then finally we can go ahead and remove the verification token so verification token. delete where ID is existing token. ID as simple as that and let's return success email mail verified there we go so we have our server action finished now we can go back inside of the new verification form inside of our components out new verification form right here and let's go ahead and let's import that action so import new verification from actions new verification here and let's go ahead and call the new verification here on the onsubmit so I'm going to do uh new verification pass in the token which we have inside of here like that and of course we can go ahead and check here uh immediately if we have the token or not so if we don't have the token we can break the function immediately like this uh well that's actually not what we're going to do what we're going to do is we're going to throw an error right so let's do that so let's import use State here and let's go ahead and let's define error to be set error from use State and let's give it a value of string or undefined and let's do the same thing for a success message so set success like that so in here if we don't have a token and we try to submit we're simply going to do set error missing token and we're going to break the function then like that and then instead of new verification let's do dot then and let's get the data and in here let's set success to be data. success and let's set error to be data. error like that and let's also add one. catch in case something breaks and let's manually do set error to be something went wrong like this and what we have to do now is actually render the errors so let's import our form error from SL form error or components I think it's just components like that and let's do the same thing for form success from form success great and now let's go ahead uh and render those so here at the bottom uh below the beat loader let's add form success to have a message of success and form error to have a message of error and there we go you can see how it says the token has expired right so you should get this message if you use the old verification token you can see I sent this 17 hours ago so obviously it has expired by now but you can see how I'm still showing the loading indicator even though I got an error and here's another thing you can test inside of your url remove the token completely and now you're going to get an error missing token right so choose one error at least for you to have here and let's go ahead and modify this now so we are only going to show the bit loader if there is no success uh and if there is no error so if it's a completely empty slate there we go so you can see how now the loader no longer shows but if I refresh it will only show during the actual uh server action call that we are doing right here new verification so on the use effect the moment the component mounts we call on submit which then in return calls the new verification if it has a token inside of search params here great uh and now what I want to do is I want to also modify this form errors and form success but let's go ahead and try and create an actual new token so for that I'm going to go ahead and go inside of my Prisma studio and this is uh the email I can send my emails to so confirm inside of your resend that you're using the email where you can send emails to uh and let me just close everything I don't need here so go inside of your app and try to log in again right and this should send you a new email or you can clear database and create a new account with this email and there we go confirmation email sent so now I should be getting a new email there we go so when I click here let's see if that's going to work email verified and then we have an error token does not exist right so that's the thing that I was telling you about that's because our use effect fires twice right so on the second iteration it's looking at an already confirmed token which we removed from the database but still I want kind of want to cover this case just in case you know it can happen in production even though I don't think this can happen in production because it won't fire twice but we're going to do our best to cover that as well and here's a fun thing let me just check if I'm now if I am now running my Prisma Studio I think I shut it down so let me open it again npx Prisma studio so in here if I look at my user and let's find it by this email so tutorial mailing and look at this we have officially verified our email which means that if I try and log in again I will be allowed to log in let's see and there we go I am officially confirmed and I can log in inside of my account perfect so let's just try one more time to resolve that little bug that we have so I'm going to do the following I'm going to go inside of my Prisma studio and let me just remove all the other users so I just want to focus on the one where I can send my emails to this one and what I'm going to do let me just refresh this again there we go so what I'm going to do is I'm going to remove my email verified property like this leave it at null and click save change or simply remove it completely and just you know register again if that's easier uh and now if I go ahead and try and log in again I will be sent a new verification email but before we click on it and verify our email again let's try and protect our little app here from that happening again so the first thing I'm going to do is go inside of the onsubmit here and what I'm going to do is if we already have a success message or if we already have an error message simply break the function right so and then we also have to add those to the dependency array so let's add success and error here and let's go ahead inside of here and let's only show the error if we never had success in the first place like this and I think that this should improve the behavior a bit so I cannot log in but I got a new email here there we go confirm your email and let's see if this will be stuck at email verified oh so it's still showing token does not exist but as I said uh yeah I think there's kind of No Way Around this at the moment you can play around if you want to but as I'm saying this only happens because you're calling use effect twice right and I believe that it won't even listen to this logic because it's it's in some special react state where it's being called twice uh with the exact same values I don't think it even considers this new values being changed so I think that's why this is happening uh but as I said in production we're going to test it of course later I think this will not happen at all and you're just going to see a message saying email verified so if I try this again uh what was my email tutorial mailing Gmail and if I log in again I should be able to log in there we go perfect so we successfully verified our email if I refresh here I'm going to get email verified to the new date perfect so let's just recap our entire flow when the user registers using the register server action we generate a new verification token using the email they used to register then we send the email to that we send the verification token to that email inside of the verification inside of the email we are using uh a route called out new verification which we added to the public routes then inside of our app out we have that new verification page which renders the new verification form located in components out verification form inside of here we use the search params to search for the token which was append appended inside of our mail function send verification email so the second argument was token and in here we append that token so we check if we can find that token in the URL if on the onsubmit which fires automatically in the use effect the moment the component loads is missing we return an error token is missing otherwise we call the new verification server action or you know in your case this can be an API route as well it really doesn't matter instead of new verification we send that token from the URL we search the token using the function get verification token by token which we defined in here so we use def finded unique where token matches the token if we cannot find the token in our database we return an error token does not EX exist second thing we do is we check if an hour has passed from the exper from the creation of the token if an hour has passed we return token has expired otherwise if it has not expired we check for the user which this token was intended for using the email so get user by email if the user doesn't exist which you know it can happen there are edge cases in that case we throw an error the email for this token which you're trying to verify does not exist there's nothing we can do here otherwise if we can find the user we update the user using the that user's ID we change the email verified to be the new date meaning today I verified this and we also modify the email for uh for to be whatever was stored in the verification token because remember this exact logic is going to be later reused when we add the settings page to change to a new email so that's why we also have to update email in here and not in the settings because we don't want to immediately change the user's email other otherwise they could use anyone's email for that right that's not good we have to ensure that they can verify the email that they are trying to change and last thing we do is we remove the old verification token no need to store that inside of our database anymore and we return a success message email verified and all of that is reflected inside of this dot then we also have an additional catch in case something goes wrong which is out of our control here and we have a little loader here we have a success and we have an error and yeah we have that little bug which as I say I'm pretty confident it only happens in development because react strict mode you can see that it's completely ignoring the fact that we already set a success message there but yeah I tried to fix it but you can see that it's not working we're going to test that again in production as well great great job what we're going to do next is a functionality to reset our password so we currently don't have that little question here so we're goingon to add a little question forgot your password and then we're going to do a very similar logic we're going to send user an email and we're going to allow them to add a new password if they have the correct token inside of their URL so let's go ahead and create the forgot password functionality so for that I want to go back inside of my components out login form right here and in here we have to find our password input so this one right here which has the name password and the input which has the type password and outside of form control here we're going to add a button component which we already have imported inside of components UI button and now inside of here let's go ahead and add a link component which we can import from next slash link so make sure that you add this import I'm going to move it up here with the other Imports like that and now let's go ahead and give this link an HRA of slou slash reset and then let's go ahead and write forgot password here and let's go ahead and give this button uh a size of small let's go ahead and give it a variant of link and let's give it as child option so it properly uses the link inside and let's also give it a class name of px0 so it is aligned with the input here and let's also give it font normal so it's not bold like that and now when the user tries to click here nothing will happen because they are immediately redirected back to the login page so what we have to do is we have to add slash out SL reset inside of our routes so let's find the routes. Cs here and we're going to add them to the out routes so go ahead and add SL / reset to the out routes array and now if I click forgot password uh I should be redirected let me go ahead and try this again there we go so refresh your page and you should be redirected to a 404 page and your url should be slout SL reset so now let's go ahead and let's create that page so I'm going to go inside of my app folder out and let's create a new folder called reset and inside a page page. DSX with a default export of reset page and a div reset page and there we go we now no longer have that error and we can click on forgot password here which redirects us to here perfect so now obviously instead of this div we're going to create a reset form like that and we can reuse a lot of elements from our login form so I want to copy that one so let me close everything and we will remember that we have that error inside of our reset page let's go inside of components out and let's copy the login form in the out and let's rename it to reset form like this make sure that you are inside of reset form so confirm right here that your reset form is open first things first let's go ahead and rename this to reset form like this and then let's go ahead and let's change the card wrapper here uh to ask has forgot your password the back back button label let's change that to go back to login and the back button hre is going to go back to login like this and now we can go back inside of the app function sorry app folder out reset and we can import the reset form from components out reset form just make sure that you have renamed the expert constant to reset form here and it should look exactly the same as the login functionality so now we're going to go ahead and modify it so let's go ahead and let's start by hiding socials right so I'm going to remove the show social prop and there we go that's going to remove the socials because that's uh not something we want to show here uh now what I want to do is I want to remove this uh use search params so we're no longer going to need that error so so remove the use search params and now we have an error here so remove this URL error constant now we have to go down and find the form error and remove the usage of URL error like that and now we can also remove the Imports we no longer need which is use search params so let's go ahead and remove that as well great and now the only thing we have to have for our inputs is the email so the user will enter the email for the account they forgot to the password for so we can find the actual password form field and completely remove that so find the end of the self closing tag like this and simply remove it so you should only have the email field inside like this great let's change the login button to write send reset email here like this there we go so this is already looking a lot better perfect so what I want to go now is I want to go back inside of my schemas so let's go inside of the schemas folder index.ts right here and let's copy and paste an existing schema like login schema here and let's just add an email and call this reset schema so just an email with a message email is required like that now let's go back inside of reset form inside of components out the reset form and let's go ahead and we can remove this link it seems we no longer need that and let's import reset schema from schemas here so now we can fix all the errors where we are using the login schema so this is going to be reset schema this is going to be reset schema and this is going to be reset schema and as you can see we have an error for the password field in the default values because we don't need it for this one right here and obviously we have some issues with our on submit function because it's calling the login server action we're not going to use that server action we're going to call the other one perfect so for now what we can do is log uh comment this out and instead let's conso log our values here and let's try this out so I'm going to open inspect element and I'm going to send this to tutorial mailing gmail.com so we're going to have to use uh that email from resend right because we're going to be sending some emails now and there we go when I click submit inside of my own submit I have the proper values of my email here here and nothing else perfect and let's try back to login forgot password there we go both are working perfect so what we have to do now is we have to well you can bring this back and we have to create an equivalent action to actually reset uh the uh the password so let's go inside of our actions and let's create a new action reset. DS remember to mark Market as use server and let's go ahead and import reset schema from our schemas let's go ahead and let's import get user by email from data user and let's go ahead and import everything as Z from zot so we can do server side validation from here as well great and now export const reset function to accept the let's make it asynchronous value which accepts the values which are typee of z. infer type of reset schema and then inside let's validate our Fields so validated fields are reset schema save bars and P pass in the values which will come from the props if we don't get a success message so if exclamation point validated fields. success return an error in valid email so server side validation in case they bypass the front end side validation and then we can safely extract the email from validated fields. dat and now let's find the existing user using await get user by email which we imported and pass in the email so make sure that you imported get user by email from data user and if there is no existing user let's go ahead and return an error which is very simply going to say email not found like that otherwise we can return a success message reset email sent obviously it's not here yet so we're going to add a little to-do generate token and send email there we go so now we have our reset function so we can go back inside of components out and find the reset form here let let's find where we import the login action and this time let's use the reset action so import reset from actions reset and let's use the reset and send the values and there we go no more errors inside of our component so let's try this out by adding a random email which doesn't exist inside of our database and that should throw an error that the user well the email is not found so we cannot reset a password for this one but if I try and use my my existing password Here I should get a success message reset email sent like this great so what we have to do now is we have to visit our schema Prisma and we have to create our password reset token so let's go ahead and do that so I'm going to go inside of Prisma schema. Prisma and let's add a model password reset token it's going to have an ID which is a type of string string at ID and the default value of Cu ID let's give it an email of string let's give it a token of string and a unique value and let's go ahead and give it an expires of date time and a unique combination of email and token like that so very similar to our verification token it has an ID it has an email token expires and unique uh yeah and don't reuse the verification token right if you're thinking oh we could have just reused it it's simply safer to keep tokens separate right uh security wise it's better that you have an exact model you can look up uh and know this is for password reset this is for email verification even if they are exactly the same uh so what we have to do now is we have to create utiles to fetch these from the database but before we can do that we actually have to shut down our application so let's shut down Prisma Studio let's go ahead and let's shut down mpm runev let's do npx Prisma generate so we add those new fields to node modules and npx Prisma database push so we add them to our neon database right here once that is finished we can go ahead and run npm run Dev again refresh your Local Host to ensure nothing breaks and now let's close the Prisma schema let's go inside of the data folder and create a new file password reset token. DS let's go ahead and import the database from s/l database let's export con get password reset token by token to be an asynchronous function which accepts the token which is a string inside of here open a try and catch Block in the catch we're simply going to return null and in here let's get the password token to be await database. password reset token which we just created find unique and where matches the token like that if you're getting an error for db. password reset token it can mean two things you didn't run npx Prisma generate or in your schema you didn't name the model correctly or if you did both then go ahead and shut down Visual Studio code and open it up again or use command shift p or control shift p and type in reload window right here and that is the equivalent of shutting down your Visual Studio code and starting it again and in here let's just return the password reset token let's call this properly password reset token like this great and now let's go ahead and copy and paste this and this one will be named get password reset token by email and it's going to accept the email Dr and it's going to use find first to get the matching email and everything else can stay exactly the same great so now what we have to do is we have to go uh back inside of our tokens lib so let's go inside of lib tokens so we have generate verification token now let's go ahead uh and first let's import get password reset token by email from data password reset token which we just created and let's go ahead and write the uh whoops and write the function for this so export con generate password reset token you to be an asynchronous function which accepts the email which will be passed from this page right here using our server action and then let's go ahead and generate the token using uu ID V4 so the same thing we are doing above let's you can can copy and paste the expires from the one above so it will expire in one hour and let's get the existing token using await get password reset token by email and passing the email from the prop like that if we have the existing token in that case let's await database. reset pass sorry password reset token. delete and let's delete the one which has a matching ID of the existing token. ID which we which we just found using the email that was sent meaning that the user already has a password reset token but they are requesting a new one and finally let's create a password reset token here using await database password reset token do create let's give it a data of email token and expires so we have all the necessary information and simply return password reset token like that perfect so so now we have the ability to fetch the password reset token and the ability to generate a password reset token which is carefully going to look if we already have an existing one so we remove it on time and the last thing we have to do is we have to revisit our mail Library so in the lib let's go to mail here and it's going to be very similar so well let's write it again just to uh you know ensure our knowledge here so export cons send password reset email is going to be an asynchronous function which accepts the email which is a type of string and a token which is a type of string and in here let's write the reset link to be HTTP localhost 3000 slout Slash new password so this is a new route which we're going to have to create later of course and the same thing we pass in the token and stringify the token like that and then await resent emails send like this from onboarding at resent dodev to the email subject the subject is going to be subject is going to be reset your password and HTML we can copy from below so click here and instead of confirm your email it's going to be to reset your password so click here and instead of confirm link it's going to be reset link and instead of the confirm email it's going to be to reset password like that there we go so we have everything we need make sure you don't have any typos make sure that this exactly matches what you've been sending before later when we do deployment we can change this to go from whatever website or domain you want in production and make sure that when you're testing this you are sending this to that email which you have in recent great so now we can finally go back inside of our reset server action so actions reset here and let's go ahead and let's import send password reset email from lib mail and generate password reset token from lib tokens and in here we have a little too which we wrote so let's go ahead and write const password reset token is await generate await generate password reset token using the email which was entered in the form and then await send reset send password reset email and in here let's use password reset token. email as the first argument and password reset token. token as the second argument and whenever you do this all always double check that the first parameter is actually an email and the second one is a token so you don't have any unexpected bugs and I believe this should already be working so make sure that you enter the email which you can use from recent right here let me copy this and go inside of this button which we have right here forgot password make sure that your app is running let's send this right here and let's click resend send reset email and that should actually be sending me an email now so let's just wait a second there we go reset email sent and let's look at my inbox here there we go reset your password obviously if I click here it's just going to bring me back to login because we have to add that page and here's one more thing that we can check so I think my local my Prisma is not running so let's go ahead and run our npx Prisma studio and you can now see that we also have a password reset token which was generated and which was sent to that email so this is the token that is going to be inside of our URL being sent to this email perfect so we just finished the first step which was sending the email for a new password The Next Step will be to create this page which we defined inside of lib mail called out new password and in here it's going to be a very simple form which is going to uh well take in the new password that the user wants and also use this token to confirm that they have permissions to change their password great great job so the first thing we have to do is we have to enable this link click here to reset password right now it redirects us back to login so let's go ahead inside of our routes. THS file right here and instead of our out routes we have to add that new link so let's add slash out slash new- password like that so that's only going to be available for logged out users because logged in users will have the settings to change their password so it's different from this new verification where it can be used both by logged in and logged out users that's why this is in public route so you can be accessed if the user is already logged in uh great so just confirm that this slou new password is exactly the same as you're sending inside of lib mail right here so send password reset email should use slash out slash new password and then append a token query here so make sure that this exactly matches what you just wrote inside of this new out routs and then if you click inside of your mail here it should lead you to a 404 page but it should not redirect you great now let's go ahead and let's go inside of the app folder out and let's create a new folder new password then then inside create a new file page. DSX and Export default new password page and a div new password and there we go we now have a new password page perfect so obviously as always we're now going to go ahead and change this to use the new password form and now let's go ahead and let's copy the existing um which one should we use how about we copy inside of components out let's copy the reset form I believe that one is the simplest so copy the reset form paste it inside of Al rename the copy to new password form make sure that you are inside new password form so you can close the other one so confirm you are inside new password form and in here go ahead and rename this to new password form like that and then you can go back inside of app out new password where you have this error and let's import new password form from components new password form and it will look exactly the same as the one we just created for the resetting of the password so now what we have to do is we have to go ahead and modify it so first thing that I want to do is go inside of my schemas right here in the index let's copy this schema and let's rename it to new password schema and let's change this to be a password and let's go ahead and give this a value of minimum of six and then the message will be minimum of six characters required or what did we write before minimum six characters required all right exactly that so just the password field for the uh new password schema like that now let's go back into the new password form and let's import instead of reset schema new password schema so we're going to get errors wherever we are using the old one so in here in here and in here let's replace that with new password schema and now we have an error for the default values so that should be the password of course and inside of the onsubmit yes we have an error we're going to fix that later so now what I want to do is I want to modify the card wrapper here so the header label in instead is going to be uh enter a new password and this can stay the same back to login and we don't need to show socials here either inside of the form field let's change the name for this one to be password let's give this a form label to be password as well and let's go ahead and change the type to be password and the placeholder let's just give it five stars actually six stars like that and let's change the submit button to say reset password like this there we go what we have to do now is we have to fetch the token from our URL so inside of your url you should have the token if you clicked here from the reset password so your token should be appended just like it was for the verification if it's not go ahead and double check inside of your mail that you are sending send password set email with the token appended and confirm in the reset action when you await send reset send password reset token that should do a proper order of email and token if you want to you can also add a console log of the password reset token to see if something is going wrong inside of it and then de buug from there great so let's go ahead and let's import use search params from next navigation like that and let's go ahead and add it here so cons search params is use search params like this and then we can extract the token to be search pam.get token and we already know why it's token is because it's inside of our URL so just double check that you didn't misspell that inside of your url it should be token like this great so now we have our token Here and Now what we have to do is we have to create a new server action to handle this so let's go ins set of actions new one new password dots like that Mark it as use server and let's go ahead and Export con new password to be an asynchronous function which accepts the values which are a type of import uh everything s z from Zod so we need that and let's import new pack password schema from schemas so then we can write values is a type of z. infer type of new password schema and let me just not misspell type of and we're also going to pass the token from the URL which can be string or null like that and immediately if we don't have a token let's go ahead and return an error missing token like this great now we can use this new password in place of our uh new password form so instead of components out we have a new new password form here and instead of using reset action let's use new password import and let's import new password and then we can replace the onsubmit function to use the new password and besides sending uh values as you can see it also accepts the token so add a comma here and pass in the token which we extract right here from the search params like this perfect and we're going to fix this in a second so now I want to go ahead back inside of the new password here and let's go ahead and let's validate our Fields so const validated Fields is going to be new password schema. save bars pass in the values if we didn't get a success from validated Fields so just make sure you put an exclam Point here let's go ahead and return error inv valid Fields like that and then we can extract the password from validated fields. dat and now let's do some token validation here so const existing token is going to be await get password reset token by token so make sure that you import get password reset token from data password reset token and then we can use our prop to token which we pass in as the second argument here and we can see if we can find that token inside of our database so if there is no existing token we're going to return an error which is simply saying invalid token like this and now let's go ahead and check if the token has expired that's going to be await get uh sorry no is that's going to be new date right existing token. expired is less than the current new date so if it has expired we're going to return an error token has expired like that and it's not expired it's expires like this and let's now go ahead and check the existing user which matches the password we're trying to reset for so await get user by email from data user so make sure you import get user by email from data user we're going to use uh we're going to use existing token. email like this if there is no existing user let's go ahead and return an error saying user actually email does not exist so for whatever email we sent this token to reset the password no longer matches what we have in our database great and now what we can do is we can finally have the new password and update the user so for that we're going to need to import bcrypt so you can use either bcrypt or you can bcrypt or you can use bcrypt JS I'm going to use JS because I found to have less problems with that so let's go ahead and let's hash the password in here so con hashed password is going to be await bcrypt do password which we pass from our fields and the salt is going to be 10 and then await database so make sure you import database from lib database. user. update where ID is existing user. ID and data is simply going to update the password to be the new hashed password and then await database. reset uh password reset token. delete where ID matches the existing token do ID and finally we can return a success saying password updated there we go and because we added the success here we no longer have that error here for data. Success so if I'm correct this should be working uh just fine but I believe my token might have expired already so here's what I'm going to do first first let's clear our URL so let's just try what happens if I do new password without any token at all so technically we could already you know redirect the user from here but I want to see explicitly what happens if we try to reset a password there we go missing tokens so we are not allowing this to reset any password great and now let's go ahead and let's use the email from recent to send a new email here so let's copy this uh this one tutorial mailing send reset email and should send me a new email any second let's go ahead and check my inbox there we go reset your password and when I click here it asking me for a new password so my previous password was 1 2 3 4 5 6 so this time I'm going to try 6543 2 1 let me just confirm that I entered that correctly 654321 I will click reset password and that should just tell me that I have successfully resetted my password there we go so if I go back to log now and if I try this with my old password 1 2 3 4 5 6 like this it should tell me invalid credentials perfect but if I try 654321 it should allow me to log in because I already have this email verified uh regardless if you have the email verified or not right you will not even get that uh message otherwise perfect so we successfully implemented the forgot password functionality inside of our application and I just want to confirm directly in my Prisma Studio that this is happening so I'm going to close everything besides uh my user here and let's go ahead I just want to show the password I don't want anything else like this so I just want to take a look at the hashed password here you can see how it looks now so what I'm going to do let me just I have too many tabs open so what I'm going to do now is Click forgot password again I'm going to send another image another message to this so send reset email and there we go so this one took a bit longer for me but still it successfully res sent the reset email and there we go I have a new password here so let me click this link and now we're going to focus on the password hash right here and see if we can notice it changed so now my password is 654321 so I'm going to change this to uh I don't know new password password like that and click reset password and once this succeeds let's go ahead and refresh our password hash I don't know if we're going to be able to notice any change here I'm not sure there we go you can see how it clearly changed to a new hash perfect so it's officially updated in the database and if I try this again with my old password 654321 I should get invalid credentials but if I try new password I should should be logged in inside of my application there we go we successfully implemented uh the reset password functionality the last thing that we have to do regarding this login screen right here is uh two Factor authentication great great job all right so to implement two Factor authentication let's go ahead and let's visit our Prisma schema right here and let's find the user model here and let's go ahead and add a new field called is to factor enabled that's going to be a type of Boolean with a default value of false so this is going to be used to decide whether to send the user the two Factor token when they try to log in and another field we're going to create is a relation with two Factor confirmation model which we're going to create so two Factor confirmation is going to be a two Factor confirmation model relation and it's going to be optional put a little question mark at the end and now we have to create this model but before we do that let's create the two Factor token which will be sent to uh the user's email so this one will be exactly the same as our password reset token and our verification token I just want to keep them in separate models so let's call this one two Factor token it's going to have an ID of string and a default value of Cu ID email which is a string token which is a unique string and expir which is a date time and a unique combination of email and token and now let's create the two Factor confirmation model model so model two Factor confirmation is going to have an ID of string ID and a default of Cu ID and it's going to have a relation with the user ID so that's going to be a string and a user is going to be a type of user relation Fields user ID reference ID and let's add on delete Cascade so if the user model gets deleted we're going to go ahead uh and also delete this two Factor confirmation if it exists uh and let's also go ahead and add at at unique user ID like that there we go so make sure that you add the user relation here with the user which we have not here right here so we have two Factor confirmation to this model yeah and make sure you add the unique otherwise you can see that we are getting a one to one relation must be unique field or something else like that so unique user ID or I believe you can also add unique here I think it's the same thing yeah but I'm going to use this method here great so make sure you add this and now let's go ahead and let's reset our database so everything is clear so shut down the app let's run npx Prisma generate so we add those new models inside of our no modules and then let's do npx Prisma migrate reset to remove everything inside of our database here and let's confirm this like that and then let's go ahead and run npx Prisma database push like this so this will push the new uh models inside of neon database and after you've done that you can do npm run Dev and if you want to you can also do command shift p and reload your Visual Studio code window so there's no any cache then refresh your Local Host here and it should still work just fine and let's also prepare the Prisma studio in another terminal so MPX Prisma Studio that's going to open it on Local Host 5555 and let me just enable all the fields to be visible and there we go you can see how I now have is two Factor enabled and two Factor confirmation here I'm going to go ahead and create a new account using my tutorial name mailing gmail.com so use the mail which can send the email tutorial mailing gmail.com one 2 3 4 5 six I'm going to create an account so we're just testing whether the rest the rest of our application is working fine there we go so confirmation email was sent there we go confirm your email I'm going to click here and that's to confirm my verification there we go this is the little bug that we have but only in development and now I believe if I go ahead and use tutorial mailing gmail.com here 1 2 3 4 5 6 and click log in I should be able to log in just fine great and now let's go ahead inside of my Prisma studio and let's refresh this user and by default I should now have a value of is two Factor enabled false and I I can only change it to true and we have the potential relation with two Factor confirmation which right now you can see does not exist great so now what we have to do is we have to create the uh tokens the data and the email for two Factor token right here so let's go ahead and do that so let's go and close everything let's go inside of data and create a new file uh to factor token. DS let's import the database from / Li database and let's export cons get to factor token by token to be an asynchronous function which accepts the token which is a string let's open a try and catch Block in the catch we're going to return null and in here let's get the two Factor token by using a weight database two Factor uh two Factor token not confirmation but find unique where we have a matching token and return to factor token like that and then let's copy and paste this let's rename this one to be get to factor token by email and in here let's get the asynchronous email and let's use find first and get the matching email like this there we go great now let's go ahead and also create a data for two Factor confirmation so two Factor confirmation .ts this one is going to be a little bit different a little bit simpler so it's only going to have one method called get to factor confirmation by user ID so it's going to be an asynchronous function which accepts the user ID which is a type of string let's open a try and catch block here and return return null in the catch and in here let's get two Factor confirmation by using await database. two Factor confirmation find unique let me see if I can expand this even further uh okay basically in one line like this find unique where we have a matching user ID so no need to use the email or the token here because in our schema we have an actual relation with the user so we know this confirmation is tied to the user so we can use the user ID directly and let's return two Factor confirmation like that that's all we need for two Factor confirmation here now let's go ahead and let's go and generate uh create a lib to generate a two- Factor token so for that we're going to need a package called crypto and I believe it already exists in the node ecosystem so you won't need to install anything at least I don't so I can just do import crypto from crypto you can see how it autocompletes and I didn't need to install any package so if you take a look at my package Json I don't have crypto anywhere installed right so you should just have this uh in by default and let me just import crypto actually uh great and now let's go ahead and let's also import get to factor token by email so make sure you add that which we just created in a second ago and let's go well we can do it at the top actually here so export const generate to factor token it's going to be an asynchronous function which again accepts the email to where we send the actual token and in here let's go ahead and generate the token but this one's going to be a little bit different because I I want it to be a six-digit number so we're going to use crypto do random integer and in here we're going to write 100,000 and here's a little tip for you when writing numbers in JavaScript if you're having a hard time you know seeing seeing how many zeros they are you can add underscore like that and this is still going to be the exact same thing if we wrote 100,000 directly so this is the same thing but it's easier to see what it is so 100,000 so this is going to be the start of our range and the end of our range is going to be 1 million like that to string and let's write the uh expires so it's going to be new date new date get time plus 3,600 * 8,000 so it's going to expire in an hour let's see if we can find an existing token by using a wait get to factor token by email and let's use the email which is passed in the props here if we have an existing token in that case await database. 2 Factor token so not confirmation but token be careful do delete where we have an ID which matches the existing token. ID and then we can finally create a new two Factor token so con two Factor token is going to be await database two Factor token. create data and inside we can safely pass the email for the user to send the token which is going to be a six-digit code and expires for when that code expires like that and let's return to factor token so if you want to you know you can modify the expires for two Factor token I think it's fine for the password reset token and the verification to last an hour but if you want to you can use some different math here to make it maybe 15 minutes rather than an hour if this is too long for you right but for the tutorial I'm just going to use an hour but let me add a little uh to-do here l later change to 15 minutes just so you get reminded that you know if you actually plan on doing stuff like this in production it would be smart to make this uh expire a bit sooner great and now let's go ahead and let's create uh a mail Ule for this so inside of lib let's go to mail here and let's go ahead and Export con send to factor email to factor token email and let's make it an asynchronous function which accepts the email which is a string and a token which is a string like that and then in here let's add const uh confirm link to be HTTP Local Host 3000 uh slou uh actually no no we don't have the confirmation link here right my apologies it's just a token so the email is just going to be this is your your confirmation code and a six-digit number so let's just do await resend emails send from onboarding uh at resend. deev uh to email subject uh to FAA code and HTML open btics write a little paragraph here uh and it's going to be your 2 FAA code and stringify the token which we sent from the props that's it uh great so what we have to do now is we have to manually enable two Factor authentication for one of the users which we have in our database so make sure you have Prisma Studio running go inside of your user model here find the user which you have make sure it's registered using credentials so make sure that you verify the email for it and everything and change the value of is to factor enabled from false to true and click save one change here and wait for a second to this update and there we go now it should be true and you can of course refresh just to confirm that you have the newest value there we go is to factor enabled is now true so as you already know I can freely log in uh with this email as you can see I'm already logged in so I just signed out but I should not be able to log in that easily if I have two Factor enabled so it's one way to prevent that in login. THS which we are going to do but the first place I want to prevent it is in out. CS in the call back sign in which where we added to do add to factor authentication check so let's go ahead and do that so I'm going to add if existing user dot is to factor enabled in that case what we have to do is we well we can just easily return false first so let's check if that is working so I'm going to use tutorial mailing at gmail.com 1 2 3 4 56 and because I changed that to true in my database there we go something went wrong so I should not be allowed to log in if I have two Factor Ena but you know this isn't exactly useful because once they confirm their uh their token how exactly are we going to allow them to log in where are we going to use that first by importing get two Factor confirmation so import get two Factor confirmation by user ID like that and I'm going to use the add sign so import it from data two Factor confirmation so don't accidentally use two Factor tokens here in here we need the confirmation so what we're going to do here is for now remove the return false and instead let's go ahead and see if we have the confirmation so con two Factor confirmation is going to be a get two Factor confirmation by user ID and pass in existing user. ID like this great uh and let me just expand this so we can see this basically it's all in one line like that it's a long line and now if we don't have two Factor confirmation then return false otherwise I'm going to add a comment delete to factor confirmation for next sign in obviously this is my choice of doing this right so every time the user logs in uh if they have two Factor authentication I'm going to go ahead and delete the two Factor confirmation for them so the next time they log in they have to do the same thing over again if you want to you can of course modify that by going inside of schema Prisma here and for example you can add expires field here as well to be a date time so I'm not going to do this in this tutorial but I'm just giving you some tips you can do that if you want to and you know make it work exactly the same as it would with our other tokens so when you uh go ahead and generate the two Factor uh confirmation where is that uh oh we don't generate it yet so we're going to do that later in there you can add the expires in maybe I don't know two days or something like that uh but I think it's safer for two factor to be very strict so that's how I'm going to do it so if the user successfully logs in and they have two Factor confirmation in that case let's do await database. two Factor confirmation. delete where the ID is two Factor confirmation. ID as simple as that and then uh we can go ahead and well we don't have to do anything because we have return true at the end so if it skips this this that means that the other one is true so just by adding this code I should still not be allowed to log in because because I shouldn't have the two Factor confirmation so I'm going to add a conso log two Factor confirmation and I'm going to log that inside of an object so it's easier to see so let's check it out if I go inside of my terminal here let's go ahead and click login again and I should see undefined for that value let's scroll above the error here uh or null there we go so you can see the object here let me just scroll up again again there we go so it's right here two Factor confirmation is null and because of that we do an if if there is no two- Factor confirmation we prevent the user from logging in perfect that is exactly what we want I'm not allowed to sign e and I shouldn't be so what we have to do now is we have to improve the behavior which happens when user clicks login here they should not get an error because they have to factor authentication Instead This should change from to be a uh code input which they will receive from their email so let's go ahead and do that now so what we have to do is we have to go inside of actions login right here so let's import uh generate two Factor token so generate two Factor token from lib tokens or we can reuse this one like that and let me collapse them there we go so make sure you have generate verification token and generate two Factor token and besides that uh I also have mail here great so we're also going to import send two Factor token email like that so make sure you have send two Factor token email and generate two Factor token here and in here what we're going to do is after we check whether the user has been verified or not but before we try to log in here let's add if user sorry existing user dot to is to is to factor enabled and if we have user. email sorry existing user. email in that case let's do cons two Factor token is going to be await generate two Factor token from uh existing user email and then await send to factor token email and let's use two-factor token. email as the first argument and two Factor token which is the six-digit code as the second argument and let's return a special object to factor to be true like that so it's going to break the function and it's going to give our front end a specific value so that we know we have to change the display right here so let's go ahead and try that out now so I'm going to go ahead and log in again and this time I shouldn't get an error instead it should just stay empty like this but I should get a new email there we go your TFA code and here we have a six-digit number perfect so now what we have to do is once the front end receives this value to factor to be true we have to modify this inputs so that we can enter that code so for that uh what we have to do is we have to revisit our schemas so let's go inside of schemas index. right here let's find the login schema and let's add a third field which is going to be code and this one is going to be optional so z. optional here and let's add z. string inside so very simple like that great and we can also add well actually no let's just leave it like this and now that we have added that make sure you did that to log in schema we can go back inside of components out login form right here and in here let's go ahead and let's add a new state here so above the error let's go ahead and let's add uh show to factor and set show to factor and use state by default is going to be false like that and then let's go ahead and modify our onsubmit function a bit so inside of here I'm going to do the following if I have data question mark error I'm going to reset the form so we have some better user experience here and I'm going to set the error to data. error then if I have data success I can also reset the form and I can set success to data do success and last one here is going to be if data has two factor in that case we are not going to reset the form because we need the credentials that user just wrote and then set show to factor is simply going to be true like that and we can also add a little do catch here so in case anything else goes wrong let's set error to be something went wrong like this great and now what I want to do is I want to display a different form field if we need to show two Factor so let's go ahead and change this and let's let's go ahead and wrap this this form field and the password form field so the entire thing like that and let's go ahead and wrap it inside of a fragment so go here because there's two items so they need to have a parent like that and let's just go ahead and indent those like this so two of these elements should be inside of a fragment and then we're going to go ahead and give this a conditional if not show to factor then go ahead and render those and you can wrap them in parentheses if you like I'm going to do that as well there we go so we are going to render the form field password and the form field email where is it right here only if we didn't get the two factor from the back end and now let's do the opposite one so if we do have show to factor in that case let's just go ahead and copy and paste an existing form field like email here so copy this one and let's paste it inside and let's go ahead and give it a name of code and let's give this two Factor code label let's change the placeholder to be 1 2 3 4 5 6 and let's change the type and we can just remove it and let's also give it oh it already has disabled is pending great so let's take a look at it now so if I use tutorial mailing at gmail.com now and try to log in I should receive two Factor true and this should change the input for me to enter my two Factor code there we go and I should be getting a new email here with my new two Factor code so now we have to find a way to enter two Factor code here so that next time we click login uh we actually verify the code and I also want to change this uh label here so I'm going to go ahead and find where I wrote login I'm going to change this if show to factor in that case it's going to be confirm otherwise it's going to be login so this should now say confirm perfect but if we just enter the code and confirm it's not going to work uh so what we have to do is we have to go back inside uh of our login action so inside of actions login right here and let's find where we destructure the fields so validated fields. data here at the start besides destructuring the email and password we can also now destructure the code which might or might not exist right so here's what we're going to do inside of this if Clause where we check for two fact token and we send the two Factor token email we're going to do the following so in here I'm going to add an if Clause if I have the code to do verify code else we're going to send the to factor code like that so that's how we're going to differentiate if the user just pressed on log in or if the user uh logged in again but this time provided us with the two Factor code so we can do that check inside of here so let's go ahead and do that the first thing we have to do is we have to import get two Factor token by email using data two Factor token like that uh all right and let's go ahead inside of here in this to-do and let's go ahead and see uh con two Factor token that we have saved in our database for this user using a wait get two fact Factor two Factor token by email using the existing user. email so we know what's the code so what we're going to do is if there is no two Factor token we're going to return an error invalid code and then if two Factor token. token is not same to what the user just wrote in the code field we're also going to return an error saying invalid code and then what we can do is check if the code has expired so has expired is going to be new date to factor token. expires is less than new date from now so if the token has expired regardless if it's correct or not we're going to return error code expired great and then finally we can remove the two- Factor token and we can create the two Factor confirmation so that user can finally log in so let's go ahead and write a wait database. 2or token. delete where ID matches two Factor token. ID and let's go ahead and import DB so I don't have that so import DB from s/l database so first we're going to go ahead and delete this one and then let's go ahead and see if we have an existing confirmation so const existing confirmation is going to be await database uh two Factor confirmation. find unique actually you know what we can use we can use get to factor confirmation by user ID corly right we have that Ule so go ahead and import get to factor confirmation by user ID from data to factor confirmation so in here let me zoom out we're going to pass in the existing user. ID or I can separate that like this there we go so get two Factor confirmation by user ID if we already have an existing confirmation we're going to go ahead and remove it from here as well so get to factor confirmation. delete where ID matches existing confirmation. ID like that and once we've done that we are finally ready to go ahead and do await database two Factor confirmation. create where sorry data user ID to be existing user. ID and we're not going to return anything because what we want is to create the two Factor confirmation this else is going to be skipped and then what we're going to do is try and log in and because we are going to create the two Factor confirmation just before we try to log in the next time the user goes ahead and triggers inside of out. THS the signin callback guess what we're going to be able to find two Factor confirmation and this is going to be skipped and we're going to delete the two Factor our confirmation and we're going to return true so let's go ahead and test that out so I'm going to go ahead and go back to my login page here I'm going to repair my emails I'm going to use tutorial mailing gmail.com I'm going to log in here this will send my two Factor token on my email so let's just wait there we go there we go tofa code I'm going to copy this code I'm going to paste it here and I'm going to to click confirm this time with a code and let's see if that's going to allow me to log in now let's wait a second and there we go we are officially logged in and we confirmed our two Factor authentication and inside of my Prisma Studio I should not be having uh any two- Factor confirmations so you can see that this no longer exists so if I log out and log in I'm going to require that again and let's go ahead and look at two Factor token they don't exist either like that so if I go ahead and try this again so tutorial mailing gmail.com 1 2 3 4 5 6 and if I go ahead and log in I'm going to be prompted with two Factor again and if I refresh on the two Factor token here we now have a two Factor token and we can see what is our secret six-digit number here we still don't have any two Factor confirmation but I do have a new code here so let me copy this let's paste it here let's confirm it like that and what this is going to do is remove my two Factor token and it's also going to create and then immediately remove my two Factor confirmation so we actually didn't even see but this definitely existed for a second before it was immediately removed by the loging callback and there we go the old two Factor token has been deleted and let's try one more thing if I go back inside of my user here and change is to factor enabled back to false and click save changes here and if I sign out now and if I try this again tutorial mailing gmail.com 1 2 3 4 56 this should allow me to log in Freely without having to enter two Factor authentication there we go so I recommend that you keep it like this for now just so you can easily log in and log out perfect so we just wrapped up everything we needed for the out screen here what we're going to do next is we're going to create the actual inside screen where we're going to have an example of a server component and how we can fetch the currently logged in user a client component and we're also going to have the settings page where we can change to new email and to new password and don't forget we also have to come back inside of our login button here and enable so that we can change the mode to a dialogue instead of redirecting to this screen great great job so just before we create the inner page let's go ahead inside of our lib tokens. DS here and let's go ahead and do this to-do which says change to 15 minutes but I don't want to do 15 minutes I actually want to do 5 minutes to improve the security even more so we just have to change to 5 * 60 * 8,000 which will turn into milliseconds representing 5 minutes great so now what I want you to do is I want you to go ahead and log in using uh your credentials like this so let me just log in and I don't have my two Factor enabled so I can just freely log in and we already know how we can get the current session ins set of app protected settings page by using a weit out but what if we want this to be a client component how will that work exactly so let's go ahead and remove a synchronous from here and let's change this to Simply be an empty object and then let's go ahead and Mark this as use client and we also have to remove this action from our form we can no longer use that and we can also remove this Imports like that there we go so now we have well a pretty much unusable settings page here so what we have to do is we have to add use session from next out react so that's how you can use the session in client components but if you click save here you're going to get an error that use session must be wrapped in a session provider so we can do that inside of our app layout right here but keep in mind you don't have to do it in the layout file so if you only want one part of your application to be wrapped inside of that provider you can do that here you can create a layout in the protected and we are going to do that later we're going to create a layout here so perhaps you can wrap it there but you know it really doesn't matter for this tutorial so now let's go ahead and let's import the session provider from next out react and let's also import out from at SL out and then in here let's turn this into an asynchronous function let's get this session using await out and then let's wrap our entire HTML inside of a session provider and let's go ahead and pass the session to the session like this and then once this refreshes there we go you can see that we have the exact same thing we had before but this time using a completely different method so our settings page is a client component which uses use session but one thing that is still not working is the sign out button so I'm going to show you two ways that you can do this the simplest way in a client component is to also import a sign out from next slou react and then you can add const on click here sign out and then simply well we can remove this form now and give this button an on click onclick like that so if I try and click sign out now there we go I am signed out and I'm going to show you another method that you can use which is the combination of a client component and server actions so you can do this if you want to you can go inside of your action and create a new file log out. DS mark this as use server import sign out not from next out react but from SL out and Export const log out and in here await sign out so we have to turn this into an asynchronous component so why would you want to do this well this is if you want to do some server stuff before you log out the user right so some server stuff right uh and you know that's what is cool about server actions because this leave completely separated from the JavaScript bundle so you can do some stuff like I don't know clearing some information about the user removing the user whatever you want to do before you log out the user so that's another way you can do that and then what you can easily do here is simply import that logout from the actions logout and then you no longer need this like that so you can try that out sign out and it's still working great so now what I want to do is I want to bring your attention to this use session hook right here and you can see that in order for us to access the currently logged in user we have to go tot data and then do user right so that can get pretty annoying so every single time we need the user we would have to write session. data question mark. user every single time we would have to do this just to only get this information which we need from the user which is the role the ID the image and the email and the name so what I want to do is a reusable component sorry a reusable hook called use current user so let's go ahead and do that in the root of your application create a new folder called Hooks and then inside create a new file use current user. DS in here import the use session from next out react and simply export con use current user and let's go ahead and get this session using use session and we are simply going to return session. data user so we don't have to write that every single time and I'll go back inside of app protected settings page and instead of using session change this to be the user and use current user from hooks use current user and you can remove this import from here and then simply stringify the user there we go so we just created a reusable hook which we can use in every single client component to quickly get access to the currently logged in user with their ID their role whatever we want perfect so now what I want to do is I want to go ahead and create uh we'll style this a little bit better right so I want to go inside of this app here uh settings and let's go ahead and uh well for now remove this stringifying Json let's just leave the sign out button and let's create a class name here to be BG white padding T and rounded Excel for example so it's not really visible now but it is going to Vis be visible when we create a layout inside of this protected folder so go ahead and create layout. DSX right here let's go ahead and Export the protected layout let's get the children let's just not misspell children and inside of here I'm going to add a div and simply render those children now the errors should go away and let's create an interface protected layout props to get the children which are type of react. react node so we can simply assign that here protected layout props there we go so now I want to go ahead uh and change this layout a bit so give this a class name of H full with full Flex Flex hole and GAP y10 and let's also give it items Center and justify Center and then you can go ahead and give it any background color which you like for example this one or I'm just simply going to copy the one that I have uh inside of my out layout here so it's that nice gradient right here I'm going to copy that and replace it here of course that's not important for this tutorial great so now we have that what I want to build now is the Navar component so I'm simply going to prepare it here above the children and write nbar like this and obviously it's not defined so we're going to get an error so let's go inside the protected folder and create a new folder underscore components and inside of here a new file navb bar. DSX so the reason I'm putting it here and the reason I'm using this convention well the reason I'm using this convention is because I'm writing this inside of the app folder meaning that anything inside of a folder can easily become a route if I accidentally name a file page so this is a good convention for you to use as I explained in my second chapter of this tutorial where we went over all different kinds of folders that exist in nextjs and I'm only going to use this nav bar inside of this folder so that's why I'm not putting it here in the components it's not exactly reusable so in here let's go ahead and let's mark this as used client and let's export p navbar and let's return a div navbar component then you can go back to your protected layout here and import the navbar component from / components Navar and there we go you should no longer be getting any errors instead you should clearly see the Navar component perfect so now let's go inside of this Navar component and let's go ahead and create some items inside so first of all I'm going to give this a class name of BG secondary Flex justify between items Center adding four rounded extra large width of 600 pixels and Shadow SM so I'm not going to make this inner content responsive that's not the point of this tutorial right this is just something to demonstrate how we can use our current session inside of different types of components and this specific component is simply going to be used to navigate the different items and to have a little user button from where we are able to log out so inside of this nav bar our component create a div with take class name flex and GAP X2 and then here outside of that div render a paragraph user button so this is where our user button will be which is going to be a reusable component which we're going to create very soon so inside of here let's go ahead and let's import button from components UI button and let's import link from next SL link but I believe that is a default export like that uh and let's also import use path name from next navigation so that we know where we are so let's get the path name here use path name and now we're always going to know on which page we are so if I go ahead and add a button here and let's go ahead and give it an as child prop inside let's add a link component and then HRA to go to/ settings where we currently are and a text settings there we go we now have a button which will lead us to the settings page which we are currently on and now what I want to do is dynamically change the variant of this button just to Simply indicate whether we are on this page or not so I'm going to write uh variant is going to check if the path name is slash settings in that case it's going to be default otherwise it's going to be outline like that so it's all in one line like this and you can see that nothing changes because we are on that page so now I'm going to copy this button here and and I'm going to put it as the first button and this one is going to check if we are uh on a server component example and let's change this to SLS server and change this to server as well and there we go you can see how now we have a server navigation here if you click of course you're going to get a 404 because it does not exist so let's copy and paste this button as well and let's change this a new one to go to SL client and check for the client component so this is where we're going to put our server component example this is where we're going to put our client component example and the last one is going to be our admin so let's change this to slash admin admin and admin like that so very simple we're not going to complicate it any further than this and now let's create a reusable user button component but before we do that one I want to create a reusable log out buttton so let's go ahead and go inside of components out and just as we have the login button it would make sense that we have a log out button so we can reuse that and wrap it around anything that we want so let's mark this as use client and let's create an interface log out button props to have optional children and Export const log out button let's assign those so log out button props and let's simply extract the children and then in here I'm simply going to call on click and I'm going to import that log out from my actions which we've created in the settings page right here when I demonstrated you an alternative way of logging out so you can use this method or you can import sign out from next out react and then called sign out here it's exactly the same right but this actions method allows you to do something on the server side before you log out the user so I'm simply going to use that just to show you different ways of doing things and in here we're simply going to return a span which will render the children and on click is going to be on click and let's give it a class name of cursor pointer great so now I want to create a reusable user button component which will use this log out button around one of the fields uh when we click on our image so let's go inside of our terminal here and let's go ahead and run the following so let me just zoom out let's add npx shat cnii latest add drop down menu so we're going to need this uh to open up the menu when we click on the user button right so we'll wait for this to install and besides this we're also going to need an avatar component so make sure that you have the drop down menu and the Avatar inside of your project and now let's go ahead and let's go inside of components out and create a new file user button. DSX right here so inside of this component here let's mark it as use client and let's go ahead and let's import everything we need from add components UI drop- down menu so in here we need the drop down menu itself we need the drop down menu content we need the drop- down menu item and we need the drop down menu trigger so we can open it by clicking on something and let's also go ahead and prepare all the Imports we need from components UI Avatar so basically those two new components which which we've just added so Avatar Avatar image and Avatar fback like that great and now let's go ahead and Export const user button here and let's go ahead and return a div user button and now I want to add it inside of our reusable well not reusable navbar components inside of protected components navbar instead of rendering a text user button let's import the user button component from components out user button and it's going to be a self closing tag so import the user button button from here go back to the user button and now we can clearly see what we are developing right here great so let's change this to be a drop down menu and now let's add a drop- down menu trigger and inside of here we're going to go ahead and add an avatar component so let's add an avatar component let's add an avatar image component which is for now simply going to have an empty source and let's add an our our fullback component like that and inside you can write you know uh anything you want if the image doesn't load or you can put any icon for example we can import fa user from react icons fa so if I render fa user here there we go you can see how we have a little user icon so let's give this out our fullback uh a class name of BG Sky 500 and let's change this to class name name text white there we go so it matches our background if you want you can also put that gradient that we reused a couple of times in our project great so now in order to fill this Avatar image source since this is a client component we can use our reusable hook so con user is going to be used current user and there we go we now have access to the user so we can write user question mark. image or undefined like like that and you can see that nothing has changed because obviously I don't have any image inside of this user but we are going to test out GitHub and Google login so you can see how the image is automatically going to be shown here so now go outside of the drop down menu trigger and let's create the drop down menu content which is very simply going to use our reusable logout button which we just created so I'm going to change this UT to go to components out because I like to be consistent and to indicate that this is a set of reable components which we store in this out folder here great and inside of this log out button we are very simply going to use the drop down menu item and write log out like that so make sure that you have the drop down menu item here and now when you click on this there we go you have the option to log out uh and let's go ahead and just align this content a bit better so let's give it a class name of width 40 and align of end and you can also add a little icon here so you can use react icons you can use radic icons you can use Lucid whatever you want so I'm going to use radx um icons radx UI react icons because I have that installed if you have lucid uh Lucid icons you can use Lucid react I believe it doesn't matter and let's go ahead and simply add an exit icon here and let's just style it a bit like that and there we go you can see how now we have a log out button which is working and if I try and log in with my social right now so I pressed on GitHub here that will log me back in and there we go you can see how I have my image loaded right here perfect so we just wrapped up the beginning of our inside application here what we're going to do next is we're going to create an example of server component so how to use all of these Hooks and stuff in servers how to use that in client how to handle admin stuff and lastly we're going to modify this settings page right here great great job so now let's go ahead and let's create our server example so in this example I'm going to show you how to fetch the current user using a server component and how to fill some information so let's go inside of the app folder protected and let's create a new folder called server and inside of the Server create a new file page. DSX let's go ahead and export the server page and let's write server page inside and now when you click inside of your n bar here you should be redirected to the server without 404 just confirm that your url is SLS server make sure that this folder name is server make sure in your NV bar that you are redirecting to SLS server in the HRA here and that your path name is matching great so we already know how to fetch the session right so we have to mark this as an asynchronous function and then we do session and then we do await out from at SL out and then inside of here what we can do is json. stringify and paste that session inside so we already know how to do that we can see the information here but we have the same problem if we want to get just the user we have to go to data and then we have to fetch the user is it session. user or this right so you can see that we still need an additional step here so let's go ahead and improve that by creating a reusable lib for Server components just as we created a reusable lib for client components uh let's go ahead and create a reusable lib called out. DS inside of the lib folder and in here let's go ahead and let's import out from at slou and let's export con current user to be an asynchron function which will oh make this an arrow function which will get the session using a wait out and simply return session. user like that and then we can go back to our server page and in here so it's located in app protected server page and in here instead of using this we can use user to be await current user from lib out and we can remove this import and then we can use the user inside like this and there we go now we get just the user like that so you can see the difference is that when we're using this out we have session question mark. user but when we use use session from next out react we use session. data. user so in case this changes in the future you know you never know uh you can try it yourself maybe it will change to user right but for now for me it's data and then user like that great so now we have this and what we can do now is we can create a reusable component called user info so you can put this pretty much everywhere um you can create it inside of this components you can create inside of this components I don't know I'm just going to put it inside of out even though it's not exactly reusable for out so perhaps simply put it inside of components it really doesn't matter so user info. DSX and this is going to be an agnostic component so we're not going to define whether this is a client or server component we're not going to care it's going to become either server or client depending on the parent so if the parent page is a server component and if you import a component which doesn't have anything defined that component will also be a server component but if you import it inside of a page which has used client at the top then the component will automatically become a client component right so for now make sure that the server page doesn't have the used client and we're not going to care about what this is and let's go ahead and create an interface user info props and the optional user which it can accept is going to be our extended user from at/ next out so if you remember we have this uh next out DTS and in here we export a type extended user where we assign the role right so then we can use that as the expected type here so we don't have to manually write you know user and and and extend the role manually we can just reuse this all right so it's going to accept the user and an optional actually a required label which is a string and let's export const user info here and let's go ahead and destructure those props so user info props we'll accept the user and the label and let's go ahead and return a card from /ui card which we already have installed or components UI card however you want it let's render this card and let's render the card header from components UI card as well so make sure you add this import and inside we're going to add a paragraph with a label and let's give this a class name of text to excel font semi bold and text Center and now let's go back to our app protected server page right here and instead of rendering this let's render user info from components user info as I've added this expert here and let's go ahead and pass in the user to the user and let's pass in the label uh to be for example server component like that and if you want to you can add a little uh Emoji here let me just open this up for example we can use a laptop or something like that so server component and there we go now we have a label that this is a server component great so let's go back inside the user info and let's actually develop this so I want to give this card a class name of width 600 pixels and a shadow of medium just so it looks a tiny bit better so it matches our navbar here and now we're simply going to render a bunch of information for the user so you can see that we can easily access all of that so below the card header add the card content which you can import from here so yeah I mean you're you're practically done with everything that we have to learn about out all I'm going to teach you now is you know how to render that information and how to render you know admin stuff for example we're going to create some reusable components for the admin but yeah if you're just looking at how to create the login and stuff you're done yeah you don't have to watch further but if you're interested in stuff like this you know continue watching so we have space y4 here and now let's create a div with a class name here Flex Flex row items Center justify between rounded LG border padding three and Shadow small and inside of here we're going to create a paragraph representing what we are trying to show so this is going to be an ID of the user which is going to have a text small and font medium like that and then we're going to create a paragraph here which is going to render user. ID like that and there we go we have the user ID here so let's go ahead and give this a class name of truncate in case the ID gets long text extra small Max width is going to be 180 pixels font is going to be mono padding is going to be one BG slate 100 and rounded medium there we go so now we have a nice little representation of our ID here and now we can just copy and paste this entire div and render the next item which is going to be the username so user.name right here there we go we have the name and what I recommend you actually do for now is log out if you're using an O out and go inside of your credential login because we're going to have to show different things depending on whether we're logged in as credentials or as something else so let me try this again so I should be redirected to the settings page and if I go to the server here there we go I can see my new name and everything perfect so let's go ahead and copy and paste this again so this one is going to be our email and it's going to render user. email here there we go we have the email and let's go ahead and copy it again this one is going to be our roll so we can get user. roll here there we go you can see how it says user here and let's go ahead and do the last one which is going to be our two uh Factor authentication like that and inside of here we're going to render uh user is to factor oh so we we didn't extend the user to have the status of two Factor authentication here so for now let's simply write off like that [Music] uh and let's go ahead and go inside of our out file so we can extend uh the callbacks here right so we need to extend the token and we need to extend the session here to accept whether the user has two Factor on or off so we can render that so we can easily do that by adding token. is to factor enabled to be existing user is to factor enabled like that and then in here we can copy and paste this and check if we have token is to factor enabled and if we have session. user in that case let's go ahead and add uh user is to factor enabled is going to be token is to factor enabled like that and let's actually just check for session user because this can be be false right so we don't want to mess that up so all in one line like this and now obviously we have to go uh back inside of our next out. d. Cs and add the is to factor enabled to be a Boolean like that and then we can change this to be as Boolean like this and now the errors are gone and you can see how the our session. user now expects the property is to factor enable great so now let's go ahead and let's go back inside of our app protected server oh sorry no components user info here and then in here we can check if user is to factor enabled on otherwise off like that perfect so let me just style this is to factor enable if you can if you want to you can leave it like this what I'm going to do is I'm going to add a new component from shaten called badge so npx shaten UI latest ad badge like this and then I'm going to go ahead and import the badge from /ui badge or components UI badge and then in here instead of rendering it uh inside of a paragraph here what I'm going to do is rer under a badge so we have like a clear indicator so variant if user is to factor enabled we're going to use success otherwise destructive and I think we don't have the variant success so we are getting this error here so what we have to do is we have to go inside of the badge component so inside of your components UI badge right here let's simply add a new variant here so success is going to be border transparent BG Emeral 500 and text primary foreground and then inside of your user info you will no longer have an error for the success variant because it can exist so make sure that you add it success and that you wrote success here like this there we go so you can see how now it says off like it's a danger thing so let me just see if I have my Prisma Studio running I don't so let me go ahead inside the terminal here and run npx Prisma Studio like this and I'm going to find my user here and I'm going to go ahead and enable two Factor authentication for this user so true save the change and once I refresh here there we go you can see that now two Factor authentication is on perfect perfect so that's it we finished an example of how to you know use user data in a server component so basically all we need to do is we need to use our hook not our hook sorry not in the is it server here yeah so await current user our lib current user which gets the session like that as easy as that now let's go ahead and copy This Server component and paste it here and rename it to client and what we have to do now is we have to replace this with client page and we have to mark this as use client so this will be a client component that you have right and we we've already done this you know but I just want to explicitly tell you now so you can here use use current user like that and that's it that's absolutely it so when you click on the client here there we go we have exact same information and let's just change this client to actually tell you that it is a client component and let's use uh different icon like a phone for example there we go so this is a client component this is a server component and we can get the exact same information using different methods one with a hook and one with a lib perfect so we just wrap server and client components what's left is to create admin uh example where I'm going to create another reusable component called roll gate so you can specifically hide some content from a normal users by using that component uh and we're going to demonstrate an API call being protected for admins and a server action being protected for admins only and then lastly we're going to create our settings now let's go ahead and let's create an admin example so in order to do that we have to create the admin page so let me just reload my window I have some errors in the cache it seems and let's go and inside the protected here create a new folder called admin like that and inside of here let's go ahead and create a new file page. CSX and let's go ahead and let's mark this as use client and let's export const admin page here and let's return a div admin page like this and now when you click on the admin here uh oh my apologies so yeah whenever you're working with Pages you have to do export default like this there we go great now we have our admin page here and now what I want to do is I want to create separate hook and separate lib to directly fetch the role right so let's go ahead and do that first since we marked this as used client let's go ahead and go inside of our Hooks and let's create use current roll. THS so if we don't want to fetch the entire user well here's the thing we are not fetching the user here we are simply decoding the session so that's important to know you're not making any any unnecessary API requests but you know just in case you want a specific hook to get the rooll you can do that as well using the exact uh same method so what you have to do is import use session from next out react and Export con use current rle like this get the session to be used is session and then simply return session. data user rooll like that that's it and then you can go back inside of that admin page and in here you can get the role using use current row and I can then write current roll is going to be roll and there we go current role here is user perfect effect and let me now show you an alternative way of doing it by uh creating the lib for this so let's say this is a server component for that you would go inside of the lib here inside of out and similar to use current user this will be current role for example and it will directly ask for the rle that's it so that's how you can create you know reusable uh Hooks and Libs for out so let's remove use client from here let's make this an asynchronous function and let's go ahead and await current roll from lib out and as you can see no errors and we are officially able to fetch this both in server and in client components now perfect so I think you've mastered you know how to create custom Hooks and rolls now so now we're going to demonstrate uh how to actually create a reusable component which will protect specific content from some users so let's go ahead and style this page a bit so let's import card from components UI card and I'm simply going to bring this back to use client because I want I want to work with client components for this so roll is going to be use current roll like that and I can remove this here great so let's go ahead and let's in this card let's give it a class name of width 600 pixels let's add a card from components UI card let's add a paragraph which is very simply going to use some Emoji here and write admin let's give this a class name of text to excel font semi bold and text Center there we go so we have a header for the admin page and now in here let's create a card content and in this card content I'm very simply going to add a class name space y4 and now I want to create create a reusable component called roll gate so you're going to see how that's going to look like and it might be useful you know if you're going to do a lot of stuff which is RO based AIS so let's go inside of components out and create a new file roll gate. thss it's going to be a client component which will have an interface roll gate props it's going to accept children which are react react node and it's going to uh have allowed rol to be a type of user rle from Prisma client so let's export con roll gate here let's go ahead and structure the props roll gate props we have the children and allowed roll and now let's get the current user role using use current uh role which we've just created and in here if roll is not allowed roll we're going to get go ahead and return you can return whatever you want I'm going to reuse our form error component from do/ form error or components form error and in here I'm simply going to pass a message which will say you do not have permission to view this content otherwise we're simply going to return a fragment which renders the children which will be allowed only for the specific role there we go so that's how you can create reusable component and hide some content from some users so now let's go ahead back inside of our admin page so app protected admin and I just want to tell you something I don't know if you know this or not but I hope I kind of made it clear um the only reason this is called protected is so I organize all of my routes inside of that it doesn't have to be called protected you don't even have to put it inside of this folder right I only do that so I can reuse the layout so I just want to make sure that none of you are confused by that so all of our routes are defined in here in routes. CS you can see that we don't explicitly tell what are the private routes all routes are private by default we only the uh tell the middleware what the public routes are so if you create something random in the middle of app folder that's going to be automatically a protected route you don't have to put that inside of the protected folder that just came to my attention I hope I didn't I hope I made that clear right so this protected is purely organizational this can be named absolutely anything all right hope I made that clear let's go back inside of the admin folder here and let's actually use that uh roll gate component so we actually don't need uh use current roll here at all you can remove that and let's go ahead inside of here and let's add roll gate component from components Out roll gate so make sure you add the import for roll gate here and inside you're going to write something that only admins will be able to see so for example I'm going to add a component here form success so I'm going to reuse it and I'm going to go ahead and write a message here to be uh for example you are allowed to see this content and now we have to Define which role can see that so allowed role let's import user role from Prisma client here as well so only admin will be able to see this and there we go since my role is a user I don't have permission to view this but if I go inside of my Prisma Studio here and if I change my role to admin and save this right here I hope I have my Prisma Studio running and if I refresh here there we go I am now allowed to see this content if I change it back to user and save there we go I don't have permission to view this content perfect so our roll gate is working and now I simply want to create uh an example to test the API route and a server action and show you how to you can protect something in there as well so let's simply create uh a div here with a class name uh Flex Flex row items Center justify between rounded LG border padding 3 and Shadow MD so just to make it a little bit stylish and let's add admin only API route with a class name of text small and font medium and let's add a button component from components UI button so make sure you add this import and in here I'm going to right click to test like that great and now let's copy this and paste it below and this is going to be admin only server action and this is going to be click to test as well great now let's go ahead and let's create both of them so first let's go ahead and let's create an adminon API route so let's go inside of our app folder and inside of the API here create a new route called admin or whatever you want and inside route. TS and in here let's export a synchronous fun function get and let's go ahead and by default return new next [Music] response with a status of 403 so you can use next response which you have to import from next server or you can just use response I'm going to use next response I believe the type the typescript is better for next response right so by default this will always return 403 so let's go ahead back inside of our page and let's add uh on click to try and go to this route so I'm going to go inside of protected admin page and let's go ahead and create const on API route click is very simply oops it's going to call fetch to/ API admin do then we're going to get response and then if response. okay uh I'm going to go ahead uh and and just console log okay uh else console error forbidden for now so just this right uh and now let's try it out so I'm going to add on click to this button for admin only API routes on click on API route click and let me just prepare my console here so when I click here there we go I have forbidden you can see 403 error right here so how do we allow this route for someone so now uh this is what we're going to do we're going to go inside of our route here and which method can we use inside of an API route to get the current role well we can use the one where we used which we used in server components so this right here which we've created the lib folder out this can be used in server components server actions and API routes so basically anything server side and those hooks that we created can be used in all client side so if you want to use this inside of your route you can do that so all you have to do is get const roll await current rooll from lib out if roll is equal user roll from prismal client. admin in that case return you next response null with a status of of 200 like that that's it that is all you have to do to check the current Rule and if they have permission to see this so now if I go ahead again I'm still going to get an error in my console log here so let me just expand this but if I go ahead and change my role to admin here and save and try this out again so let me refresh there we go I am allowed to see the content I will test this and there we go I got okay perfect so now I just want to prettyy this with toasts so let's just go ahead and add a new component inside of here so let me just open a new terminal MPX shat ceni at latest add soner or you can manually install soner if you've already used it before so it's just you know for some toast information here then you have to go inside of the app folder layout here and import those R as/ components UI soner and simply add a toaster somewhere in your project for example I'm going to add it here and then you can go back inside of uh the admin page right here and in here instead of doing this we can add toast. success you can import toast from sonor itself like that so to do success allowed API route and in here we're going to do toast. error forbidden API route there we go like that so in I click here there we go allowed API route if I go ahead and change this back to user and click again forbidden API route perfect and it is ex exactly the same for Server action right so let's just try it out so let's go ahead and create actions admin. DS use server export const asynchronous sorry admin asynchronous function and in here let's get the role using a wait current role if roll is equal to user roll. admin we're going to return actually we can uh well yeah we can do this return error forbidden otherwise let's return success uh allowed like this make sure you've marked it as use server here go back to the page here and in here let's do const on server action click so that's going to tell the admin make sure you import ad admin from actions admin like that do then we're going to get the data if data. error toast. error data. error if data. success toast. success data success as simple as that and let's use the on server action click here for this button so admin only server action and let's try it out so I should be getting an error for the server action there we go oh I'm not getting an error let's see what's going on maybe I have to [Music] refresh no I'm still allowed all right so we're going to check that out so admin if roll is user r that admin oh my apologies this is allowed and this one is forbidden my apologies I did the opposite logic so let's try it out now there we go forbidden server action uh and yeah let's also change just the results so this is a success and this is an error like that okay sorry about that there we go so now forbidden server action if I go in my Prisma studio and change my role to admin and save and try the server action again there we go allowed server action perfect so now you know how to use our reusable hooks reusable components and reusable Libs inside of server actions route handlers server components and client components all that's left is to create the settings page so I can show you how you can uh create some best practices to for change password for example where user has to verify their password first how to change email and we're also going to create a little toggle to turn a two Factor authentication on or off great great job so let's go ahead and let's learn how to update the settings and how to update the active session of this user because just modifying the database is not enough we also have to update all of those Libs and hooks which hold the current session so I want to start by creating a schema let's go inside of schemas here and let's export con settings schema which is going to be an object and for now we are only going to try and update the name field so go ahead and add z. optional because user doesn't have to always update that name and it's going to be a string like that and now let's go ahead inside of our actions and let's create a new file called settings. DS let's mark it as use server let's import everything as Z from Zod let's import the settings schema let's import the database let's import uh get user by ID from data user and let's import current user from lib out and now let's export const settings to accept the values which are a type of z. infer type of settings schema and in here let's get the user using await current user if there is no user we are going to return an error unauthorized and we also have to turn this into an asynchronous function so make sure that you add asynchronus here so this await doesn't have an error and now we checked for this user here but let's also confirm that they actually exist in the database and it's not some leftover session so let's do const database user is is going to be await get user by ID using the user. ID here if there is no database user we can return the exact same thing so if there is no database user return unauthorized like this and then let's go ahead and let's do await database. user. update where we have a matching ID of database user. ID and the data is simply going to spread all the values we pass and at the end let's go ahead and let's return success settings updated like this so now let's go back inside of our uh app folder protected settings page right here and we can remove these two so we no longer need that and let's go ahead and remove the Imports as well so just leave use client and instead let's let's go ahead and import from s/ components UI card the card card header and card content let's go ahead and replace this entire thing to use the card element let's Max the width to 600 pixels let's add a card header with a paragraph which is simply going to say settings and a little settings emoji and let's simply style it so it looks the same as our other titles there we go and now inside of card content I simply want to add a button component so go ahead and import a button from components UI button we're going to add a button and say update name so for now we're just manually going to try it like this and let's add on click to call the settings server action so import this and let's manually pass in the values for name to be new name and now let's use this on click and let's pass on click here and let's also import from react use transition so I want to do this so I can see when it's pending so const is pending start transition from use transition let's wrap this inside of start transition like this and then we can use this is spending to disable this button so we know something is going on there we go so open up your Prisma Studio make sure it's running and confirm uh that you have only one uh only uh that you don't have any users which have the name of new name so right we're trying to update this so make sure that you only have uh some other names inside of here and now we're going to try and click on update name here there we go see it completed and now I'm going to go ahead and refresh this and there we go you can see that my name in the database has updated to new name but if I go back to my server right here you can see that my name is still still my old name tutorial if I go into the client my name is still my old name tutorial here so what we have to do is we also have to manually update the session every time we change a specific field so for that I want to go back inside of .ts and in here this is what we're going to do we're going to add this little conso log here I am being called again like this and let's go ahead and open our terminal so we can see exactly when this is being called and this is what I want to do now uh you have two options to update the session so I'm going to show you both of those so you can do it completely using client site inside of settings page right here if you want to you can do the following uh you can import use session from next out react and then in here you can go ahead and use this session and you can dist structure update so what you can do is call. then here and then manually update the session like this so let's take a look at it now I'm going to uh click save here and once this is completed you can see that it's being called up all the time so it's constantly being updated but still even though it's being updated you can see that my names are simply not changing they're still staying at my old names even though I'm obviously updating as you can see in my database my name is not no longer tutorial so how do I update my name well we have to do the following we have to go inside of our token here and we have to assign the name manually so token. name is existing user.name and while we are here let's also do token. email to be existing user. email let's also go ahead uh I believe this is all we need so name email role is to factor I think that's the only thing we're going to update from the settings and then we have to do the same thing here so if session. user session. user.name is token. name and let's also do session. user. email is token. email like that so let's try it out again I'm going to go ahead here and you can see how it immediately works now because our token now is passing the new values name and email so the moment I added that even without testing my name has been updated so this is what I want to do now I want to go back to my settings page and change this to say something different so let's confirm my name is still my old name but if I click on update name here wait for it to confirm there we go my name has been updated in real time to something different great so now we are ready to actually create the form so let me just remove the console log from my token here we no longer need this do I have a conso log okay I no longer have a conso log great but just before we do that uh on the settings page we cannot show the same settings to all users right so if the user has logged in user using Google or GitHub we have to show them different settings right because they cannot change their password for example because they don't have a password they also cannot change their email because it's linked to the account model in the database so what I want to do is I want to go back to uh .ts here and I want to fetch the account so let's go ahead and create uh data account. DS and let's import the database from s/ Li database and let's export con uh get account by user ID using the user ID which is a string let's make this an asynchronous function let's open a try and Cat block let's return null here and in here let's get the account using await database. account account find first where we have a matching user ID and let's return account like this this so make sure you have this little util now let's just visit our next out. d. DS and let's add a new field here called is a out to be a Boolean like this and now let's go back inside of .ts and inside of this token after we confirm that we have this user let's get the existing account using await get account by user ID and let's pass in the existing user. ID and then what we're going to do is add a token is or out is going to be existing account but we are going to turn that into a Boolean by adding double exclamation points at the end and then in our session here we can do session. user. is oou to Simply Be token. is oou and let's add as Boolean here to get rid of this typescript error great so now we have that and now we are ready to go back back inside of our app protected settings page right here and we are ready to create our form so let's go ahead and import everything as Z from Zod uh let's go ahead and let's import use form from react hook form let's go ahead and let's import Zod resolver from Hook form resolvers Zod let's import our settings schema here from schemas and let's go ahead and let's import everything we need from components UI form so we are going to need the form element the form field form control form item form label form description and form message to show the errors uh message and we're also going to need a separate input component from components UI input like this now let's go ahead and let's actually Define our form to be use form and we have to give it a type of z. infer type of settings schema and in here let's go ahead and let's write uh a resolver to be Zod resolver and passing the settings schema and let's go ahead and let's give it a default values of name that's the only one which we have defined so for now leave it is empty later we're going to fill it with the actual user name and let's change this on click to instead be onsubmit which accepts the values which are a type of z. infer type of settings schema and then we are simply going to pass in the values here inside like that and let's also prepare some states here so import uh use state from react so we can show the errors and success messages so const error set error use State and let's go ahead and give it a type of string or undefined and let's do the same thing for the success message and then in here we are not always going to fire the update instead if we have data. error we're going to show uh set error to be data error and if we have success we're going to call the update and set success data success like this uh great and you can also add a do catch here manually to set error something went wrong so if we don't catch something in our server action we have a fallback for this great and now we can remove this here and instead what we can do is we can render our form element and we can spread the form inside and then we can add uh a native form element which is going to have a class name of space Y6 and on click which is going to be form handle submit and let me just collapse this Fields form handle submit our on submit function so we successfully passed uh those values here now inside of the form let's add a self closing tag form field which is going to have control of form. control it's going to have a name of name which is the field we are trying to update and it's going to have a render from where we are going to destructure the individual field and then we can render the form item with the form label which will say name then inside we can add a form control and we can add our input component finally and we can spread this field prop which we destructured above and let's give it a placeholder of John do and we can use the disabled prop to be is pending which we get from our start transition here and the structure is pending here like that uh and now let's go uh outside let's go and wrap this form field inside of a div like this and let's give it some different spacing so space y4 because we're going to have multiple inputs inside and outside of this div now render a button which is simply going to say save and let's give it a type of submit like this so now it's time for us to give this uh an actual default value so why is this submitting when I click on it uh something seems a bit wrong let me just see onsubmit that values so this seems to be immediately submitting uh once I click on that so let's see what I did wrong oh it's because uh in the form I use on click it should be onsubmit my apologies so in your native form make sure you use onsubmit great so now when I click it doesn't submit so now we have to fill this with the currently logged in user information and for that we can use our hook so let's go ahead and get the user using use current user from hooks use current user and in here let's go ahead and add user question mark name or undefined so don't put an empty string because then that will update uh the Prisma inside of our settings you can see that we just spread the values so it's going to receive name to be an empty string and is going to change that in the database but if you give it explicitly undefined then it's not even going to add name field to the values here so that's why I want you to do it like this and now if I refresh here I believe I should have uh my name here but I don't seem to have that uh let's see why that is happening so I'm going to go ahead and console log the user to see if we have some issues here so I have my user and my name name seems to be empty I believe that's because I just submitted the name uh from before yeah because we had that on submit function on click and then we had a default value of an empty string which submitted it all right so yeah we we made a small mistake you probably have the same thing if you do no worries so let's try and change our name so I'm going to call this new name change and let's go ahead and save and let's see if that's going to update uh our property so if I go to server component there we go new name change client component new name change settings new name change if I refresh here there we go new name change perfect you can see how now it's working just as fine so the reason uh our name was empty is because by default I was holding an empty string here and inside of this form I had onclick so when we clicked on the field it fired a submit action and it changed the name to an empty string so just bring it back to this and you can freely update your name uh let's go ahead and try this one more time if I click save here this is going to update my name and there we go server and client components are updated great so now I want to go ahead and actually show this errors and success messages so let's go ahead and let's import form success for from form success and let's do the same thing for form error to be form error if we have an error in any case and Above This this button here let's Ender form error and have a message of error and let's do the same thing for form success to have a message of success and let's give this button a disabled if is pending so now when I update my name again I should get a success message that everything was okay and that my settings are updated great so now we have to add some fields from shat CN UI so that we can update the other stuff so let's add the fields switch and select so inside of our terminal here I'm going to shut down the app I'm going to shut down my Prisma studio and I'm going to write npx shat cnii uh latest add switch so that's going to be on or off for two Factor authentication and after switch we also have to add select so we can change our user role obviously changing the user role in settings is just for development right usually you do that using direct database access or by implementing an API to update the roles so that's that's on new how you're going to handle that so just refresh your page if you've shut down the app and now let's go ahead back inside of our schema so that we can add those new Fields properly so let's go inside of schemas right here and let's go ahead and let's add is to factor enabled to be z. optional and z. Boolean then let's go ahead and add a rooll to bz. enum an array of user roll from Prisma client so make sure you add this import do admin and user roll do user and now let's add an email field to bz. optional z. string. email and password is going to be z. optional z. string. minimum of six and new password is going to be z. optional it's going to be the exact same thing and now here's a cool thing with Zod we can use refine to check if the password and the new password match so if data. password sorry we can not if they match but we can check that by default they are optional right but if the user enters a new password they also have to enter their their current password so let's get data here. password so if data. password is entered and data. new password is not entered return false and we can do if data. new password is entered and there is no data. old password also return false otherwise return true and we can write custom messages for that by adding a little comma here and opening up an object so message is going to be new password is required and path is going to be new password right or you can uh you can write two defines if you want to for example you can chain this refine with another one and this one is going to check if new password is written and old password is not and then change this one to password is required and the path to be password like that so then you handle both cases in the refine here great so we have added everything we need inside of our settings schema so now let's go ahead uh and let's go back inside of our app protected settings page right here and we have this existing form filled so now it's time for us to add a new form field to change the email so let's copy and paste this and let's go ahead and modify our default values for the email you can see how now we have that to be user. email or undefined all right and now in here change this one to be the name of email to have a type of a label of email let's change the placeholder to be John do example.com and let's give it a type of email and now as you can see we have our email fill here just refresh and this will give you the current email that you're logged in with so when you're testing this make sure that you're logged in with the credentials user so don't use oout providers for this part all right so we have that and now let's go ahead and let's add a form fi for the password so let's copy this the name is going to be password and we're going to have a password here and let's go ahead and give give this a type of password and let's go ahead and give it a placeholder of 1 2 3 4 5 6 like this and by default let's add password to be undefined so we're not going to fill the password because we don't have the users's password we only have the hash so by default we're going to put it as undefined meaning uh if user saves this form we are not going to update the password at all so this is for the password field and now we have to copy this field and paste it and this one has to be new password so this is going to be new password and let's go ahead and modify that as well so new password is also undefined like this there we go so now we have the fields to update the name the email the password and the new password so now what we have to do is we have to create uh a form which is going to be able to change the role for so in order to do that we have to import uh some things from our new component which we added called select UI select so just confirm that you've added that right we added npx chat CNA select and switch make sure you run those commands so in here import select select content select item select trigger and select value and now we can go back and actually create this so let's copy the last form field which is the new password form field let's change this one to have a name of role and let's clear up the form item so let's just add form label which is going to be roll and then inside we're going to use the select component and let's give it a prop disabled of is bending let's give it on value change to be field on change and let's give it a default value of field. value and inside let's open up a form control and let's add a select trigger with a select value which is going to be a placeholder of select a role outside of Select trigger uh sorry outside of Select outside of form control add a select content which is going to have select item which is going to have it's not going to be a self closing tag so like this the string is going to be admin as an option and we have to pass in the value to be user role which we can import from Prisma client so make sure that you import this so this one is going to select admin and then you can copy and paste this and this one will select role uh sorry user and the label is going to be user like this great so now you can see that we have an option to select the role perfect so let's go ahead uh inside of our default values here and let's add the role so R is going to be user roll or undefined as well like that so when I refresh here I believe this should be pre-selected for me it's admin I might have changed it from the last time also if you if the form is too big for you if you can't scroll up or down you can just zoom out you know I'm not really making this responsive or anything uh great so one thing I've noticed we are missing is the form message which will show an error so we are not using the form message anywhere as you can see so let's go ahead and simply add it to the fields we need so first we have the name field so outside of form control add form message so this will handle any errors and let's do the same thing for the email outside of form control for the password same thing and for the new password same thing and finally for here uh for here we have to put it I'm not exactly sure where I think we can just do it outside of Select like this so now uh for example if I enter a password there we go you can see that new password is required or if I do the opposite thing Let me refresh if I do the opposite thing and enter this password then the password is required so our refine is working quite nicely great and there's a last field which we have to allow for updating with which is the two Factor authentication so for that we have to import switch component so import switch from components UI switch and let's go down here and copy this field form field new password so this one with the item label control because the select you can see see that it's quite custom right so we have to going to have to modify it and let's change the name of this one to be is to factor enabled like that uh and let's go ahead now and let's modify this a bit so I'm going to remove everything inside of form item here and I'm going to give this form item a class name of flex Flex row item Center justify between rounded large border padding three and sh SM and then inside I'm going to open up a div with a class name space y.5 and I'm going to add a form label component to say to factor [Music] authentication and in here I'm going to add form description to say enable to factor authentication for your account and outside of this div we can add add a form control and simply render the switch component inside it's a self-closing tag and let's give it a disabled prop of is pending a checked of field. value unchecked change to field on change like this there we go we can now modify this and we can save all of those things but obviously we have to modify our settings a bit because right now I can change my email to whatever I want without any confirmation same thing for the password we are not exactly checking if they are matching so let's go ahead and revisit our settings action and let's uh modify it so that it can actually handle uh all of those different changes because when we enter a new password we have to Hash that password right uh and let's go ahead and do the following so the first thing I want to do is I want to check if the user who is trying to to change these fields is logged in using credentials or if they're logged in using oou so in here after we check that we have a database user let's check if user is O Al let's go ahead and do the following values. email which is a field they should not update is automatically going to be undefined values. password will be undefined values that new password will be undefined and values that is to factor enabled is going to be undefined so these are the fields that oal users cannot modify because their email is handled by the provider they don't have a password and two factor is also handled by their provider so it makes sense that if we disable those fields in the API or the server action we also hide those fields from them right here on the client side so let's go ahead and do that so I'm going to find uh the field which I don't want to show so we don't want to show the email and the password so let's find where the email starts right here and let's do if user is a out is equal to false then we're going to show this form field which has the email this form field which has the password and this form field which has the new password so all the way until we get to the role so obviously we have an error because we don't have a parent component so wrap the entire thing inside of a fragment all the way to the end here of the new password and then if you want to you can indent that so it looks a little bit better like this so right now everything should look exactly the same right so I'm going to log out and I'm going to log in using my GitHub and now those fields should be hidden from me because I'm logged in using oou uh looks like they're not hidden that's very interesting oh uh let me just refresh this perhaps the log out didn't work EX exactly as expected so let me try logging in again because I logged in as I I stayed logged in as the previous user there we go now when I'm in all out you can see that I can only see my name and my role and I should also hide the two Factor authentication so let's do that as well I'm just going to copy this query here I'm going to find my field for two Factor authentication and I'm only going to render it if or out is false so right here to the end like this and and then I can indent that as well and no need for a fragment here because it's a single field there we go so allout users should only be able to update their name and their role perfect so I suggest that you log out now and log in uh back to your credentials so we can continue uh developing our settings great so you can see how we have much more options here as credentials and in here we confirm that if client side somehow fails and they send updates for this we will never allow them to update those great so now we have to do the logic if the user is trying to update their email so if values. email and if values. email is not the same as user. email so we are only going to send a new verification token if the user is trying to update an email which is different from what it was before so let's do const existing user to be await get user by email from data user so we have to confirm that the email they are changing to isn't uh used by another user so values. email if we have an existing user by that email we are going to return an error uh which is going to say email already in use and we also have to confirm that we are not that user so existing user and and if existing user. ID is not the same as our user ID so now if I try and use an email from my other account I believe I should get back an error because I'm trying to take someone else's account there we go so email already in user so what I meant to say was email already in use there we go so you can see how that now uh has switched has is protecting my other users try go into your database and take a look at another email that you have and try to use it here and you should be prevented from updating to that email there we go you can see how when I refresh it's back to normal great and now if we pass all of that verification we have to create a new token for them to verify so const verification token is simply going to be await generate verification token from lib tokens right here make sure you import that and pass in values. email so we know to which email to send that and then let's do await send verification email so make sure you add this import from lib mail and in here we're going to pass verification token. email as the first argument and verification token. uh token as the second argument like that and let's break this function and let's write success verification verification email sent like this so if I try to update my email to something else gmail.com in production this is going to send the email verification to this email there we go verification email sent right now this email is not being sent because remember we have to add a domain to resend so that we can send emails to anyone else great so we just handled the case uh for emails but how about for passwords so we have to do the same thing for passwords now before we update it so if values. password and if values. new password and if the database user has a password at all in that case first we have to check if they have entered a correct password so const passwords match is going to be await BP so let's import bcrypt again you can use bcrypt or bcrypt JS I'm going to use bcrypt JS here bcrypt do compare values. password with the database user password which is a hash so we are going to know whether the the password is correct or not without actually knowing what is the password so if the passwords don't match we're going to return an error incorrect password like this otherwise we have to Hash the new password so hashed password is going to be await bcrypt do has values new password and 10 salt rounds like this and then we can manually modify values. password which will be updated here in the database to be the new hashed password and let's do values new password to be undefined because we don't even have that field in our database great great job so now if I try and enter a wrong password here and try to update some other password I believe I should get an error uh because I don't have a matching password right so let's try this out uh let me just refresh here should I have gotten error here I believe I should have so let's try it one more time so password here I'm going to change this to something wrong my new password let's click save here and there we go now I have incorrect password so just make sure you refresh because if you have that email here then it's going to send you a verification for that email but now if I try and use 1 2 3 4 5 six and my new password is going to be 6543 2 1 Let's click save and then I should get settings updated like this great uh and obviously we have to remove the error from when we submit so let me try and log out now and let me try tutorial mailing gmail.com let me try my old password 1 2 3 4 5 6 so if I try to log in with that wrong 654321 if I try to Lo uh tutorial mailing gmail.com if I try to log in with this so my new password there we go it is officially working perfect and now let's just confirm that our roles are working so right now I am an admin but if I change this to user and if I click save let's see what's going to happen there we go I don't have permission to view this and I should get forbidden API route in here I'm getting forbidden server action if I change it back to an admin and click save and then try again there we go allowed API route and allowed server action and lastly let's change to factor authentication so you know that I just logged out and logged in without two Factor enabled so let's try enabling this now and let's click save to see if we're going to get any errors or if this is going to work just fine so if I refresh here or simply go to the server for example there we go two Factor authentication is now on perfect so let me go ahead and log out and let me try and log in so tutorial mailing gmail.com 1 2 3 no wrong password 654321 because I changed my password so let's try that out now it should prevent me from logging in and it does perfect and I have a new email remember this one only lasts 5 minutes so make sure you enter this fast let's go ahead and confirm it and if this is still working I should be redirecting Ed back to my settings page and looks like I am great great job uh and looks like one thing here is not updating correctly so my two Factor authentication seems to not be updating here so it's on here but here it's off oh yeah I think inside of our page we forgot to add the default value for that yes we don't have a default value uh for two Factor authentication so let's add is to Factor enabled user is to factor enabled uh or undefined like that so I think that now when I refresh here there we go you can see how now it's turned on great so everything is working just fine uh I think this was a very cool exercise we did a big project but we exclusively focused on you know mastering next out and all the ways you can do things so yeah about this update thing I'm not even sure if you need it or not so it's very inconsistent on my part I actually when I developed this the first time I did not need to do this so I didn't need to manually update my name and email every time in this sessions and callbacks so it's very inconsistent I'm not sure how it works but this is you know a bulletproof way uh for you to know that it's been updated but it's always updated once you log out and log in and here's another thing that you can do so you don't have to update on the client you can also extract update from here and then let's go back inside of app protected settings page let's remove the update from here and let's remove the import uh of use session here we no longer need that so let me find there I go remove this import let's go back inside of our actions settings so imagine if this is your route Handler you can do this as well so you can now uh also import update from out I believe and then simply at the end of this thing after you update the user in the database call the update here manually or maybe this is not how it's working so perhaps uh I need to do this const user like that or let's call this new user updated user and then in here name updated user.name is this working wait what is this accepting it's accepting a user oh so I have to write the user manually and then name is going to be updated user.name email updated user. email uh what else do we have is to factor enable updated user is to factor enabled and we also have roll updated user roll so you can do it like this if you want as well is that all the fields we have let me just quickly check uh we also have the password yes so but I mean password really doesn't matter you don't even have to update that yeah we don't store that in our session so I think that this should still be working now so if I try changing my name let's try uh update server test and click save here I think this should still work just as fine let's go ahead and see there we go so name is update server test uh yeah you can see how oh you can see how on client it didn't update yeah so maybe it's not the perfect solution so yeah you can see there's a lot of things you have to take care of when working with next out it's obviously a great library but yeah sometimes it's just a little bit inconsistent uh so yeah bring back use session here in the settings page uh bring back the use session hook and call the update here and then well you you can leave it here as well if you want to update it from the server side as well uh great so we wrapped that up what's left is to deploy uh our uh our actual application so deployment is pretty easy the only thing that we have to take care of is the Google and GitHub callbacks so before we wrap up our out master class I want to talk about this video's sponsor clerk you've probably seen me use clerk in a lot the tutorials that I have primarily because it's so easy and so fast to implement so before we wrap up I want to show you how quickly we can do with clerk what took us 7 hours to do with next out so I'm going to give my application a name out masterclass or out tutorial I'm going to select email address Google and I'm going to select GitHub as the options to log in I'm going to click create application and I'm going to copy my environment keys so I'm going to go ahead in this new project that I created and I'm going to go ahead and create a new environment file like this environment and I will paste those keys here then I'm going to go ahead and continue in documentation where I have to install this package so I'm going to go inside of my terminal here and I'm going to install the package we already set the environment keys so we don't have to do that all I have to do is add clerk provider inside of my app layout so let's go ahead and do that here here I'm going to go inside of app layout right here I'm going to import the clerk provider and I'm simply going to wrap the entire app inside of clerk provider like this let's go ahead and see what I have to do next I'm going to go ahead and add a middleware so I'm going to create a new file inside of my project called the middleware and I'm going to paste the snippet from the documentation right here now I'm going to go ahead and skip to the bottom to create custom signin and sign up pages so I'm going to go ahead and create the following folder structure here inside of my app folder I'm going to create a new route called sign up and then I'm going to create another catch all route sign up and inside I'm going to create page. CSX and in here I'm going to paste this code snippet like that I'm going to copy and paste this and rename it to sign in and I'm going to rename the inside route to sign in as well and then I'm going to go ahead and copy the other snippet for the sign in like this and then I have to update my environment variables with those new routes which we've just created so let me paste that here and now let's go ahead and let's run our app so make sure that I have mpm runev I believe I already have that right here I will refresh my page right here and I will be redirected to the log in right here there we go I can use GitHub I can use Google or I can sign up using the email address and the password and this will came this will come with validation with two Factor authentication email verification absolutely everything so let me go ahead and create a new GitHub account here and now let me show you how easy it is to fetch the current user session so I'm going to go inside of my app folder I'm going to go inside of page. PSX here I'm going to remove remove absolutely everything from here and the only thing I'm going to render is my user button component so let's go ahead and import user button from at Clerk nextjs and let's save this right here and as you can see there we go I have a user button and from here I can manage my entire account by changing my email I can even connect a new linked account I can add a password I can check my active devices I can delete my account and inside of my dashboard here I can control how many users I have and I can also ban the users impersonate users visit their profile and also delete the users and let me show you how we can easily create a public route for example I'm going to create a new folder public right here and page. VSS and I'm simply going to call this a public page with a div this route is public to everyone all I have to do is go inside of my middleware and I simply have to add public routes SLU that's it so now what I can do is I can log out from my account here and demonstrate to you that I can go directly to localhost 3000 SLU and there we go this route is public to everyone but if I go to any other route I have to log in again so as you can see it took us 5 minutes to implement with clerk what took us 7 hours to implement with next out so that's why I love to use clerk inside of my tutorials it's extremely simple to implement it is extremely secure and it is an absolutely great deal and I'm very thankful that they've been sponsoring my channel from the earliest videos and allowing me to create so much free content and now let's go back to wrapping up our tutorial so before we deploy our project I just want to go ahead and add a couple of improvements inside of our app so sign out of your application and yeah here's one thing whenever you're signing out make sure that you don't have two tabs open of the same application because then you you're kind of not going to be signed out completely so just always make sure when you sign out using next out that you only have one tab open of your session otherwise uh it's just going to be a little bit weird so sign out of your application make sure that you can see the login screen and let's go to Local Host 3000 where we can find the signin button and in here what we have to do is we have to install a dialogue component so let's go ahead and shut down the app and run npx shat CNU at latest add dialogue like this so this will add the dialogue component inside of our app let's do mpm runev uh and then let's go back inside of components out right here and let's go inside of of the login button and now we have to handle this case if mode is model right so we can do that uh by importing the dialogue so let's go ahead and import everything we need from at/ components UI dialogue so we need the dialogue itself we need the dialogue content and we need the dialogue trigger like this and then inside of this mode model all we have to do is render the dialogue then we have to render the dialogue trigger and let's give this dialogue trigger our as child prop and inside we're simply going to render the children and then dialogue content is going to render our login form from do/ login form or components out login form so that's how easily we can reuse our form so if you want to do the same thing for register feel free to do that and let's just give this a class name of padding zero with AO BG transparent and Border none so now if we go back to page. CSX where we use our login button and change the login button mode to model we can go ahead and click sign in and let me just refresh my page to confirm that this is up to date yeah if you shut down your app make sure you run it again and there we go now it's in a model and to fix this hydration errors which we have all we have to do is also pass the prop as child right here there we go so now no errors and you can see that I am opening this inside of a model instead of a redirect so if I remove this mode and click sign in then it will redirect me to the page great so we have that covered now here's another thing that I want to cover So currently when I log in into uh a specific page right here and when I I get redirected sorry if I go for example into admin and if I log out in my URL it's just SL says slash out/ login but what I wanted to do is I wanted to tell me what's the last place I visited so that when I loging back again it will redirect me back to that path so let's go ahead and visit our middleware dots where we can modify that so find this if Clause if we are not logged in and if this is a public Crow and in here let's define let callback URL to be next url. paath name and then if next URL already has a search let's do callback URL plus equals next url. search and then let's encode our call back so encoded callback URL is equal to encode URI component with the Callback URL and all we have to do is append that to this new URL here so let's go ahead and do that let's change this to use back TI and let's add a question mark and encoded call back URL query so now make sure that you're logged out so when you refresh it should not show you the settings if you log out and it's showing you the settings page again it means that you have another tab open of this page so make sure you close our tabs and then log out so now I'm logged out and if I manually go to SL settings you can see that I'm redirected back but this time I have a query from where I came from so if I try to access admin now that is saved in the URL so when I log in I will be redirected back to that page so what we have to do is we have to use that callback URL inside of our login form so let's go inside of components let's go inside of out login form right here and let's go ahead we already have the search for Rams great so now besides the URL error let's also get the Callback URL to be search pam.get callback URL inside of our URL and then we can pass that as the second argument of the login server action like this and let's go ahead and go inside of login here and the values are going to be the first argument but the second argument is going to be the Callback URL which is going to be optional and a type of string and then we can go ahead uh and add that to the redirect to so call back URL or the default login redirect so that's why we use that here so let me try this out now so tutorial mailing gmail.com 654321 I have two Factor authentication on so I'm going to get an email so usually once I log in I'm redirected to the settings page but now since I have this inside of my URL once I confirm this to Factor token I should be redirected back to the admin page so let's just try that out if it works so looks like I made some mistake here so let's go ahead and see what I did wrong uh call back URL here how about uh I try logging out and uh console logging the call back URL right here oh I think what we did wrong inside of our middleware here is that we forgot to add uh the Callback URL here so make sure that in your response redirect new URL you add the call back URL like this so let's try out now so make sure you're logged out let's attempt to enter admin for example and there we go now we can see how our query has the call back URL and it seems like we are having this little type error here in the login so let's change this to be string or null there we go that will resolve the typescript error so if I try this again tutorial mailing gmail.com 654321 and I log in I'm going to get a new to factor authentication code now there we go let's go ahead and use this and now I should be redirected back to slash admin instead of Slash settings because that's the last page I visited or attempted to visit while I was logged out and there we it's finally working perfect so now we just have to do the same thing for the social buttons here so let's go ahead and try that out so go inside of your components out and find the social button here and in here you can do the same thing so import use search params from next navigation here get the search params from use search params and then get the Callback URL to be search params doget callback URL and finally you can do this here so call back URL or the default login redirect so if I try logging in with GitHub now I should also be redirected to slash admin instead of Slash settings there we go perfect but there is one more thing we have to take care of and that is inside of our uh mail Library so in here we are hardcoded to Local Host so we have to change that to dynamically use uh our environment variable so let's go inside of environment and let's create next public app URL to be HTTP Local Host 3000 so don't add a slash at the end so just Local Host 3000 and make sure it's HTTP and then let's go ahead inside of here and let's add const domain to be process. environment do next public app URL and then we're simply going to change this from instead of being hardcoded to use the domain variable so the main slout SL new password which will translate to localhost 3000 slout new password so later when we deploy we can easily change the environment variable to our new deployed URL so let me just try this out I'm going to go ahead and attempt to log in and now I should get an email and the redirect link oh sorry this is to factor out not this the new let's try new password so let's try new password so now I should get the new uh email being sent here but let's see if it's going to lead us to undefined or to Local Host there we go it's still working it's leading us to Local Host perfect so we wrapped up everything everything we need for our app uh make sure again that you're only using one application open uh for this uh tutorial great so we've wrapped up the entire tutorial now it's time to deploy so the first thing we have to do is we have to create a new repository in the GitHub so I'm going to give this tutorial next 14 Al masterclass I'm going to make this a private repository and I'm going to go ahead and click create reposit itory then what we have to do is go inside of our terminal here and we can shut down the app and run git ad and then get commit and I'm going to go ahead and call this for example uh deployment and I'm going to now run this three commands which we have so this is if it's a new repository and this is if it's an existing repository so let's use these three commands here copy them and paste them here and after you push and when you refresh this project right here project deployed uh sorry not deployed you should see it in GitHub right here perfect so now let's go ahead to versel decom Let's click add new project and let's select our new uh GitHub repository and now we have to assign the environment variables so let's go to environment like this and let's copy everything and let's paste them inside so obviously we're going to have to change the next public app URL but we can only do that once we deploy so I'm going to click deploy I'm going to pause the video and we're going to see if I get any errors if we do we're going to go ahead and fix them together so I got an error with my deployment and I believe I know why yeah I forgot to add uh that we need to initialize our Prisma client so let's go ahead and go inside of uh package.json here and in here let's add a post install script and let's run uh Prisma generate and here's another tip for you if you don't want to wait until uh versel does the build you can manually do mpm run build so this is not going to deploy or anything this is just locally going to attempt to build so run this and we're going to see if we have any problems here so we don't have to wait for s and there we go here it looks like everything is okay so now what we have to do is we have to redeploy we can do that very easily with verell all we have to do is run git add git commit I'm going to call this piix and get push and once you push the new deployment is going to automatically start so if you take a look at here uh go inside of your projects here select the new project and in here if you look at the deployments tab you can see that it's building a new one right here so you can click on it and then you can expand it again and there we go this time it was successful and you can see our page right here so let me just go ahead and expand this I want to go to the root of my project in the project so I can get the actual domain so don't use the deployment domain use the actual domain right here so when I visit this there we go we have our login here but our GitHub and Google are not going to work so let's go ahead and do the following copy the URL like this this one and let's go back inside of your uh GitHub o out where you define your client secret right here you can find you know in the beginning of tutorial where I did that change the homepage URL to be that new page and replace the backs slash and now you have to change the authorization call back you URL as well there we go so your new domain URL / API out callback GitHub and go ahead and click update application and you don't have to update the keys so just make sure that you have those new URLs here and then you have to do the same thing in the Google Cloud so find your project go into credentials here let's go inside a web client let's change the url to be that remove the back slash and in here also replace this to go to/ API out call back Google with this URL here and let's go ahead and click save here as well and now you have to go to the oou consent screen right here and in here you have to add uh let me close this you have to add where is it so click addit app and you have to add uh authorized domain so for me it automatically added this domain right here the moment I added the credentials so just confirm that in your NE in your authorized domain you have that domain and you can just confirm and save and continue great so now let's go ahead and try it out now so I'm going to go ahead and attempt to log in with GitHub here let's see if that's going to work now so uh there we go I logged in perfect and let me try Google and there we go Google is working as well perfect great so you officially deployed what we have to do now well if you want to you can continue watching the video where I'm going to show you how you can add uh the domain to resend so that you can send emails to anyone and so that inside of your lib mail. TS you can change the from to be from whatever domain you want for that you're going to need to purchase a domain right you can find very cheap ones for I believe $5 so I'm going to do that I'm going to purchase a domain and I'm going to show you how to change the DNS settings so there we go you can see you can find very cheap ones so I'm going to go ahead and then purchase this one and then I'm going to show you how to modify the DNS settings so after you've purchased a domain or use whatever domain you want go ahead and go to resent go inside of your account go to domains and I'm going to go ahead and add this domain so out masterclass tutorial right here I'm going to click add and now we have to add this DNS records and then we have to verify them so let's go ahead and do that so I'm going to go ahead go inside of your DNS I'm using GoDaddy and let's click add a new record so the type is MX for the first one I believe the host is send and let's go ahead and copy the value right here to be the value let me zoom out so you can see and the priority it says 10 so let's copy 10 as well like that and let's add more records so the second one is txt it's also send so txt send and and the value is this one and let's add one more domain also txd this is the name and this is the value and let's click save all records so make sure you've added all of those to your DNS right here and then what you can do is go ahead and click on verify DNS records sometimes it can take a couple of minutes maybe even hours for DNS to propagate so this is quite optimistic of me trying immediately so if it doesn't work immediately I'm going to wait a couple of minutes and then try verifying again if it's still not working perhaps we did something incorrectly but it's just a matter of copying this values and adding them to your DNS records so this is the same process if you're using know any other I'm using goad in simping because I know how to use it and access the DNS settings you can use name chip verell whatever you want to do wherever you add your DNS variables so I'm just going to pause the video and see where this is going there we go so my domain was officially verified and what we can do now is we can send the domains uh we can send emails using that domain so let's go back inside of our lib folder mail right here and I'm going to change this to send from for example you can do anything you want I'm going to use mail at out masterclass tutorial.com so from now on that's going to be my from domain let's go ahead and change that here and let's go ahead and change that here so I'm going to go ahead and first attempt this locally if it's working and then we're going to go ahead and deploy again so I'm going to mpm runev here and I should also be able to send emails to anywhere now not just my logged in account so we're going to attempt to do all of that so I'm going to go ahead and sign in I'm going to use tutorial mailing gmail.com 654321 and I'm going to check my email now and let's check my email and there we go you can see that the name is mail and it's coming from mail Al masterclass.com so we officially uh we officially linked our mail what I want to try now is whether we can send the emails to some other mail so let's try that by creating an account so I'm going to call this test and I'm going to go ahead and use uh I don't know something at example.com so I think this should fail now but I still believe that we should see it inside of our resend as something that has failed so let me just go ahead and refresh and there we go you can see how now we can send emails to any account that you want any email that you want perfect so this is now full on production everything is working and to push that to production all you have to do is do get ad get commit let's add domain and get push and that's going to re-trigger the deployment but we didn't even add anything here right except uh changing our mail of course to use this one so you can do anything you can make this send you can make this whatever you want all that matters is that you have your domain here perfect great great job you wrapped up the entire tutorial tutorial um thank you so much for watching remember to leave a like share and subscribe and watch my other videos if you like them so just one thing that I forgot to cover if you use the domain right here from versel and for example if you try to log in use your password and get the two Factor Authentication token the domain that will be sent to you uh sorry not this one new password let's try this again so new password for tutorial at tutorial mailing gmail.com we forgot to change the environment variable of next public app so let me just wait for this to come there we go and when I click here you can see that it leads me to Local Host 3000 instead of this domain so it's quite an easy fix we just have to copy the URL we have to go inside of the settings of the project inside of environment variables here and we have to find next public app URL so right now you can see it's Local Host so our mail system is going to uh add URL links with that so just change it not with the slash to go to https your versell link and don't put a slash at the end and click save and after that you have to go in your deployments select the last deployment and click redeploy like that and then we're going to demonstrate this again just to prove that it is working all right the app has been deployed so I'm going to visited on verell again and I'm going to send myself an email and let's just confirm that this time the URL link is correct so let's see if this is the correct email looks like it is so this time when I click here I'm redirected to the correct website perfect so that's it we've WRA up the entire tutorial we fixed the bugs we enabled resend we enabled absolutely everything thank you so much for watching one more time and see you in the next tutorial
Info
Channel: Code With Antonio
Views: 355,973
Rating: undefined out of 5
Keywords:
Id: 1MTyCvS05V4
Channel Id: undefined
Length: 480min 57sec (28857 seconds)
Published: Sun Dec 31 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.