How to use Credentials Authentication in Next.js with NextAuth?

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Hello there everybody welcome back to another video and in today's video we are going to set up NextAuth with the credentials provider in Next.js. So essentially you will be able to add authentication in your Next.js app with username and password. Now we are going to be using the NextAuth library in this case and as per my experience I have faced a lot of troubles adding the credentials provider which means adding authentication using username and password. So this video is going to help you out with that. Alright so the very first step is to create a Next.js app. So I'm just going to go ahead and say npx create next app. So let's do that next app and I'm just going to say dot and then I'm just going to add the dash dash ts to use TypeScript. You can still use JavaScript it's fine but I'm going to be using TypeScript and the code won't be very different so you don't need to worry about that. We are also going to be using Prisma which is an ORM for relational databases and MongoDB as well. So we are going to be using Prisma if you use some other database provider and you can still use something else if you use in a different ORM you can still use that with NextAuth it provides a huge support for these other ORMs as well. Alright so once our app is initialized now let's set up Prisma. If you don't want to see how Prisma is set up and all that stuff you can skip to this time step above and let's do that now. So first off we are going to npm install Prisma with the dash uppercase d flag. Now that Prisma is installed as a dev dependency we are also going to install the Prisma slash client. After that is done we are going to install the Prisma adapter for NextAuth which is also required. So let's do that final little thing npm install NextAuth Prisma adapter. Now let's go ahead and say npx prisma init which will initialize Prisma for us and it's going to create a .env file which we should not commit to git. So let's just go ahead and add this to our gitignore real quick that's it. Let's remove all these comments and in the database url I'm just going to say file colon dot slash db dot let's just say test dot db really doesn't matter because we are using SQLite right over here just for this demo. Once we have that let's go inside of this Prisma schema where we have let's change this provider to SQLite and now let's add these tables. So if you go to this page I'll put this link in the description below you'll find a lot of details about this. So we'll just go ahead and copy these models that we need for this to work right. So we can just go ahead and say model account I guess that's all we need and now we could just go ahead and paste this. Now we have to make a few changes because we are not using we are using SQLite so we don't need db text let's get rid of that and also these little things let's remove these and that's all. Now one thing that we have to change is in the user model right over here in the users table instead of having an email we are going to have a username right and you can also have the email verified it really doesn't matter. So we're going to add the username and additionally let's add a password which will be a string and username is not going to be optional. That's all we have right over here now let's go ahead and run npx prisma migrate dev so that we have all these tables created. I'm just going to say init that will be the name of our migration and if you see there's our db. Now let's go ahead and install next auth. So what we will need in here is npm install next auth then we are going to need two more dependencies so that is first one is zod and the other one is bcryptjs. This is for our schema validation so when someone sends a request to our api we can validate that and bcryptjs is simply a library so that we can hash our password so let's do that. Since we are using typescript we will also need to install at types slash bcryptjs as a dev dependency so let's do that again. Now let's go ahead and create a register out because next auth is not going to handle our registration function. So basically when the user signs up next auth is going to handle the login functionality where it's going to have a jwt token that it returns and it's going to store that in the next js app and all that stuff so that we don't have to worry about it. What we can do is we could go inside of the pages api directory and let's create a folder not a folder but actually a file called register.ts and inside of this register.ts file let's actually write the code for our back end for a registration. What we can do is we could just export default an asynchronous function and we're going to call it register user let's just do that and this is going to take in the request which will be next api request. Now again if you're using javascript and not typescript you can skip this part easily. Then we have the response which will be next api response as simple as that. Now when the user registers we need two things from them the username they choose and the password they choose. So what we can do is we install a dependency called zod and with zod we can validate if the user sends us the correct data or not. So what we are going to do is we're going to create a register user schema. Now if you don't know what zod is just follow along with me so what we can do is we are going to just say z and that will be imported from zod right there z dot object and call it as a function and then inside of their first property is going to be the username and that is going to be z dot string not strict object string and what we can do is we can sort of make it a username. So this is a pretty cool website I really like called I hate regex where you can find it regular expressions for your app. So I'm just going to copy this regular expression for username after copying the username regular expression we could just go ahead and change this regex method and here we will need a regular expression so I'm just going to go ahead and paste this in within these flashes and I'm going to add gm for global and multiline we don't need multiline and then in here we could add the error message which is going to be username invalid or let's just say invalid username. Next up we are going to add the password so let's add a comma and let's say password that is also going to be a z dot string and also we're going to add a min of one which means it should have a minimum length of one actually it should have a minimum length of five because it's a password right and let's also go ahead and add the error message so password here would be minimum five const something is equal to register user schema the variable we created above dot parse and we can parse whatever the data comes from the user which is request dot data let's do that request dot data actually it's request dot body my bad so this will be the body that user sends us through the post request so once we have that we have the username and the password properly parsed I'm just going to collapse that and let's go ahead and say const prisma equals to new prisma client which will basically allow us to create prisma queries all right now that we have prisma right over here what we can do is we could check if the user already exists and we can do that by simply let's just say const user is going to be a weight prisma dot user dot find and I'll just say find unique in this case and we'll say where username is going to be equal to the username so if you don't provide the key and the value you can just provide one thing which is basically this refers to this so where username and this will be either the user or null so what we can do is we could say if user is well not equal to null what we can do is we could just go ahead and return let's say return rest dot send and we can send back user null and message user already exists all right so once that check is done let's go ahead and create the user so basically the user is not null we are going to return that user is or user already exists next creating a user so I'll just say const new user new user is going to be equal to await prisma dot user dot create and then we can create a new user by passing it in the data so the data is going to be the username and the password but what we don't want is that the password should be hashed we don't want to just send the password right away so what we can do is we could just go up top right over here and we could say const hashed password is going to be equal to bcrypt dot hash now this is what we have to import manually I don't know it does not work this way so I'm going to import bcrypt from the library called bcrypt.js remember that's the different name and then inside of hash we have to pass in two arguments first is the password that we want to hash which is basically password and the next is the salt so by default it's 10 I'm also giving the number 10 and the password is going to be hashed password that we get back from right over here and the problem is that this will return hash will return a promise of string which means we have to await this first once we have the new user created let's just go ahead and return actually return rest dot send the user is going to be equal to new user and let's add the message that user created successfully all right that's it that's all we need for this basic implementation you can take this forward because this is just a bare bones implementation of the register function now let's work on authentication so inside of the next auth docs you will see we have to create auth folder an auth folder and inside of the auth folder we have to create this file with this name so with these brackets and dots let's let me just copy this part coming back to bs code in the api folder I'm going to create a new file actually wait in the api folder create a new file and then just add dot ts after that so it's going to be auth inside of the auth folder is going to be next auth dot ts now this file is going to be longer than we think first let's go ahead and create a variable called auth options so I'm just going to auth options this will have a type of auth options that comes from next auth and it's going to be an object now what we could do is we could export default export default next auth this is a function that comes from next auth again and we have to pass in the auth options right over here now inside of this auth options we are going to first off add the prisma adapter that we installed previously so what I can do is I could just say adapter adapter is going to be prisma adapter and right over here what I can do is I could just go ahead and say cos prisma equals to new prisma client so we just go ahead and create a new prisma client and then we just pass it right inside of the adapter then we can go down and we can add the credentials provider basically the provider that we want to use and that's called the credentials provider so I'm just going to add an array called providers this is going to be an array where we have to add credentials so if you write credentials it will automatically import it but let's make this let's change this with f2 and I'm going to make it credentials provider so that it's more clear now again this is a function inside of here we have these options now these options are pretty simple but we have to work quite a bit so the first step is adding the credentials what do we need from the user so if I go ahead and let's go inside the object we will need the credentials and this again another object with a username so the first step is going to be the username and if I just go ahead and open up another object it's going to have a type and a placeholder and a value so I'm just going to give it the type of text which basically means an input type text and then we could just go ahead and give it a placeholder for test at test.com okay and then we could just copy and paste the same thing but this is going to be password now and this is going to be the type of password and it's going to have a placeholder of let's just say password something like this really doesn't matter once we have the credentials set up what we can do is we could just go ahead and add a method called authorize so this is the authorize method and what we have to do is for now just to remove the errors I'm going to return null so this authorize method will return either null or the user back so what we need is we first want to make it asynchronous let's make it async so it will return null when the user does not exist or the authorization failed for some reason and will return the user object itself when the authorization passes right so basically you return null if the user does not exist or the password is wrong or something like that now as we did in the register page if I go back this register user schema we can do the same thing with the login schema so let's go right over here and I'm going to paste this and this is going to be login user schema and let's just import z from zod and then what we can do is we can pass the same way we did inside of the register function right over here so what we can do is let's just go ahead and say const something is equal to login user schema dot parse and we want to pass in the request dot body actually instead of doing request dot body we have the credentials object right over here which you can simply pass in right over here so we get back a username and a password now once we have done that let's see if the user exists or not so what we can do is we can again bring in prisma so const user is going to be await prisma that we already initialized right over here so prisma dot user dot find unique so we can find unique where the username is equal to the username as simple as that so we are finding the user by the username not by the password because this password will not be hashed and in the database we are storing hashed passwords so this is again going to be either user or it's going to be null so what we can do is we could check well hey if not user then return null which means the user does not exist so we return null and you're not logged in back in here what we can do is we could go ahead and check if the password is right or not so the username is right but the password is right or not and we can do that again with bcrypt so let's go to the top and i'm going to just go ahead and say import bcrypt from bcrypt js then let's go down there right over here and i'm going to say const is password valid like so that's going to be equal to await bcrypt dot compare now here we compare and if you look closely this is s and hash so s basically means what the user provides us and hash is the password that we have in the database so s which means the password that we receive from the user and then hash is going to be user dot password which is basically this is the database password right this is the hashed version of it so this is going to give us a boolean value and what we can do is we can again check if not is password valid we can again return null which means the password is not valid you're still not logged in and finally if everything is done what we can do is we can return back the user so this is essentially the authorized function which you have to write on your own now the other thing that we have to add is the thing called callbacks so i'm just going to collapse the credentials provider and coming out of the providers array you can add a property called callbacks which will be basically called after some code runs so the first callback we are going to add is called session so if i just write session you see this is how it works in session we get back if i just expand this we have the session basically the session of the user and the token so whenever the user tries to get the session right whenever we try to write in our code that if the user exists or not what we can do is we could go ahead and say session dot user dot id to the token dot id now it might give you some type errors right now but ignore it and then we can return back this session so all we are doing essentially is just adding an id property on the user so that we can access this id on the front end where we try to get the user once this part is done let's again do this let's add one more callback which will be called jwt so in the jwt callback we are going to get the token the account and the user so basically when we append this id to the token we can append this id to the user in the session right and we can basically make a check so if account exists right so if the user is created we set the token dot access token that will be equal to account dot access underscore tok and then token dot id will be equal to user dot id and then finally we are going to return back the token now this return token will come over here and give us the id inside of the session now let's see how we can fix this type error so right over here in the root i'm going to add a next dash auth dot d dot ts now do this only if you are using typescript if you are using javascript you don't need to worry about it first off you're going to import next auth from next auth not like this instead we have to import it from the next auth package so let's make proper and then we can declare module next auth and we are going to just change the interface called session so all we are doing is we are modifying the types internally in the next auth and what we do is we just say user is going to have an id id of string and so you add an n percent and you can say session index user so basically you say well hey user is also going to have an id with the default user properties that it has and that takes out the type error all right so now the callbacks part is done as well let's go below and we are going to add the pages so basically we want to say we want to tell next auth that the sign-in page so basically the sign-in page will be slash login which is the page we are going to use where our user will log in so we don't want to use next author's page we want to create our own page then we could go ahead and add session inside of the session object we can add the strategy of gwt so what this basically means is that it's going to return a json web token that will be stored in the cookies and all that stuff finally we have to add a secret so let's just do a secret and it's going to be process dot env dot i'm just going to call it jwt secret it really does not matter so let's just copy this and i'm going to go in here and i'm going to add this secret as some random gibberish make sure to make it random and not to expose it so now we are done with this file completely let's get rid of it now let's work on the actual ui so i'm going to just kick start the dev server npm run dev with the turbo flag so that it starts up easily this is how the page looks like okay so i quickly went ahead and added the login page and register page so if you just if you just go ahead and say register here you will go to the register page or the login page and also if you want to do this yourself you can just go ahead and do this yourself but i have the code on the github repository which will be linked down below from where you can just copy all of the css code and all that stuff coming back to the register page which is the first functionality we have to do so what we can do is when the form is submitted we can basically submit this form with these data now i'm just going to go ahead and create a function for submission so function on actually let's just call this handle submit and this will take the event in itself which will be form event right now what we can do is we could just go ahead and chain this on submit is going to be equal to handle submit now inside of here first off we are going to get these input types so it this input has a name of username and this one has a name of password so what we can do is we could just go ahead and say const something is equal to new form data and this form data in itself will take the e.target so we could say as it's going to be html form element now if you're using javascript don't add these type annotations this one or this one you could will be fine with without these and over here we could just say well we get back the form and now let's see how we can push to this api so we have created this api slash register file what we can do is let's close this out so we are going to do something like this let's make this asynchronous first and then what we can do is we could say fetch now fetch is going to take in the route which is going to be slash api slash register and then what we can do is we could pass in the other data now the first off we are going to say the method is going to be post so method is going to be post and then we could say headers and inside of the headers we can pass in the content type this will be equal to application slash json as simple as that then we could go down and set the body to json dot stringify and this is basic javascript right this is not something that i need to explain you right now so it's going to json stringify and we could pass in the two things that we need to pass in which is first off is the username so username is going to be form dot get and we could get the username this way username and then password is going to be the same thing so we could say form dot get password all right as simple as that now what we can do is you could get back the response let's await fetch so we get back the response then what we can do is we could say const data is going to be await res dot json so convert the response to json data and then what we can do is finally we can if you go back to the register route here we return a user right here we return a user as the new user so what we can essentially check is if data dot user is not equal to null or we could simply go ahead and say if not data dot user so if the user does not exist right from our response we could return null in this case essentially what you can do is you can show a message that the password is invalid or the user already exists in this case the user will already exist but right now we'll skip that part you can do that yourself now once all that is done once we check if the user exists or not so the user exists the user is registered now we want to log the user in so what we can do is we could just import something from next auth slash react and we can import the sign in function and after all this operation is done we could just call the sign in function let's do that sign in and inside of sign in we can first of all specify we want the credentials to be used and then we can add a comma and we could say well hey first of the username is going to be data dot user dot username the password will be data dot user dot password and basically we don't want to authenticate with the password like that so let's just go ahead and say password is going to be form dot get and we get the password and what we can do then is we can add a callback url which is after this stuff is done we can call we can redirect the user to the slash route and essentially that's it if you want some more operations to do after sign in what you can do is you can just await this and then do the other operations let's test this out if it works or not so right over here i'm on the app instead of the login page let's go to register and i'm going to just go ahead and say well hey the username is going to be my name usman and the password is going to be usman1234 let's also open up the dev tools that we can see if it actually works or not so i'm going to go to the network tab and let's click on submit wait a minute i forgot one thing to do before we submit so basically when we submit a form it the page refreshes by default so we have to prevent that behavior so i could just go ahead and call e.prevent default at first okay coming back let's click on submit now and you see it goes ahead redirects us to the home page now if i go back inside of here let's launch a new terminal and let's say npx prisma studio to open up our prisma studio so in here if we can just see we have the user table inside the user table we have the username we have the password which is completely hashed and i guess that's all so now we are redirected to the home page but how do we check if the user exists or not so let's go to the home page which is the index.tsx and i am just going to remove everything from in here so let's do that real quick and let's get rid of these ones as well and what we can do is we could just right now let's return a div and an h2 welcome welcome and then what we can do is let's also have a p tag so user id right now what we are going to do is let's just go ahead and say const something is equal to use session so use session comes from next auth react and we get back a couple of data so we get back the data and then we get back the status so what we can basically check is if the status is authenticated then and we can also say well hey if is if you go back you see it's session or null so if data is not equal to null again then we can display this data right over here which we need to wrap in a parent element like so so we could say welcome and then we could say data dot user dot username and then right over here we could say data dot user dot id for now and let's hit save let's go back to the app it says use session must be wrapped in a session provider so we forgot one thing if i go to the underscore app.tsx this is what we have to wrap inside the session provider so that we can access the session so let's cut this out and i'm going to add a session provider and let's just wrap it this like this hit save go back you see welcome and then we get back nothing and the user id is this now if i were to just go ahead and see why the username does not work let's just go ahead and do a little trick so i'm just going to say json.stringify the data.user you see we get back the name null image is null and the id is this so if we want to access the username we can do the same thing that we did with the id so come back right over here in the type definitions and i'm just going to add username string and then what we can do is go back to our next auth file and right over here we can just go ahead and add these things so in the callbacks when the session is requested we could say session user username is going to be equal to token dot well we have a we have some stuff so token dot username and then token dot username right over here is going to be equal to user dot username let's hope it works i know it says you know it gives us an error and that is because we have to simply log out and log in again so right now what i'm going to do is go to the dev tools inside of the let's see in the application tab in the cookies i'm just going to clear all these cookies so that now we are not logged in and what we can do is go back to the login page now let's implement the login page because this is going to work once we log in in the login page everything is going to be the exact same thing as we did in the register page so let's copy the handle submit and let's paste it and let's just go to the form let's say on submit is going to be handle submit the only different thing is going to be we don't need this fetch request so let's get rid of that and all we need is just this sign in so we can await it if we want but we can also skip it so this is going to be form dot get and we get back the username all right so a form event is also not imported let's do that come back to the login page let's see if it actually works so my username was man and my password was usman1234 i believe and when i click on submit you see we are redirected to the home page and now we get the username the only thing left to fix is that it says property username does not exist on user or adapter user this is an sort of an internal error so right now to fix this for a temporary solution i'm just going to go ahead and wrap this inside of these parentheses and i'm going to say as a user and this user comes from prisma client so let's import that so now this is the user type in prisma client and as user then we can access the username we know that it works fine and if i go to this terminal where i come to log the user you see we get back the id we get back the username we get back the password essentially whatever we return from this authorize function we get everything right over here all right that's it for this video i hope you liked it i hope you enjoyed it i hope it was insightful and please let me know in the comments below if you want more videos like these on next year's on prisma on next auth something stuff like that i'm pretty excited to bring you a lot more content like this hope you like this one peace out
Info
Channel: Max Programming
Views: 2,716
Rating: undefined out of 5
Keywords: javascript, typescript, react, js, web development, node js, nodejs, javascript tutorial, javascript tutorial for beginners, javascript for beginners, web development full course, web development course, web development roadmap, next auth credentials, next auth credentials provider, next auth credentials custom page, next auth credentials jwt, nextauth credentials, nextauth tutorial, next js 13, next js 13.4, prisma next auth, zod nextjs, next auth prisma credentials, prisma
Id: fqXC2V-MSV4
Channel Id: undefined
Length: 31min 51sec (1911 seconds)
Published: Sun May 07 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.