Full Stack Authentication with Next-Auth and Next.js 13: All You Need to Know

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's going on developers this video is a tutorial on full stack authentication with next off and Nexus version 13. in this tutorial in order to keep track of our user we're going to create a backend database and then set up the Prisma client in order to access to that backend database in the first section we're going to integrate the next off package with the Nexus version 13 and we are going to do this inside the API directory of the app directory so that's a new one in the second section we're going to protect some of our Pages inside our application with the next auth middleware and the third section is a bonus one we're going to protect our API routes with JWT access token so just grab a cup of coffee and join me because in this video you're going to learn a lot about the authentication in nextges version 13. so without further Ado let's get into it okay I opened up a brand new Nexus version 13.2 project and the first thing I want to do is to install the next auth package so I go to the terminal and say npm I next dash off okay I closed this off and then we have to create the API raft Handler for the next off so this is a Nexus version 13.2 which means that we can have our API routes inside the app directory so I go to the app directory and then inside the API directory I'm going to create a directory called off and then inside it we're going to create a dynamic right for the next off so inside the square brackets I'm going to say dot dot dot next dash off and then inside this next half directory I'm going to create a wrap.ts file so this is a dynamic route Handler for the next half in other words this is a catch all route for the next off which means that every API route which starts with the slash API slash off just like this will be handled by this rap.ts file okay so in this file first of all we're going to Define our API Handler so I'm going to say const Handler equals to next off and then inside the next half we're going to pass an option object we're going to fold this option object in a second but before that I'm going to export this Handler as the get request and also Handler as the post request so with this one line of code we can have the next half API Handler inside the app directory so every get and post request to this API route will be handled by the next auth and now let's go and fill up the next off option object so here the first thing we want to specify is the list of the providers so what is a provider a provider is a specific way of authentication the most basic one is the credentials provider which means that users must have a username and password in order to be able to sign in into our application and also there are other providers and if I go to the documentation of the next app and inside the providers section you can see the list of the providers for example if we want to allow our users to sign in into our application with their Google account we should add the Google provider inside our providers list and also we have the Facebook provider GitHub provider and so on but the credentials provider is the most basic one and we're going to go ahead with the credentials provider in this tutorial so I select the credentials here and here I just copy the credentials provider and let's go to the vs code and paste the credentials provider here so let's go back to the documentation and copy the Imports of the credentials provider and let's paste it here and you can see the arrow is gone so the first thing inside the credentials provider which we have to specify is the name which is the credentials and then we have a credentials object which consists of a username and password which means that our user have to have a username and password in order to be able to sign into our application and since the next auth can create a default sign-in page we can have the label for the username inside the sign in page the type of the input and also a placeholder for the username and we can have them with the password as well and then we have the authorize function which is the most important section of the credentials provider and here we have to add the logic to look up the user from the credentials that is supplied to the authorized method so when the user inside the sign-in page provide a username and password and then click on the sign in the authorize method inside the credentials provider will be called and here we have to check in our users database to see that if such a user with the supplied username and password is existed if the password is correct we just return the user object into the session of the next off and if the credentials is not correct we just return null into the session of the next half which means that the user is not authenticated so here as you can see we have a dummy authentication method but in real world applications we should send a post request to a backend API for example a login API and then this backend API checks if the supplied credentials is correct just return the user object with the basic info of the user for example ID of the user name of the the user of the email of the user and then if the credentials is not correct you just return null as a response of the request and since this project is a full stack project where here we can use the Prisma in order to set up a sqlite database and then inside that database we can keep the list of our users and then we're going to create a login API which takes the username and password and checks inside the sqlite database if supplied to credential is correct and such a user is existed then it Returns the basic information of the user as a user object so we can call the login API here inside our authorize method so now let's go and set up our database with the prismap so first of all we need to install the prism mod so I open up the terminal and here I paste the script for installing the Prisma npm install Prisma save Dev okay and then we're gonna create our Prisma schema with this script npx Prisma in it and then dash dash data source provider sqlite okay and here as you can see it creates a Prisma directory for us and inside it you can see there is a schema that Prisma file so here we can create our Prisma schema and I go to the quick start section of the Prisma documentation and here there is a small and simple schema file let's copy that and then let's paste the schema here as you can see it has a provider of sqlite and then it has a user model which has a ID email name and each user has a list of posts and then we have the model post which has an ID also title content published and then the author which is the user and also author ID which is a reference to this user IDs so it's a firing key in our relational database so now we can run the Prisma migration in order to create the SQL database with these two model or table for us so I go back to the quick start section of the Prisma and here after the simple model schema we had the npx Prisma migrate div and let's copy this and here let's paste the script here let's run that and as you can see it creates the div.db which is a sqlite with these two user table and post table inside it and then as the last thing we should install the Prisma client so I'm going to say npm I and then add Prisma slash client okay and as a last thing I go to the olive directory and create a new file called prisma.ts and inside it I'm going to paste a couple of code that I've got from the Prisma documentation so what does these four lines of code do every time we need to use the Prisma client we have to instantiate a new instance of the Prisma client class so in order to have just one instance of the Prisma Clan class throughout of our application we just import the Prisma from this prisma.ts file so every time we need to use the Prisma client we don't need to instantiate a new instance of the Prisma client class you can find this file inside the GitHub before of this tutorial and it's inside the lead directory and then prisma.ts file so let's save this and save the Prisma schema and also the next of API route and now we can go ahead and run the Prisma studio and here I say npx Prisma Studio and here as you can see we have the post and also the user model and now we can add a record inside our database so the Prisma studio is a convenient tool when you want to see what's inside your table inside your database so now we're done with the prism and let's go create our login API so let's close our terminal and also the Prisma directory and here inside the API directory of the app directory I'm going to create another route called login and then inside the login directory I'm going to create the route.ts file and inside it we're going to create a post request so I'm going to say export async function post and then it has a request which its type is request so this post request is our login API inside the body of this login API we're going to expect the username and password so let's create a interface for the body of this login API so I'm going to say interface request body then inside it we're going to have a username which is going to be string and also a password which is going to be string as well and then here inside the party of this post request we're going to access to the body of the post request we're going to say current body which is going to be type of request body and then equals to wait request dot Json okay and then with the help of the Prisma client we can find the user with this username and password so here we're going to say const user equals to weight prismard and let's import The Prisoner from the lead directory and then prisma.ts file as you can see we export Prisma client here and then inside our login API we import the Prisma from the prismat.ts file inside the lab directorate so we don't need to instantiate a new prisoner client from the Prisma client class so here we can access to the user model and then we call the find first function and inside it we're gonna pass the where object let's say in this application we're going to use the email of the user as its username so we're going to find the first user that its email is in match with the username that is supplied to the login API so I'm going to say email and then set it to buddy that username okay and then we can check that if the user is not null and then the password of the user is equal to the supplied password to the body of this post request then we can say that the username and password is correct and then we can return the user object as a response of this login API so here we can say if user is existed and also here we can check the password of the user with the supplied password inside the body of the request so we can say just user that password is equals to the body the password so this is a very naive way of checking the user password since the password inside our database are going to be hashed because we shouldn't keep the user password as a playable strings so when we are going to create a user inside our database first we hash the user password and then save the hashed version of the password inside our database so we can hash the password and then convert the quality of the hashed password with the bcrypt library so first of all let me install the brickwork library here inside the turbo I'm going to say npm I bcrypt okay and then since we are using the typescript we should install the types of the decrypt so I'm going to say npmo dash dash safe div and then add types slash books okay and now we can import the bcrypt here so I'm going to say import Star as Big Crypt from Big Crypt and here instead of using this dummy equality statement we can use the decrypt dot compare function so here I've opened up a parenthesis and inside it we're going to say wait we Crypt they are compared and then put the supplied password inside the body of the request and then pass the user dot password so this compare function first of all hdbody.password and then compare it with the user.password which is already hashed and if these two are equal it returns true or else it returns false so now we can check that if the user is not null and then if the supply password is correct we can return the user object as a response of this login API so here first of all we extract the password from the user object so when we say const the object set it to user and then put out the password and then put the rest of the user information into a object called user without pass and then return a new response and stringify the user without password object and else if the user is null or the supplied password is not correct we just return now so I'm going to say alt return no response Json dot stringify of just no okay so that's it for our login API and now we can use the login API inside the authorized function of our next off API route so I go to the next of API routes here in the authorize function I'm going to create a post request to the login API so I'm going to say currents press equals to wait Fetch and then pass the API slash login then set the method of this request to post and then set its headers content type set it to application.json and then inside the party of this post request we're going to send the username and password from this credentials object so I'm going to say Json dot stringify then put an object here which has a username which comes from the credentials yeah username and also it has a password which comes from the credentials password and then we say current user equals to await res dot Json and here we can check if the user is not now we just return the user that we've got from the login API and if the user is null which means that the credentials was not correct we just return null into the session of the next aft which means that the user is not authenticated so now we can test the login API but before doing that let's create another backend API for creating a user so inside the API directory of the app directory I'm going to create another route which is the user and then inside the user we're going to create the route that TS file and inside it we're going to export a post function which takes the request as its parameter so this post request is for creating a user and inside the body of this post request we expect the name email and the password of the user so let's define a interface for the body of this post request so I'm going to say interface request body and then inside it we're going to expect a name which is going to be a string and also an email which is going to be a string as well and also a password which this also need to be straight so now we can have the body of the post request so I'm going to say colors body set its type to request body and then set it to a weight request.json so in this way we can access to the body of this request and then we create a user object inside our database using Prisma client so I'm going to say const user equals to a weight Prisma and then import The Prisoner from the lib directory and then call the user dot create function and inside it we're going to pass an object which has a data object and then we're going to say the name of the new user is the body that name its email is Buddy that email and also its password would be the hashed version of the buddy.password so first of all we need to Hash the buddy.password so let's import the Big Crypt here again so we'll say import Star as Big Crypt from Big crypts and here we set the password to await decrypt dot hash then pass the Buddy dot password and then pass the number of the salt round we're gonna pass 10 because inside the documentation of the buildcrypt it is recommended to pass the 10 as the number of the salt to this hash function so in this way we first hash the password of the new user and then save the hashed version of the password inside our database not just the plain text of the password and now we can return the created user into the client so first of all it is better to extract the password from the user object so I'm going to say const an object set it to New created user object and then extract the password and then put the rest into a variable name result so the result is the user object without the password and then we just return new response from this post API and then pass the Json at stringify and then pass the result object into it so in this way we first create a new user inside our database and then we'll turn the new user object without its password as a response of this post request to the client so now let's test it so first of all let me run our server npm brand Dev okay it's working on the port 3000 and then Opera of the insomnia in order to test our API so here as you can see we have a post request to the localhost 3000 and then slash API slash user so inside the body of the request we pass the name of the user email of the user and also the password of the user so if I click on the send it will return us a Eternal server error so if I go back to our vs code and here check the errors so it says that the user model doesn't have a password inside it so let's go to the Prisma schema here and yeah the user model doesn't have a password so let's add a password which is going to be a string and let's save this and let's run the Prisma migration in order to submit these changes to our database and let's run npx Prisma Studio to see if the user has now a password yeah the user model has now the password filled inside it and let's go back to our vs code let's roll our server again in PM run this let's go back to our insomnia and send the create user post request and as you can see we have the user object with the idea one its email and also its name so let's check it inside the Prisma studio so let's run it again inside another terminal npm Prisma Studio okay and you can see we have a user with the idl1 it's email its name and also its password so if I go back to insomnia you can see we provided the one two three for your password and here we can see it doesn't save the one two three for the password of the user we first hashed it and then we save the hashed version of the password inside our database not just the plain text of the password so now let's there's the login API with the username is the email of the created user which is Sakura gmail.com and the password is one two three and if I click on the send and it said method it's not loud so let's go back to our vs code and here it says that new HTTP method exported from the login API so this is our login API oh yeah we should have the post in the upper case and if I go back to the insomnia and click on the sun and yeah you can see that the login API returns us a user object with the ID of the user or email and the name so now let's Supply a incorrect password and click on the send and you can see that the login API returns null to us which means that the credentials we provided was not correct okay and now we can go ahead and finish our authorized function of the next of API route so we have already finished it and as you can see if the login API returns a user object it returns that object into the next off session and if the user object is null it is returned null to the next auth session so what is the next off session inside the indexed of session we can keep the authenticated user object so throughout our application we can check if the user object inside the next off assistant is not now it means that the user is authenticated and have signed in into our application but if the user is null it means that the user is not logged in into our application so in order to access to the next app throughout our application we should wrap our application with a session provider in the root layout of our application just like what we do with the context API or Redux State manager so here instead of wrapping the whole application with the session provider will create a component called providers so I'm going to say providers.tsx and here I'm going to create a functional component and this functional component takes the children as its props so let's define an interface for the props of this components which has children inside it which is going to be a react node and then you can have access to the children of the props of this provider and then let's just wrap the children with a session provider so I'm going to say session provider which comes from the next off slash react and then wrap the children inside the session provide so that's it for the providers component but before moving forward let's mark this component with the use clients okay and then we go to the root layouts of our application and then wrap our application with the providers component that we've just created so now throughout all components and Pages inside this application we can access to the session provider and now let's run our application I believe it is running already and yeah let's go to our browser and go to the localhost 3000 and as you can see we have a upper here so let's add a signing button inside the app bar here so I go to the vs code and inside the components directory I'm going to create a signing button component so I'm going to say something in button that TSX and let's create a functional components and here first of all it's access to the session of the next aft so in order to do that we use the use session hook which comes from the next off slash react so I'm going to say const an object and set it to use a session which comes from the next off slash react and then access to the data which is the next off session and then let's rename it to the session so here we check that if the session is existed and also session has the user inside it it means that the user is now logging into our system so the signing button must be turned into the sign out button so now let's return the j6 for the signing button we have a div element and then we render a P tag and then inside it we render decision.user.name and then we put a sign up button which in its own click event which is called the sign out function which comes from the next off slash react that's it the next off will handle the sign out process for us so if the user is not authenticated we have to return a sign in button so let me paste a button which is the sign in button and inside it's unclick event which is called the sign in function from the next off slash react so this will redirect us into the sign in page which will be created by the next off package but we can have our custom sign-in page if we want and I put the link to the video for creating a custom signing page in the description below so now let's put the silent button inside our app bar so here we just add the sign in button inside our app bar and let's import it and if I go to the browser it says that react contacts is unavailable inside This Server components so use session Hook is using the context API under the hood so let's go to the sign button and let's mark it with the use clients and let's save this and the arrow is gone yeah and as you can see the user is not signing and if I click on the sign in button it should redirect us into the sign in page and it gives us an error so let me check the log of the server so here it says that missing next of API route error so we have the API then off next off oh yeah uh this arrow is because we named the API route of the next off to the dot dot dot next dash off it should be dot dot dot next off without any Dash so if I fix this and remove this Dash and turn it to just next off and let me restart the server so I'm going to say again npm run Dev and let's refresh this and now if I click on this sign in and you can see it redirect us into the sign-in page as I said before this login page or sign-in page was created by the next app automatically so we can have our custom login page if we want to and I have another video to create a custom login page and if you want to know how we can create our custom login page you can watch that video which the link is now on the screen and also I put the link to that video in the description below so here I just put my username and password let's copy the username from the insomnia paste it in the username and for the password I'm going to say one two three it gives us an error and if I go back to the vs code first of all it's warn us with the no secret I will fix it later in a second and it's with the fetch API here so let's add the http localhost three thousands and let's save this to see if it is working so now let's refresh with my username also my password one two three if I click and you can see yeah it is now working and you can see the signing button is turned to this sign out because the user is now existed in the session of the next half if I go to the signing button you can see that here this condition is true this session is existed and also session has the user inside it so it render a P tag with the username of the user and also its sign out button so if I click on the sign out you can see it now the user is not logged in and the name of the user disappear and the sign button is shown to the screen so if I click on the sign in again login with my credentials and you can see again the name of the user is now on the screen so now let me go back to the vs code and fix the next of no secret warning but before doing that you should know that the session of the next half can be kept in two ways you can keep it in a database or just we can turn it to a JWT and then keep it inside a HTTP only cookie so the default strategy for keeping the next of a session is to turn into a jetability and then keep it inside a HTTP only cookie so to specify the strategy for keeping this session we can have the session object after the providers list and inside this session we can have the strategy which can be set to the database or JWT as I said if you want to keep the session inside the database you should set up a database for the next off but if you choose to generate BT the session will be turned into a JWT and then will be kept inside a HTTP only cookie so the default part as I said is JWT so here we go ahead with the default strategy JWT and also you can specify the age of this session for example max age which the default max age is 30 days so when a user login into our system this session will be valid for 30 days it means that within the 30 days the user doesn't need to sign it into our application every time he or she visit our application so that's it for the session object since the default strategy is the JWT we don't need to specify that but if we go ahead with the JWT strategy we should have a next of a secret environment variable inside our DOT EnV file so I add a next off underscore secret variable inside our EnV file and we should set it to something complex so let me add some random string here and also in order to next off work correctly in the production environment we should have the next of underscore URL so I added inside the envo file and since our Nexus application are running on the localhost port 3000 I just add the http localhost Port 3000 for the next half Euro so now let's save this and also save the next half API route and let's restart our server okay and let's sign in again let's go back to our vs code and you can see that the next auth secret warning is now gone so yeah I think that's it for this section uh let me quickly recap what we have done inside this application so far first of all we have created the API route for the next half inside the app directory we have created a directory called dot dot next off inside the square brackets in the slash API slash off and then inside the route Handler first of all we have created a Handler which is set to next off and then here we export that Handler as get and also as post from this file so in this way we can have the next of API routes inside the app directory and then inside the option object of the next auth first we have specified the providers and inside the providers we use the credentials providers and credentials provider means that we're going to indicate our user with the username and password and then we have the authorized function in which we first send a post request to the slash API slash login and send the username password inside the body of this post request and this login API checks if the users existed with this username and password and if it is the case it Returns the user object so we check if the user object is not now it means that the supplied username password was correct and then we just return that user object into the session of the next off or else we just return load which means that the user is not authenticated and then we have created a providers component which wrap its children inside the session provider component that comes from the next off flash react and then inside the root layout of our application we wrap the whole pages and components inside this provider's component so in this way we can access to the use session hook which Returns the session of the next off and then we have created a signing button and inside we first of all use the use session hook to extract the session of the next off and then we check if this session is not now and then there is a user inside it we just return the name of the user with the sign out button and if the user is not inside this session or the session itself is null it means that the user is not logged in into our application so we just ran their sign in button and inside it's on click we just call the sign-in function which comes from the next auth slash react it will automatically redirect us into the sign in page okay that's it for the setting up the next off with the next JS version 13.2 and then we have created the login API in which we extract the username and password from the body of this login API and then with the help of the prisoner we try to find any user with the supplied username and then we just check if the user is not now and then we compare the supplied password with the user.password with the help of the bookcrypt library and if these two condition is true it means that the username and password was correct so we just return the user object as a response of this login API and if the username and password is not correct we just return now so this login API was called inside the authorized function of the credentials provider as you can see here so yeah I think that's it for this section and in the next section we're going to use the next off middleware in order to protect some of the pages inside our application so only authenticated user can access them okay first of all we're going to create another page for our application so here I'm going to create a user post directory and inside it we're going to create the page.tsx so let's create a functional component here and let's rename it to the user post page and then here we just say that only authenticated user should access to this page so in the app or we can see that we have a link to the user post page so let's go to our browser and here if I click on the user post page you can see that the only authenticated user should access to this page so if I sign out then home page then click on the user page you can see that the user is not logged in but we can access to this user post page so let's fix this with the help of the next of malware okay I go back to the vs code and here inside the SRC directory and side by side of the app directory I'm going to create a middleware file so I'm going to create a file called middleware.ts and inside it we're going to export defaults from the next off slash malware and then I will export a config object so I'm going to say export const config equals to an object and inside that object we're going to have a matcher and it's going to be an array and inside it we add the URL of the pages which we want to protect from the unauthenticated user so in this case it's the user post page and if we want to protect all the URLs that start with the user post we can add a slash and then column path and then a star so in this case all the URLs that start with the user post will be protected from the authenticated user so let's save this and I'll go back to our browser let's refresh and here you can see that the user is not signing so if I click on the user post page you can see automatically we will be redirected into the login page so now if I log in with my username and password and you can see now the user is authenticated and we can access to the protected page so if I click on the home page and then click on the user post page you can see that we can access to the protective page but if I sign out and then go to the user post page which is a protected page you can see that the unauthenticated user will be redirected into the login page so in this way we can protect some of the pages inside our application we just need to create a middleware file inside the SRC directory and then export the default from the next off slash middleware and then explore a config object with the matchup property which specifies the pages that we want to protect from the unauthenticated users that's it and now let me show you another problem that we have to fixed in order to secure our application so inside the app directory and then API directory I'm going to create another API for users so let's create a dynamic route inside the user directory it will be the ID and then create the route the RTS inside it so it will be the slash API slash user and then ID of the user so this API is a get request so I want to export a async function get and then have the request which is type of the request and then also we want to access to this ID prams here so we can have the prams here and these params will be type of a object that has prompts inside it and the problems has the ID which is going to be a number so in this way this get request can access to this ID params here so inside this request we want to return the post or comment of the user with this ID so we can do this with the help of the Prisma so I'm going to say curls user post equals to weight and then for the Prisma from the prisma.ts file that posts that find many and then inside it we specify the where object so we want to return the posts that their author ID equal to the prints that ID okay and here just include the author and then select some of the fields from the author we want their email and also the name of the author so these are kind of the Prisma stuff and since this is not a prismarck course you just need to know that this statement will return the post of the user with this ID and if you want me to create a crash course for the Prisma please let me know in the comment section so after that we just return a new response and then stringify the user post okay so let me go to the Prisma Studio Prisma Studio and then here for this user let me create a couple of posts here so let's add a record its title would be the test and its contents also would be test just add the author ID of one then create the second post test two and then also add the author idea one for the second post let's save this and if I go to the user you can see now the user has two posts here test and test two so now let me call this get request from the insomnia so here inside the user if you just send a post request to the locals 3000 API user and then ID of the user is one so if I click on this it will return internal server so let's go back to our vs code uh yeah author ID is in string so let's add a plus before the parameter ID and then send the request again and you can see that it returns us a list of two objects the test post and the test two post with the user of idl1 it's okay but what if we want to protect this API from unauthenticated user how we can protect our API routes inside the next.js so in order to do that we should require the client to have an access token inside the header of its request to this API but first in our login API we have to create an access token and return the access token to the user when user logged in into our application and then if the user want to access to this protected API route it should add the access token inside the header of its request so let me show you what I mean in action so in order to do that we have to take Three Steps step one our login API should create and return an access token when every user logged into our application Step 2 we should save the access token inside the session of the next off so later we can use the access token in order to access to the protected API routes and in the third step we should protect our API routes and require the user to have the access token inside the header of its request so let's do that in action okay as the first step in the login API we should create an access token and return it to the client along with the user object so in order to create an access token we're going to use a library called Json web token so I'm going to install it in the terminal so here I'm let's say npm I Json web token and then since we are using the typescript I'm going to install the types of the Json web token so I'm going to say npm I Dash Dash safetiv uh types slash Json web token okay and now we need two functions the first one is for creating or signing a JWT token and the second is for verifying a JW team so I'm going to go to delete directory here and create a file called jwt.ts and in this file I'm going to Define these two functions but before creating these two functions let me Define an interface for the sign options so we say interface sign option and then this sign option could have a expires in which is going to be optional and its type is going to be string or number we will see the usage of this interface in a second and then we're going to Define our function so the first one is for signing a JWT access token so I'm going to say export function sine JWT access token and this function takes two arguments the first one is the payload which its type is going to be the type of JWT panel which comes from the Json web token and we're going to have an options which its type is going to be sign option which we have just defined so this sign option having expires in option that determines the expiration time of the Json web token and we can Define it default sign option and then pass it as a default value to this options parameter so we don't need to pass the option object every time we call this signature access token so I'm going to say const default sign option which is going to be type of sign option and set it to a object and set its expires in to one hour and then we set this default sign option to the default value of this option parameter and then inside this function we need a secret key in order to create a JWT so we're going to Define a variable inside the EnV file called secret key and set it to a string for example something complex and you should know that this secret key is used to sign and verify the JW it is so it is very important for you to keep it secret and not share it with someone who should not access to it because if an attacker have access to this secret key he or she can create a valid JWT access token and then use it to access part of your system that is protected and that's why we keep this secret key inside the environment variable not just in our code so let's save this and go back to our JWT file and here first of all we have to retrieve the secret key from the EnV file so I'm going to say const secret key equals to process that EnV dot secret key okay and now we can create a JWT so I'm going to say const token equals to JWT which comes from the Json web token so let's import it manually here we can import the JWT from the Json web token and then call the sine function and then we pass the payload in order to create a JWT from this payload and then we have to pass our secret key and since we are reading the secret key from the environmental variable it has the type of string or undefined but here in the sine function we should pass it as a type of string so in order to fix this we put an exclamation mark here and then we pass our options so in this way we can create a JWT access token from the payload and secret key and also we have capacity option which describes the expiry time of the access token and then we can return the token from this function okay and then the second function that we need to create here is the verify JWT so I'm going to export another function called verified JWT and it takes a jability token as its parameter which is going to be string and then inside it I'm going to create a try cache block and then inside the try block first of all I'm going to read the secret key from our environment variable and now we can decode the JWT token so we're going to say const recorded equals to JWT that verify the token and then pass the secret key so here we just return the decoded as jwtpayout so in this way we can verify a JWT token so if the token is invalid with this secret key the JWT throws an error here and here in the catch block we can catch the error and first of all we log the error into the console and then we just return now which means that the JWT token was not valid and that's it for this two function we use sine JWT access token to create in JWT access token and then we use the verify JWT in order to verify the token that is supplied by the client so if the token is valid we just return the decoded object of the JWT and if JWT token was not valid we just return now from this function okay and now we can go to the login API and here if the login process is successful we can create an access token and then return the access token along with the user object so here we can say punched access token equals to sine JWT access token which comes from the lib directory and JWT file which we have just defined and then pass the user without pass object so the access token is Created from this user without pass object and then you can create an object called results const results equals to an object and then spread the user without pass and also access token so this result object have the user object with that path and the access token so here in the response we just return the result object which has the access token inside it so let's save this and go to the insomnia and inside the login API let's send a post request to this login API so the server it is not running so let's go back to our vs code and run our server okay and now let's send the request it just return node and that's because our password was wrong let's fix this and send the login request and here we go as you can see we have the response object that has the user data and also has the access token inside it so now we have to store this access token inside the next of a session and later when we want to call this user profile API we should have this access token inside our header of our request so now we are reaching to the Step 2 which is storing the access token inside the next off and then if I go back to the vs code and here inside the sign in button components which we have access to this session here if we inspect the session object you can see that it has an user object inside it but this user object only has an email image a name not the access token and also doesn't have the ID of the user so let's fix this first of all we're going to create types ball so here inside the lead directory I'm going to create a director called types and then inside it we're going to create a next dash of the TS and inside it first of all we're going to import the next off from the next off and then we declare a module called next off so we'll say declare module next dash off and then inside it we're going to Define an interface called session and this session will have the user object and this user object it'll have an ID which is going to be a number name just going to be string and also the email which is also going to be a string and it has an access token which is going to be string so let's save this and go back to our sign in button and if I open the other completion for the user object inside this session you can see that now it has an access token email ID and name so here let's log the session that user and now let's go to our browser open up the console and here if I click on the sign in put my username and my password and you can see that the user object inside the session only as the name an email but doesn't have the ID and also the access token so in order to fix this we go to our next of API routes and here after the providers list we're going to have a callbacks object and inside this call wax object we're going to Define two functions a JWT function and also a session function so we'll say async JWT and this JWT takes an object and inside this object we're going to have the token and also the user and then inside it we're going to combine this token object and user object into one object and return it as the JWT so I'm going to say return an object and then spread the token and also the user so in this way we combine the token and user object into one object and then return it as the JWT and then we're going to define the session object we'll say async session which is going to have an object as its parameter and then inside this object we're going to take the session and also the token and then inside this function we're going to say session dot user equals to token and since type of the token is JWT and type of the user is a object that has ID name email and access token we just say token as any to fix this error and then we just return this session okay and now let's go back to our browser let's sign out and clean the console and again sign in put my username password and here we go the user object now has the ID name email and also most importantly the access token so in this way we can save the access token inside the next half session and now we can go ahead and reach the step 3 which is protecting the API routes and require the client to have a valid access token inside the header of its request okay I go back to the vs code and here inside the API directory we want to protect this route which retrieve the post of the user so first of all before retrieving the post from the Prisma we check if the access token is inside the header of the request so in order to do that I'm going to say const access token equals to request that headers that gets access token so here we have to say that if the access token is undefined which means that the access token is not present in the header of the request or if the access token is not valid we just return an unauthorized arrow with the status code of 401 into the client so here we can say if not access token or not verify JWT of that access token then we just return a error into the client so the first statement checks that if the access token is now if it is not present in the header of the request and the second statement checks if the verify JWT returns null which means that the access token is not valid so if one of these statement is true we just return a error response into the client and remember this verify JWT functions comes from the JWT file that we we have just defined okay so here we just return new response to the clients and inside it we're gonna say Json that's stringify an object which has a error inside it with the unauthorized message and then we set the status code of this response to the 401 which is a standard for sending in our authorized response to the client so in this way we protect our routes with a JWT access token so let's go back to our insomnia and here in the user profile let's rename it to the user post okay in the user post we are going to call the slash API slash user and then idea1 which we have just protected with the JWT so if I click on the send it returns us an unauthorized error with the 401 status code so that's because in the header of our request we didn't provide any access token so I go back to the plugin API send the login again and then copy this access token here and go back to our user post API and inside the header I'm going to create an authorization and then paste the access token that we've got from the login API so now let's send the request with the access token it again gives us an unauthorized earn so let's go back to our vs code and inside this API yeah we're expecting the access token inside the header of the request so let's rename it to authorization because it's in standard name for expecting the access token inside the header of the request so it's authorization let's save this and go back to insomnia and now let's send the request again and you can see that this time it Returns the post of the user without any error and that's because we provide the authorization header with a valid access token okay now let me tamper with the authorization so let's remove some of its character no it's it's not a valid access token JWT if I click on this send this time again we can unauthorized message and that's because our access token is not valid so let's grab it one time again from the login API let's paste it into the authorization header click understand and this time you can see that the API returns us the expected message and yeah in this way we can protect our API rats inside the next.js so let me quickly recap what just we have done in this section first of all we install the Json web token library and then we created a jwts file and inside this file we export two function one for the signing or creating a JWT access token and the other for verifying a JWT access token and then inside our login API we create an access token with the user object and then return it along with the user data into the client and then we have created a types directory and inside this type structure we created a next Dash auth.ts and inside it we we Define the shape of the user object inside this session so we added the access token inside the shape of the user object and then we created a callbacks object inside the next of API routes and inside this callbacks object we create a JWT and then we take the token user from the parameter of the jbt and combine them into one object and return them as the JWT and then we created a session function and then take the session and also the token from the parameter and then set the session.user to the token and then just return this session so in this way we can save and persist the JWT access token inside the session of the next half and then we have protected our API with the access token so here we expect the authorization header of the request and then we check if the access token is not there inside the header of the request or the access token is not valid and if one of these two condition is true we just return a error response with the unauthorized message but if the access token is in the header of the request and it's a valid access token we just retrieve the post of the user and then return the response with the post of the user so in this way we can protect our API routes with a JWT access token inside the next.js so yeah I think that's it for this video and if you enjoyed this video please hit the like button and if you want to see more content like this please subscribe to my channel I really appreciate that because it will encourage me to move forward have a nice time bye-bye
Info
Channel: Sakura Dev
Views: 81,809
Rating: undefined out of 5
Keywords: next js, next js 13, next auth, next auth app dir, next-auth jwt, next-auth middleware, next-auth tutorial, next-auth credentials, next-auth custom login page, next.js 13, next js typescript, next js tutorial, authentication in nextjs, authentication in next.js 13
Id: 0eu4_lLFkGk
Channel Id: undefined
Length: 66min 32sec (3992 seconds)
Published: Thu May 04 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.