The Ultimate Guide to Next Auth - Everything You Need

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's up YouTube my name is Brett Westwood and today I'm going to show you how you could use authentication inside of your next js13 project using nexoth we are going to use three providers that next auth allows us to use one is going to be the credentials provider which allows us to use your username or email and password to sign in and authenticate an account the other two will be the Google provider and the GitHub provider there is one caveat though with the credentials provider and that is it doesn't actually register a user all it does is authenticate users so what we need to do is we need to create a register API endpoint inside an xjs13 which we will do inside of this tutorial after we get all of these users authenticated they will be sent to a database and we are going to use mongodb for doing that and we're going to connect our database to our application using prism so if you want to learn how to create a fully functional login and register page just stay tuned watch the rest of this tutorial and you should be able to do it at the end of this tutorial also before we get started if you could hit that like button and also subscribe if you want more content similar to this that would be amazing so no further Ado let's get started and let's jump right into the code first thing first is we need to set up the environment for our next js13 project so to do that we are going to open up our Command terminal on our system and we are going to change directories into wherever you keep all of your projects if you don't keep your projects in a specific directory you can just use your desktop so after we're in the specific directory we want to use we need to open up a Google Chrome tab and you're going to be on next.js Docs and for these next JS docs we are going to be on the installation Tab and we are going to copy this command npx create-next-app at latest so we're going to copy that go into our terminal paste it and then we have to give the project a name so I am just going to put YouTube next auth press enter then it's going to prompt you to a few questions before we get started typescript no eslint no Tailwind CSS yes the source directory no the app router yes and the default import Alias no it's going to initialize the project and it's going to install all the dependencies necessary for nexjs this should take about 15 seconds and after this is done we're going to change directories back in to our project so I called a youtube-nex auth and then we're going to do the shortcut code dot to open up my text editor which is vs code we are going to close this command terminal open up the project right here which this is a boilerplate next.js13 application I am using version 13.4.2 in this tutorial I'm just going to go over quickly what these folders are so the app folder is the main folder we're in this page.js folder is your home page so we are going to go inside of it we can remove this image import and remove everything inside of the main tag including the main tag we are just going to create a section element and inside of it we'll have an H1 saying home perfect now we're going to go inside the global CSS the global CSS we're going to move lines 5 through 27 and we'll keep lines one to three because we are going to use Tailwind CSS for this application the layout for file is the file for the root layout this is going to apply to all the pages in your application which is referred to as the children this is where you can import your next font Googles this is where you import the global CSS and this is where you can have metadata for your whole application after we were done with this we are going to organize the project a little better we are going to create two main folders the first one is going to be the API folder this is where we're going to have next auth and we're going to have all of our backend routes inside of and then we also are going to create a folder inside the app called parentheses site so this means that this is where all of our client side facing um pages are going to be this does not include so I'll explain how the routing Works in xjs it is a little different than a react application so for example inside of the site I'm going to create a new folder called register register is going to be considered a page route so it is going to be localhost 3000 slash registered that will be the page and to write the code for this register directory you get to create a file inside of the directory called page.jsx and then I'm going to create a login page as well so I'm gonna have a folder called login and then we'll have a new file called page.jsx inside of the login so technically now we have two client-side facing Pages named login and register and then a third one too if you include the home page so I am just going to open up my terminal kick real quick and run npm run Dev this is going to start my localhost 3000 I'll open it up and I will just show you for example what is going on it's the home page is the localhost 3000 if we go to slash login it should be empty but it doesn't give us an error so if I go to like slash h it will give us this page cannot be found so they log in and register page are there but there's just no content on it so now that we've set up our environment and our application we are ready to set up Prisma so we can connect our mongodb database so to connect our mongodb database to our next js13 application we need to use prism so we're going to set up prism right now so we do have our development server running so let's stop it by pressing Ctrl C and we need to install a package which is a Dev dependency it's going to be our first package and it's called prism so we need prism to connect the database after we install it we need to initialize this so it's going to be npx prism init so that means two things happen well more than two things but two things that you could see so you're gonna see it created a prism directory right here and inside of it has a schema.prisma and it also created an environment file right here dot EnV so let's just go inside the schema.prism real quick and we have first off there is blue and green text uh in different colors so if yours text doesn't look like this it's because you need to download the extension prism so we have the prism extension it has 832 000 downloads and it adds syntax highlighting formatting Auto completion jump to definition and letting for prism files this is very useful if we are going to use prism so I highly recommend you get this extension on your text editor next thing we are going to do is we are going to go inside the schema.prism and we are going to change the default provider which is the postgres SQL to a mongodb and then the database connection URL string is in the EnV file under the value database underscore URL so if you go to this it is right there this is our default string that has no use to us so that means we need to create our own string from mongodb by creating a collection so to do that we are going to open up a Google Chrome tab go to Google go to mongodb it should be the first search result and then we're either going to sign in or sign up in an account I'm going to sign in using the Google provider so we're just going to sign in your page looks something like this at the top left there's a drop down you click it and you click new project so for the project name I am just going to name it what my project is called you can name whatever you want so YouTube next auth we're going to click next we don't need to add any members or set permissions so we're just going to click create project this is going to create the project and then now we're going to build a database so we're going to build the database we're going to select the free version the providers AWS the recommended region is going to be whatever it is with the star and then your cluster name you can leave it as default or you could change it wherever you want but it is only server side so no client is actually going to see it so we're going to click create and the most important part is this username and password so I'm just going to use the username and then the password you could have whatever password you want but I'm going to keep the one that they gave me I'm going to copy it open up my notepad paste it in my notepad because we're going to need this for later and then we're going to create the user so it shows the user created right here you're going to use your local environment and then you're going to use your IP address or you if you want any IP address to have access to this database you press 0.0.0.0 slash zero and any IP address can access its database as long as they're logged into your account we're just going to click finish and close and then we're going to click go to database and this could be instant or this could take a few minutes and this is going to create your cluster and your collections mine is already created because it says status is active and it's green now we're going to connect the database by using the database connection string we're going to click connect and we're going to click mongodb for vs code it's going to give us this connection string right here we're going to press copy we're going to go back to our vs code we are going to paste that string right here and then we're going to add a test at the end so it's going to be mongodb.net test and then in the password with the greater than and less than sign we need to replace it with the password in our Notepad if you don't do this you're not going to be able to successfully connect to your database so now we are technically successfully connected to mongodb we could go close this and we can leave this page open for now and now we are ready to actually start creating schemas in our schema.prisma file so we are going to create two schemas one is going to be a user model and the other is going to be an account model so the difference is that we are all going the everybody's gonna be sent to the user model even if you sign up with the account either through Google or through GitHub we need the account model because like I said we are using the providers of Google and GitHub so we need that and we are going to use a relation to connect these two models a relation of one to many so I'm just going to copy and paste these schemas inside of my code editor below and I'll explain exactly what's in it so we're going to copy paste so right here I connected a user schema right here every user is going to have an ID of string and this string right here has a decorator attached to it this decorator is straight from the Prisma docs and this is what you have to use for the mongodb database we're also going to have a name an email email verified image we're going to have a hashed password because we do have to Hash passwords before we send them to a database created at update it out we're going to have the accounts and these accounts are going to come from the account model that's what it means so anytime somebody gets a GitHub provider logged in it's going to still be in one specific database so it's easier for us to see and like I said we have a relation the relation here is in the account the account is in relation to this user model right here and it's going to take in consideration the user ID right here in the reference each ID to make sure they match up so that is how we're going to connect and how we're defining types inside of our database using prism if you do want more information on this stuff I will link the prism docs below inside the description we want to access prism globally as well on the client side so we do have to get a package on to our application so we're going to install the at Prisma slash client package so when you do this there's two ways you can do it you could do Prisma client globally in one file and then just import it from that file or you could just initialize Prisma on the top of every file that needs Prisma so the reason why you would need Prisma on the front end or on any of your code on the server side is because it gives you different methods and functions that allow useful transactions so we are going to actually create a lib folder it's going to be Libs and then inside this lips folder is where we're going to initialize the Prisma client and we're going to make it a global state so we could use it in any file we need as long as we import it from the libs folder so we're gonna have Prisma db.jsx and we have to import the Prisma client we're going to call client Global this dot charisma or we're going to initialize it with the new Prisma client function and then we're going to say if the process dot environment variable like the node environment is in production not development if it's in production the environment which means that we're pushing it to production the whole application we are going to use the globaldist.prisma for the client and now all we have to do is export default client so like I said if we want to use the Prisma client in any of the folders we just got imported from this export okay so now we are finally ready to install packages from next auth so I'm going to install two packages off the bat so we're going to have next dash auth at latest and then we're also going to have a prism adapter so this is going to be next Dash auth slash prism Dash adapter so we're gonna install these two packages next all that latest is the main package that allows us to use the authentication that Microsoft provides and the prism adapter allows us to connect prism and the database to next auth so to make sure these packages are installed you can just go to the package Json we have everything installed with the versions I'm using I'm just going to close this tab close a few more tabs I'm not using just to clean things up and now we have to create a main entry point for this next auth allow to allow it to be on our project so to do that we are going to create another folder in the API called auth and then we are going to create a catch all API route and it's going to be a bracket dot dot dot next auth and then close bracket and then this will have a file underneath it called route Dot jsx so this route jsx file is like I said the main entry point for our next auth application so there's a few things we have to import before you even start typing any code so we have to import next auth that's the first thing next we want to import prism and that is from that Global lip file we just created from dot dot slash dot dot slash Libs slash prismdb we also want to import the prism adapter then like I said we are using three providers that allow for authentication the credentials the Google provider and the GitHub provider so we need to import those as well okay so now we have all the Imports ready to go now we can actually start coding this entry point for next auth so we are going to create some auth options and these auth options they give us different properties that we can use to make our authentication process a lot more efficient smooth and clean so the first thing I'm going to do as a property is the adapters I'm going to define the adapters or the adapter my fault the adapter so it's the prism adapter and it's taken in the prism globally so that's the first thing we're going to do and then we have to define the providers so it doesn't know what providers we're using so we have to tell it what providers we want to use so first one I could do is I could do the GitHub provider and the GitHub provider takes in an object with the client ID and the client secret we're going to get these values later but for now we are also going to send all of these values to the EnV file because these should not be client side facing after that we are going to have the Google provider and is going to have another object with the client ID and the client secret as well and like I said we will get these values later on in the tutorial um another one we are going to do the last provider is the credential provider this is the most complex provider to actually code so that's why I'm leaving it right here at the bottom so the credentials provider first takes in a name and we have to name it so we're going to name it credentials that's what the um docs say and that's what most people do and then in the credentials we're going to have an object and then inside of this object we are going to have different labels that we need to fill out so these different labels we're going to fill out I'm going to have an email and then the email is going to be defined with a label type and we could have a placeholder not necessary we're gonna have a password we have a label and the type is going to be password and then we'll have a username and then it'll be a label type and a placeholder as well so we could close this and then right below this we are going to have the async authorized and it's going to be a function which is going to be the authorization and authentication logic of the credentials provider so for now we are going to do this so I'll type this out first and explain what we're doing so we are going to create a user because we don't have the register API endpoint gradius so we have no registered users so technically we have to hard code a user inside of the logic part of the code which is right here so we're going to say cons user equals and then it's going to have an ID a name and then we can give it an email gmail.com which is not my email so you could try to email if you want but that's not gonna get to me so we have a name and an email and ID so this is a user I just created this is dummy data and all you have to do is return this user the reason why I am doing this is because next auth actually gives us a pre-built login page to test out our um code before we actually start creating the register API and not everything works so that's why I'm doing this like I am now so we are going to close the credentials provider and then we could go outside of this array and outside of this array we are going to have a few more properties that I want to call so one that is required is going to be the secret so we need a secret and the reason why we need a secret is because it helps encrypt the JWT tokens so this secret should be on the EnV file as well we're gonna have to create that now so secret equals it's going to be a string and they could just be whatever it should be something hard to guess so there is my secret I'll close the EnV file and then the next option I want inside of the auth options is going to be the session our session is going to have that strategy of JWT that's how we're gonna encode all of our stuff through Json web tokens and then after that option we are going to have one more option and this is going to be debug so debug is a pretty simple um option that we're going to use here in the auth options it is going to help us when we're in development and it's going to give us errors specified in X auth so for messing up anywhere in the next auth code this will pull up in this terminal right here and tell us exactly what we're doing wrong so that's why it is definitely useful to have this right here okay and then the final thing we have to do is we have to export these auth options but we get to export them in a certain way so we have to export them as handlers and we had to pass them through the next auth package so we have all the auth options passed inside this next auth inside of this specific variable and we have to export the Handler but you just can't export handlers like this export the ball handler the reason why is because we are in a route file in the API of nexjs if you're on any route files in xjs you must export them either by an HTTP request so like a post request or a get request or a put request it has to be exported like that so we are going to type export with an object Handler as git Handler as post because we are only using git and post requests inside of this catch all route okay so now I want to make sure all of this code is working and like I said next all provides a pre-built login page and we are going to test out to make sure we are returning this specific user like this code says right here so we are going to run the development server npm run Dev open up localhost 3000 and the path for these pre-built sign in page is going to be slash API slash auth sign in and here is this pre-built login page that is specific to next auth to sign in with Google and sign in with GitHub isn't set up yet even though it's showing it's showing because we added them in the providers option but we don't have the keys so this will not work it's going to throw an error the sign in with credentials though however should work and it's only going to return that user that we hard coded in the async authorized credentials function so I could type in anything I want here and then this and then I'm going to inspect the page before I submit it and we are going to go to the network tab and then when we submit it we should get a 302 which means a return and found content so perfect so now we have a credentials of 302 with the request method of post and it's shown us the request URL that's showing the payload that I typed in and it sent us to a login page okay now we also can look at the application tab and if you look at this it gave us a session token right here so this session token is what's going to give us that session data that we could use to show the user's name email whatever information you want to show to the client that they signed up with you can show through here and you're gonna have to be able to access this session token and there's going to be two ways you could access this session token that I'm about to show you okay so there's two ways to get session data and that is through server side or client-side rendering so server-side rendering means you're just going to get the information quicker you could do either way you want whatever you prefer but for this project too I'm going to do client-side but I'm going to quickly show you how you can do both real quick so technically we are logged in because of these tokens we refresh the page that the tokens are still here so we are going to do a server side rendered real quick I am going to open this up real quick right here we are on the home page we need to import a few things from next auth to do a session side render so we're going to say get server session and this is from next Dash auth and then we are going to create a session con session and this is going to equal weight that means we need a asynchronous function in this variable session is going to get the session server server session and it's going to take in the auth options which is the backend code from that catch all route which will be Auto imported when you type so now if you want to show it you could have H1 that says server side rendered and then we can do a json.stringify so we'll just do Json to a stringify and you're going to stringify the session so now since we are logged in we should get all the information on the home page so if we go to localhost 3000 I'm going to remove this real quick and there is the user that is hard coded on our catch all API route name Brett email Brad gmail.com and that is server side rendered okay so that is how you render server side how do you render client side so if you want to render client-side is a little trickier but it's not hard at all the reason why is because in xjs13 all pages by default are server side rendered so if you do want to render something client-side like a use date if you use any Hooks stuff like that you need to put a used client tag at the top of that file and we need to create a context folder so this is where I'm gonna have all of the providers in context for this project and inside of that we're going to create a file called auth context Dot jsx and then inside of this auth context jsx we are going to initialize the session provider so like I said you have to mark this as use client if using any type of hooks or providers so we're going to import the session provider and this is going to be from next auth slash react then we're going to export a default function called all the context but I'm going to change the name to provider because this is what I'm going to use in the other files we are going to return the session provider and it's going to be wrapping all of the children and I just got to close this as well and this file is complete and the reason why I'm doing in this file like I said before is next js's docs recommend that you do any providers inside of a separate file so I'm going to import this provider into layout you should not do any layout you should not do any provider functionality inside the layout it needs to be separate so I'm going to import the provider from the contact slash auth contacts and I am going to wrap all the children with the provider so just like this so now I have access to the use session hook inside of my application which will render a session data client side so I'm going to show you exactly how I do that too so to do that we are going to create a folder for this purpose only called components and inside it we will call a file call user .jsx we could just do a react functional component and we are going to import the use session hook and this is going to be from next Dash auth slash I think it's react let me just make sure that's the correct yep so it's from next auth slash react and if we want to use this session which is uh we are going to call it like this so we are calling the session by using the use session hook and then if we want to show this off we can just do a Json dot stringify again Json Dot stringify and we're gonna do this session and now I just want to compare the two on the same page we are going to get the user I'm just going to capitalize this we are going to get the user inside of our home page import user from the components and then we're going to do a self-closing tag because we still want this page to be server side rendered so if we go over here it says react concept isn't available in server components the reason why is because we did not do a use client on the top so you see it does throw that error I'm glad I actually did the error so to show you so if you don't do a used client at the top when you're doing like a hook or use session or any providers you'll get error thrown at you I think I might have to restart the server let me restart it real quick we are going to run the dev again go to localhost 3000 it might have logged us out but it looks like it did it so as you can see right there this popped up maybe a second later if you want to replay it this popped up a second later and this was technically the client-side rendered so let me just label real quick H1 client side rendered so if we go back to the page it'll be more cleared so this is the server-side rendered session data and this is the client-side rendered session data if I refresh it since it's already I think loaded it might be at the same time but we'll check it out nope as you see it takes about a second more not even a second more to render the client side so the client side does take a little longer but it does get the job done both of them do get the job done and it's essentially the same thing just using a different method okay now that we're able to connect next auth successfully and show that we can log in a user with a pre-built page and we could get the session data by using a client call or server side call now it's time for us to actually register our own user so first thing first is I want to create the client-side register form so I am going to minimize this API folder and we are going to work in the site folder in the register page.jsx so like I said earlier this isn't a tutorial on Tailwind CSS so we are going to use a Tailwind CSS well Tailwind UI template for us register form so we are going to go on Google and we are going to go to Tailwind CSS we could just go to the top right here go to components browse components and then if we scroll down we should be able to see a sign in and register form so if we click code and then we make sure the down arrow is clicked to react we can literally copy all of this code and this is going to be for a register and I'm using simple so that is the format and it should look like this so I'm going to minimize this paste decode in here we're going to scroll the top and it has some comments so it's telling us that we need to require a tail in CSS forms and that is a package that Tailwind CSS requires us to download in our project so we need npm install at Tailwind CSS slash forms we're going to press enter and now we have that package on our system but now we need to implement it in the config file so to do that inside the plugins array bracket we're going to press require and then it's at Tailwind CSS slash forms so anytime you do changes in the config files or EnV files you should reset your development server and restart it but ours is currently not even on so we're good to go so we're going to remove this code and we're going to move this comment we don't need to do this comment at all we are going to call the function register we're going to change this to register your account register for an account and then if we do look at what the template looks like we only have two fields and we're actually requiring three we need a name email and password for the register portion of the client so to do that we need to just pretty much copy this whole div and paste it down again and then just change a few fields so the first field should be named HTML forward name ID name it'll be a name for name the type is going to be text we don't need an autocomplete and I think everything else is looks good let's just see if the UI looks good and let's just change the button down here to register let's open up localhost 3000 we're going to get sent to the home page you see we're still logged in we're going to go to the register so here's how our registered page looks looks pretty nice right real quick to make too the only thing is it's not functional we have no State like we could type in input but we're not receiving any states so that's the next step we need to do so we need to mark this page as used client since it is client-side rendered because we're using the use State hook so the U State hook we are going to get the values of all these inputs so to do that we need to initialize you state by data and set data and that is going to equal an object with the initial values of name which is empty string email empty string and password empty string so we have that going for us now and now we need to add the values and on changes in each input so the value is going to be data.name because it's the data object with the property name and then the on change is going to be setting the data from an anonymous function to the e.target.value now we need to do for the email input which is value equals data.email and the on change is the set data exactly like that so if you just change this field right here and this dot dot dot is the spread Syntax for data so it's showing all the data is the same and we're just changing the email field we're going to have the value here data.password and then we'll have the on change as well so now all of our inputs should be get we should be able to receive the state but we're not doing anything with the state yet so on the top of the form right here where the form starts we're going to remove the action and Method and we'll do an on submit this on submit is going to point to a function called register user register user which we haven't created yet so we're going to create it right above the return we're going to create an arrow function called register user and it's going to take in the E dot prevent default and we're just going to close it for now I like putting this in a parenthesis so let me just shut down the terminal real quick and we are going to install one package which is going to be axios you could do an axials request or fetch request when calling data from the front end to the back end and we will use axios so we're going to import axios at the top here from axios and then now before we even do axios here we actually do need to create a back end for this register API endpoint okay so now we successfully set up the front end for the register when the user needs to register now we need to set up the backend API call for this register as well so to do that we want to install one package before we get started and that's going to be bcrypt reason why we are installing bcrypt is because we want to Hash passwords before we send them to a database now that we have the um package installed onto our project we are going to go inside the API folder create a new folder called register and then inside of the register we're going to have a route Dot jsx so now this is where all the backend API is going to be and then the front end is going to call the back end which is going to be here so we are going to import bcrypt from bcrypt we're also going to import prism because we need to use some prism functions and methods and this is going to be from and we're importing it from the global lib file that we created earlier and we also need next response and this is specific to next.js and this allows us to send responses back to our client so now we are going to create an asynchronous function and we don't name functions like I said in routes we just call them whatever the HTTP request is so it's a post request and it's a request taken as a parameter and inside the code block the first thing we need to Define is the body so the body is going to equal the request dot Json also we want to destructure the body so we're going to have a name email and password coming from the front end which is going to equal the body so now we restructured it and now I want to do a few checks so if they don't enter a name email or password we want to make sure that we send an extra response saying that there's missing fields so to do that we are going to do if no name or no email or password we want to return a new next response saying missing fields and then we want to give a status of 400. so that is the first check we are going to do inside of the back end and make sure they actually entered something in the inputs when they register next thing we want to check is we want to check to make sure that there is no user already associated with the email they're trying to register with so for example we are going to create a variable called exist and we're going to await a Prisma dot user dot find unique and this is going to take an object and this object is going to have a where and then this object is going to be an email so we're just checking R against our database using prism to make sure there's no email associated with the email they're trying to register with that's all we're doing here in this code so then right below it we're going to say if exist is true that means if there is an email that does match what they're trying to type in we need to throw a new error we need to stop them right there because we only one person can have one email each email has to be unique so we're going to say email already exist so there's that error and then if they pass that check error we need to Hash their password that means that their email is fine the username was entered I mean their name was in there their email isn't used by another user so now we need a hash their password so we're going to say hashed password and then we're using bcrypts function of hash that means we're going to Hash the password which is the first parameter take send the password which is the string and then this is the salt the salt you're going to put 10. this is just going to be the strength of the hash of the password so after reading we hash the password we need to now create the user in the database because we are registering the user so we're going to use the prisma.user.create function we are going to have the data object with a name email and password which we don't need password here we're just going to put a hash password and we are going to close this object and make sure everything is closed properly and then close that as well and that allows us to create the user in our database so after that step is done we are good to go for the register function and all we have to do is return that user and returning the user with the next response dot Json and user so that is going to be it for the register route now what we can do is we can actually test this route with the front end but first we got to hook it up before we even test it because I did stop in the front end before we actually finished all the code so if we go back to the register page on the client side inside of the register user function we need to use axios to do a post request to that specific endpoint we just created and that is slash API slash register and the reason why is because it's in the API folder and the register so that is the path we're using and then we are going to pass in the data oops data and the data is whatever they enter those on change values after that we could do a DOT then this is going to take an arrow function and this Arrow function for now we could just do an alert saying user has been registered and then we could do a DOT catch and then we could do an alert saying an error occurred so now we could test this out and obviously if it works we're going to get this alert and it's going to also be registered into our database the new user so let's test this out real quick before we continue with anything else so run the development server on localhost 3000 um just reload this to make sure everything's good nope I did a minus sign not equal Okay cool so let's check the console make sure we have no errors so we're clear for the console let's type in Brett Brett gmail.com and then one two three four five six seven eight I'll do is the password we will inspect the page before we click the button we will go to the network tab and we'll see what requests we get what status we get back so we're going to click register and an error occurred so we obviously did something wrong it says we are missing fields so we could check back and see what we did but it looks like we did type in everything so we typed something wrong on our code so let's minimize this go back to our register route which is our backend and we said if there is no name no email or there's no password we're going to return next response missing field status 400. so let's look to make sure that looks good name no email no password return new next response missing field status 400. name email password body request.json we didn't in a way to here that's why because if we don't await it that means it's just going to keep going with the function and even though this takes a few milliseconds we need to await the request because it is takes time to process to come to the back end so let's try it again and we shouldn't get an error now so that's just like a quick debug real quick to make sure everything is working good so you just go back make sure you have the error codes and see what's going on so we're going to go to refresh the page I'll type in Bret we'll do Brett gmail.com and we'll do one two three four five six seven eight we'll click register and this time the user has been registered so we do get a 200 request we have all of this information here we have an ID created we have all of the um schema properties here created for this user the updated that we have the hash password the ID the email verified we have a post request of a 200 status and it's requesting to the endpoint API slash register so now we can check our mongodb so let's just go into mongodb and sign in real quick and we're going to make sure that this user is actually in the database so we are on the correct collection we are going to browse the collection it's going to be test slash user and we have a Brett and then Gmail with the hash password and the ID it's underscore ID so everything works on the register API and and also on the client side as well now we are going to create the login client side page we are literally going to do the same thing and we're going to take a template from Tailwind CSS which is the tailwind.ui so if we go back to the tailwindui.com we could literally just take the same sign in form not a big deal copy all of the code again minimize Pace it in the front end code so we could close the API folder make sure in this site login and then page jsx we're going to paste it remove the comments because we don't need them and then at the top of the page we need to use client we need to tag it with the use client reason why is because we are going to use use state from react and let's change the function name to login we are going to initialize the use state by doing the variables data and set data as an object we're going to take in the email and we're going to log in with the password so that's what we're going to log in with now we need to add the values and on changes on the inputs so the value is going to equal data.email and then the on change is going to set the data and change the email to the e.target.value and then same exact thing here for password okay now both of these inputs we are getting the state from what the user is typing and we are not using axials for this specific file the reason why is because next auth provides us the sign in function that we could Import in here so the next thing we are going to do is we are going to make sure everything is set up inside of the back end of the login API okay so I just wanted to check to make sure the login page everything looks good the console looks good and it's a sign in with email password and sign in perfect so like I said we are going to start working on the back end but before we do that we are still in the front-end client page login page I just want to remove this right here the action and post we're going to have on submit and we're going to have a login user as a function and then we need to create this function so it's going to be a arrow function with e dot prevent default and then let's just close it that's all we're doing for now let's make sure the page looks good refresh it everything looks good no console log errors as well okay perfect so now let's actually start working on the backend API of the login so this is how we're going to authenticate the user and this is the main part of the whole tutorial so to authenticate user with the login you could either do it during Google GitHub or you could do with the credentials provider right now we're working on the credentials provider and that is the most difficult one to do so to do it you have to do it inside the catch all route which is in the route jsx file inside of it where you do all the logic and authentication is inside of this authorized function so right now all we have is a static user named Brett with email at Brett gmail.com we just created the register um API endpoint and we made it functional so now we could actually register users so we don't need the static user anymore what we need here is we need checks to make sure that everything is checking right and make sure everything's right before user logs in so for example if somebody's trying to sign in they need to make sure they type in the email and password if they don't we need thrown error we need to also make sure that that email is in our database so they can actually log in with that account another thing is we need to compare the passwords so that these passwords match and if they do match we can log them in and if they don't match we are going to throw an error saying the passwords do not match so first we are going to remove this static user and let's give us some space and let's do a comment saying we're going to check to see if email and password is there that's what you really want to check so we're going to say if there's no credentials.email or there's no current credentials.password we're going to throw a new error saying missing fields we can obviously change the error message or whatever we could say please enter and email and password so that means that is the first check they had to pass it's like almost like in sequential order so they gotta check this check and if they pass that check they get to go to the next check so this is the first check very simple right so the next check we're going to do is okay they typed in their information correctly now we want to see if the user actually exists if they're actually logging in with the registered user so to do that we are going to say cons user equals a weight and then we have a Prisma function saying find unique that means we are going to go on our database and we're going to find that email and make sure it matches up with the sign in email as well so it's going to be passing an object with the where object and we're going to look for the email of the credentials email and we're going to try to match them up so let's close this up and then after that we need to do a check so we're going to say if user doesn't exist so if no user was found actually we'll say that if no user was found so if we look through the database and we don't find a user we need to run this specific check and throw an error at this specific client so we're going to say if there is no user or we're going to also say if the user doesn't have a hash password reason why is because we're going to have users in our mongodb database that just have password and the reason why is because if you look at the schema.prism there's not a hash password for the account right hash password appears optional so if somebody signs in with the GitHub or Google they and they they don't have a hash password so how are we going to authenticate them when they log in we don't so that's why we need to check that as well so we're going to say if there's no user dot hash password right so if we don't have a user or the user does not have a hashed password we are going to throw a new error saying no use your phone I mean if you're logging in with a GitHub provider you always log in click in the GitHub provider button you do not log in here so that's why we have to throw this hash password error as well so that's for that and then the next check we do is if we do find the user and the user does exist they will pass this check that means we're going to check next to see if the passwords match so we're going to check to see if the passwords match and the way we do this is we have to use bcrypts compare functional function so to do that we have to import B Crypt at the top so we're going to import bcrypt from bcrypt so we could use the compare function and method so we are right here we are going to do cons words match and we're going to await the B crypt.compare and the first parameter we are taking the password that the user actually typed on the sign in form and then we're comparing it to the hash password in our database so then we need to check right after this saying if passwords don't match so if they don't match and they typed in the wrong password we're going to say if the passwords match is not true that means they typed in the wrong password we're going to throw a new error saying incorrect password and we're going to close it right there so that means that they pass all these checks that means they actually logged in with a user that is in the database so after that we are just going to return the user so right here is all the functionality from lines 27 to line 54 about 27 lines of code to actually verify to make sure that this user is in the database and log them in and to authenticate the user during a login process so now I want to test out this code right here that we just made to make sure I can actually log in successfully so if we go to the login page we have to connect that backend code right to this front-end client side right here and like I said before we can't use axios because next auth provides us a sign in function that allows us to use so we must import that at the top so what we're going to do is we're going to import sign in and this is going to be from next auth slash react so we're gonna have to use this sign in function here instead of axios so to do that it's going to look exactly like this we're going to sign in the credentials with the credentials of their backend and then we are going to pass in the data through a spread syntax so data and then we're going to have a comma and then redirect will be false and if you don't have redirect as false it is going to redirect you to a pre-built next auth page that we don't need to use so we're going to have that there we're going to close this and then we could close this as well for now obviously we're going to have then and catch statements in a little bit but we'll do that one after we test this out correctly we can actually do a DOT then for now and we could just say alert user has been logged in so that would actually alert us is saying hey we're logged in and we could just check the cookies to make sure we're logged in as well and we could go on the home page and see what it renders for user so let's check this code we are running let me just reset the development server just in case let me go back to my localhost 3000 I will refresh the page and we are just going to use the registered user that I already registered so as we remember it's Brett gmail.com and then the password is one two three four five six seven eight so we're gonna do Brett gmail.com let me just switch the network tab and then we're gonna do one two three four five six seven eight we're gonna sign in and it says user has been logged in we can make sure to by looking at the application we do have a next auth session token that's where all the session data is and we could access the information and then I could just go to localhost 3000 minimize this real quick and then it says username Brett and then Brett gmail.com and this is the account that I just logged in and registered through mongodb so that means everything is working how it should okay now I want to download and install a package onto our application which is react hot toast so react hot toast is going to give us toast notifications so these are professional looking notifications if somebody logs in successfully or an error occurs you can do alerts like we've been doing so if you don't want to do the step you can skip this and just go to the next step everything is time stamped as well so the package we are going to install is npm install react Dash hot Dash toast and the way this works is we need to wrap our whole application with the provider and it's going to be like a toaster provider so to do that instead of going to the layout we need to go inside our contacts folder create a new file called toaster context.jsx or whatever you want and then inside of this we are going to mark it as a used client and then we are going to import toaster from react hot toast we're going to create a function called toaster context and then we are going to return poster and toaster is a self-closing tag so it's going to look exactly like that we will close this and then let's export it so we could use it inside of our layout file so now we are going to go to our layout file and inside the layout file we have to self close tag this so it wraps around all the children so we will import toaster context from contact toaster and then we could put it right behind this first provider and it's like I said it's a self-closing tag so just like that so now that allows us to use toast notifications throughout a whole application so the first page I want to do it on is the register page so if we go to register oops that's API close your API folder go to the front end we're going to go to the register page and instead of alert we will do toast Dot success and then it says user has been registered cool so that's if this works this API endpoint works then we're going to send this notification and if it doesn't we should send a toast dot error something went wrong perfect so that's that toast right here for notifications and now let's implement it for the login page so for the login page it is a little bit different the reason why is because for the then we are going to take the parameter of callback so when we use the sign in function with next auth it is giving us callback options and properties so this is the property we're going to use and then we're going to call an arrow function and then we're going to do an if statement so we're going to say if there is a callback error so if there is a callback error we want to run the toast dot error and whatever the callback.error is so for example the Callback dot error is going to be whatever we put inside of our backend code right here with this error so if they didn't enter their email and password it'll throw this error they didn't have no user found in their database it's going to enter this error if it was an incorrect password it'll enter that error that would only work if you pass in the Callback dot error so then that's if it fails so we're going to say that let me see where this code ends [Music] okay and then we're gonna have another if statement inside of the then so if there is a callback dot okay and there is no callback error we are going to run a toast success message so we are going to say toe success logged in successfully so that is all we have done so far for toast notifications now we need to test them out so to test them out let's start our development server and I'm going to register a completely new user so we're going to go to the home page and see if we're still logged in so technically we're still logged in I will inspect the page go to application delete all of these for now obviously there's an easier way to log out but that's just going to be what we do for now we are going to go to slash register and then on the register page let's register a new person so we could do Tom and then Tom gmail.com and then we'll do the same password one two three four five six seven eight and before I click this we should get inside of the register page user has been registered if everything worked correctly and then if it didn't something went wrong so we will click register and we have one error toast is not defined and it's because we didn't import toast at the top so let's open up our vs code again and we didn't so we just can't use toast without importing it so let's make sure we have it on the top of both pages so here's the register page import host login page we imported toast okay cool so let's go back and let's try again so we register something went wrong uh where's the network tab we have a 500 error let me try to refresh it and try it with a different user let me make sure that user actually didn't get registered and it did so the reason why we got error is because when I did submit the uh register it gave me an error that told us wasn't defined but still submitted our user so let me delete him real quick tomatoma Gmail now we only have that one user let me go back to localhost refresh the page and let's register again Tom Tom gmail.com one two three four oops one two three four five six seven eight and then let's register and it says user has been registered and we get a 200 okay post request and we see all of the information of the user we just created in our mongodb database let's just confirm it with mongodb as well and we have a brand new user right here cool so now I want to go to the login page so slash login and we are going to log in now with this user Tom gmail.com and it'll be one two three four five six seven eight and then we'll sign in and right now we are not getting any notifications popping up but it looks like we are logged in let me see and we are logged in and you could tell we're logged in by just going back to the home page and we have Tom and then Tom at email so the only thing that's not working is the toast notifications for the login page and let's fix that right now okay so let's fix this toast error problem that we have and let's just look back at the code and where the problem is actually happening so we don't have to sign out button so let's delete all these tokens refresh the page make sure we're signed out and it says null perfect let's go to our login page again so we're prepared to log back in and let's look at the code for the toast so we're on the login page let's review this code and make sure everything is good we have the sign in function signing in the credentials API provider we're using all of the data which is the email and password the redirect is false if it's true if it's true then we are doing the Callback and if there's an error we're doing a toast.air.callback error and then we're saying if the Callback is okay and there is a callback error which if there is no callback error so that's the issue right there it should be the issue so if there is no callback error then we do toast stuff success logged in successfully because we're saying if it was okay and there was an error then you run this so it didn't make any sense so let's try it again and hopefully that is what fixes the code so let's do Tom gmail.com one two three four five six seven eight sign in and it says logged and successful so that is why there was an error not popping up with the toast notifications now let's just make sure all of the error messages are working correctly too so let's delete everything refresh the page and let's do a Tom gmail.com and let's just give some random password like we forgot our password and we're trying to guess so we try to sign in correct password perfect okay so let's do this and then let's um do an email that's named part of the database so tom23 gmail.com no user found so it's checking it in sequential order so if it's checking the user first and then if the user is good then it's going to check the password but if the user is not good it's going to throw that right off the bat and then if we don't have anything in this field the email address uh you can't see it so if you don't have anything in the password it says please fill out this field and that is from the at Tailwind CSS forms package that we installed when we created this template so that's that check right there so it looks like everything is working pretty good and everything is actually working how should so the next step is we actually need to create a dashboard for the client and we also need to set up the Google provider and we need something GitHub provider as well okay so first we will set up the GitHub provider what we are going to do is we are going to set up a button below the sign in or you can do on the register account we'll just join the login page you can do whatever you want for your application but we're going to set up a button below saying to log into GitHub and then you click the button and then it will authorize you to log into GitHub and then authenticate you as well so to do that let's just first go into our code and inside of the catch all route as you can remember and the GitHub provider we have a client ID and a client secret that we have not got yet so to get it we need to go on github.com so if you go to github.com obviously if you don't have an account sign up for an account and if you do log into your account at the top right you have a down arrow click settings inside of the settings we are going to go all the way to the bottom left to developer settings oauth apps new oauth app the application name is going to be next auth we could do practice the home page URL is going to be your localhost 3000 we don't need a description and the Callback is just going to be wherever you wanted to call back we could just do localhost 3000. okay so we're going to register the application and it's going to give us a client ID and then we need to generate a new client secret so let's just copy this client ID because we do need it so we're going to copy it go inside of our EnV file I think it was called GitHub underscore ID cool so we are going to name a variable called GitHub underscore ID and this is going to equal that client ID I think the other one is called GitHub underscore secret and this will be that secret key yep secret cool so now we need to get the secret key by clicking generate a new client secret key we got to confirm our password and then after you confirm the password knowing it's you here's the secret we could copy it minimize the page paste it here and now we have the GitHub ID and the secret cool now we are going to go to the login page and we are going to come all the way down below the sign in button underneath the form we are going to just do an H1 it's not going to look pretty and we're going to say sine into git Hub below then we'll have a buy-in and then we'll just say sign in and then let's just style it just real quick class name BG black text White and then we could just do with we could do with full see how that looks okay so there's the GitHub sign in obviously I spell whatever in the H1 wrong sign in to GitHub and then there's that now we need to unclick on this button so the on click we're going to have an anonymous function that's pointing to the sign in function that allows us to use it inside of next auth so sign in and then we are just going to do a string called GitHub so this is all you need to do for a basic understanding of how to sign into your GitHub account so after we do that this should work but let me just restart the development server just in case and then we're gonna do npm run Dev go back and we're going to refresh this localhost 3000 slash login after it's refreshed we'll click sign in and as you can see now it's trying to authorize this account we will click authorize B Westwood 11 which is me and then technically we're signed in we can expect the page application we have a session token and we could just go to the localhost 3000 and then there's the name email and it's client-side render stuff like that and that is the email associated with my GitHub so now we could check our mongodb database and since we signed in we should have an account so now we have an account with our GitHub provider as the provider type is oauth and we have all these properties too then if you look in the user is also in the user as well right here so like what we did in the Prisma schema we did a one-to-many relations between the user and account schema that's why I said all of the users no matter what provider they use will be in the database under the collection user so that is why this looks like this and like I said with the no hash password in the code earlier for the login um logic as you see the GitHub provider doesn't have a hashed password field so we can't use this email to sign in with the credentials provider it only could be signed in with the GitHub provider okay now so now let's set up the Google provider so to set the Google provider we also need the client ID and client secret we are going to go to Google and you're going to search Google Cloud console click the first link and then your page to look something like this you should be logged into your Google account the top left I mean top right we're going to down click this and we're going to click new project you can name your project whatever you want YouTube next auth um and then just click create so now it's creating your project we can select the project and then we could just go to API and services and then after we click API and services we need the oauth consent screen we need to create one so this is like the screen that pops up when you want to sign in with a specific Google account it's on a lot of websites you've probably seen it before so for this consent screen we have to we have to actually go to the right one I don't know why I was on that one so YouTube Dash next auth make sure you're in the right project and then it's going to prompt you to a few questions on what you should do so we are going to make sure it's external so it's available to any test user with any Google account we need an app name so we're just going to YouTube next auth support email is going to be Auto populated for you so click that you can skip all of this and then your developer contact information you could just do the same email as well it is required press save and continue the Scopes you could add or remove Scopes you could click the first three this one this one and this one click update then we're going to click save and continue you don't need to add any test users so save and continue this is just a summary of everything we did so you're going to go back to the dashboard after you're back at the dashboard we are going to create some credentials so click the credentials tab make sure you're in the right project click create credentials now you're going to click oauth client ID application type is going to be a web application you keep this name as is it's not a big deal and authorize redirects we are going to do okay so for the authorize redirect URI we are going to do http slash localhost 3000 slash API slash auth slash callback slash Google and then we're just going to click create so now it gives you the client ID and client secret that we need for our project so for this we are just going to copy the client ID go back into our vs code and we're going to make sure it's named correctly so it's Google ID and Google Secret so we're going to have Google underscore ID that's what we just copied and then Google underscore Secret go back to that oauth consent this is the client Secret copy that and paste it and now we have the keys ready for our Google authentication okay so now let's create the buttons so we can actually log into our Google provider all we needed was ID and secret which we just got and I am on the login page on the client side and we have the sign in to GitHub below with the button I am just going to copy and paste this down I could just do background of green instead say sign into Google below and then we are just changing the string on the on a click from GitHub to Google and we're having this sign in function from next auth so we could test this out we can go back to our localhost 3000 let's go to the application and let's just log out of all of our stuff by deleting the cookies we will go to slash login nothing wrong in the console and then it says sign into Google below did I copy something's not popping up right let's check the code again because the button doesn't look like it's right there I guess BG green is actually not a background so let's try it again BG red the 500 I know is one okay so there's our sign in with Google if we click that we should be able to sign in with the Google account so we click it and as you can see we sign in with the Google I could just do this one right here and now we are technically signed in and we can inspect the page look at the application we have three tokens again we can go to the localhost 3000 and here is my name Competitive Edge email competitive.edge.tamp.gmail.com so we are successfully logged into Google let's just make sure our mongodb has that information as well if we go to account now we have two accounts we have one with the provider GitHub and one with the provider of Google and then if we look at the users we have the Competitive Edge in here as well so everything is working as it should now you could sign in and register with authentication with the Google provider the GitHub provider and the credentials provider the last thing I want to do is I want to show you how you can protect a page if a user is logged in or not there's multiple ways to protect pages when it comes to next auth but I am going to show you just one example of how you can do it and then you could pick from the docs of which ones you want but the code is pretty simple and straightforward so if we are on a client-side page you have to use a client-side method to do this so for example if we go to the login page we are on the login page it is a use client page I am going to also import the use effect because we're going to use that and I am going to call the use effect function right above I mean the use effect hook right above the login user so we're going to have a use effect and this use effect is going to be an arrow function and inside of the code block we're going to say if the session which is the object we're getting Dot data node.stata is my fault if the session does status equals authenticated then we want to do something which means we want to actually push the user away from this page because they're already logged in and we want to push them to the dashboard so there's a few other Imports we're going to import real quick first we are going to import they use router from next slash navigation not router another thing we want to import is we want to import use session and we could import it right with the um sign in function right here so we need to actually get the session from the client side so we could do a cons session equals use session and that's going to allow us to get the session if it isn't and then if the session status is authenticated we do want to do a router.push but we need to actually initialize use router so cons router equals use router and then we're going to say router.push and then we're going to push it to the dashboard that means we are logged in and we don't need to be on this page anymore so this is one way to protect a page and the page we're protecting is the login page if we are logged in and authenticated so let me just terminate the development server real quick restart the development server let me open up a new localhost 3000 we are technically logged in right now let me inspect it real quick I could just delete the cookies refresh the page all right we're going to go to slash login and we can log in with the Tom Gmail and then we can do a password one two three four five six seven eight we will sign in logged in successful and then it's pushing us to the dashboard page which I have not created I thought I did so we can just create a new folder called dashboard and then inside the dashboard we're going to have a page.jsx let's name a used client at the top let's import use session and this is going to be from next odd slash react then we can just do a arrow function remove this call this dashboard if I could type and then right above the return we have to create a session variable using the U session hook and what we could do here is we could just [Music] say H1 dashboard and then we could do a P tag and then we could say hi and then session Dot it'll be a question mark dot user Dot name or we could just do email perfect and this is going to get the session import session we have the data okay cool so now if we go back to this page let's try to go back to the login page is not defined it says cannot read properties reading of null reason why is because it is client-side so it is taking a few milliseconds to solve so technically the email is null so I do have to put a question mark in front of this as well and it looks like it's not working and it's not working it's because we are not I see why it's not working it's because when you do this we are actually getting the data from the session so we have to create this as an object and we have to write this a session like this so let's go back to the code and now says hi Tom gmail.com okay so let's redo that whole process again and let's actually create the sign out button as well so we are going to import sign out from this next auth and let's have a button right here we will say sign out and this will be an on click Anonymous function sign out and we're just gonna no parameters are gonna be passed in it's just going to sign out the current user okay so let's go back click sign out and now there's no user even if we refresh it let's go to the login and if there is no user we could stand the login page so we're going to do Tom gmail.com one two three four five six seven eight we're going to sign in it's going to say we logged in successfully push us away from that page and bring us to the dashboard saying hi Tom gmail.com we click sign out and now we're not logged in anymore even if we go to the low cost 3000 it will give us nulls so that is a lot of information I know to digest especially in one video but everything will be time stamped it did take me a while to learn all of this stuff as well so don't get frustrated if you're watching this video but if you like this information to authenticate users for your application is a very useful skill to have so if you did like this video hit that like button and also subscribe for more content like this that would help me get out more content also motivate me as well so thank you for everything and also have a good day
Info
Channel: Brett Westwood - Software Engineer
Views: 49,083
Rating: undefined out of 5
Keywords: NextAuth, NextAuth Tutorial, Authentication in NextJS, NextJS 13 Authentication, AuthJS, How to protect pages in nextJS 13, NextJS Authentication Step by Step, The Ultimate Guide to Next Auth, How to use Next Auth, Google Authentication in NextJS, Credentials Authentication, How to authenticate users in nextjs, tutorial on Next Auth, How to send users to MongoDb database, Create login and regsiter page nextjs, API endpoints nextjs, next js, next auth
Id: PrdbyNYq-z4
Channel Id: undefined
Length: 96min 26sec (5786 seconds)
Published: Wed May 17 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.