Full Stack Authentication With Next.JS 13 | Next Auth | Nest.JS

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Master the authentication in a full stack project with nextjs next off in the front end and nextjs in the back end in the back in section we are going to use nestjs and you will learn how to create a login API create your access token and refresh token how to protect your apis with JWT access tokens and how to create a refresh token API we're not going to use any third party packages like passport.js we're going to implement these functionalities from scratch so you can learn them in a very basic level and therefore understand how authentication Works in back and side in the front end we use nextjs version 13 and next off and you will learn how to integrate the next o with your next project how to retrieve the next o session in the client components as well as the sever components how to save the backend access tokens in the next off session and how to protect your pages with next off middle work and how to use next off callbacks and most importantly you will learn how to implement a robust solution for refreshing the backend access tokens automatically with next off in your client and also your server components so sit tight here because you will learn a lot about the authentication in this tutorial and let's get right into it okay so now let's create our nestjs project in order to do that we need to install the nest CLI and we can install it with npmi DG at nj/ CLI and since I have it on my machine I'm not going to install it again okay so now we can create our project with the nest new and then name of our project which is going to be off- Nest I'm going to go ahead with the npm here and we're going to wait for installation okay so now let's open up the project okay the first step that we should do here is to configure Prisma actually I wanted to use jurol RM but it requires more SQL knowledge and is more complex than Prisma so I decided to use Prisma for this project because it's simpler and it allows us to focus on authentication part of this project but if you are a dral orm fan don't don't worry after this video I will upload a very short video and refactor this project to use drizal orm so now let's install the Prisma okay I open up the terminal and I'm going to say npm install Prisma D- save Dev okay and now we can use npx Prisma in it to initialize our Prisma setup so as you can see here we have a Prisma directory and inside it we have the Prisma schema and also it will create for us a EnV file and and inside it it creates a database URL for us and since we're going to use sqlite for this project we're going to change it to the file colon sd. DB so it will create a dev. DB file in the root path of our application so let's save this and now we can go back to our schema. Prisma file and here change the provider to SQL light okay and you can see here we are reading the database URL from a the EnV function which reads the database URL variable from the EnV file and since we are going to use EnV variables we should install the config module with NJ otherwise we can't use EnV variables so in order to do that I'm going to install the n/c config package and then we should go to our root module the app module. TS file and here inside the Imports list I'm going to use the config module and call the for root function here okay so now we can access to the EnV variable throughout our nestjs project so let's get back to our schema file and here I'm going to create a model for user so I just paste the user model it has an ID email name and password if you're not familiar with Prisma I have a comprehensive course on Prisma and you can watch it and master the Prisma okay cool now we can use the migrations to actually create the user table inside our database so I'm going to say npx Prisma migrate Dev and set a name for it I'm going to go ahead with the init and we have a problem here and that's because we didn't save our schema so let's save this and run the Prisma myr command again and now as you can see we have a div. DB file inside our Prisma so the user table is now created in our SQL light database the next step is to create a Prisma service so we can use it inside other module to do Crow operation with Prisma so in order to to do that we need to install the Prisma client so here I'm going to install the Prisma client with this command npm install at Prisma / client okay and then we can create the Prisma service so inside our root module the app module I'm going to create a Prisma do service file so I'm going to say Prisma dos service.ts okay and then inside it we're going to copy and paste the code from the NJ documentation it will create a Prisma service that extend the Prisma client hand and on the module in it actually it will call the connect function from the Prisma so here you can see it's a injectable class and later we can inject and use this service in other services so let's save this and now we're done with configuring the Prisma with our application that simple so we can go ahead to the next section of this tutorial and that is creating the user module okay so let's create the user module I'm going to say Nest GMO which stand for module and then the name of our module which is user so as you can see here it creates a user module for us and here we need to create a user service and also a user controller so here I'm going to say Nest GS user which creates the user service for us and then we're going to create the controller with Nest GCO again user okay so now let's get rid of the test file inside the user module and as you can see we have a user controller user module and also a user service okay and here we're going to go to the user service and create a function for creating a new user and later we can use this function inside our off service for registering a new user so here first of all we need to inject the Prisma service here so inside the Constructor of this service we're going to use the Prisma service so I'm going to say private Prisma which is going to be type of Prisma service okay and now we can create the create function in this service so here I'm going to create an Asing function create which takes an object that contains the name email and password of the new user for registering that user inside our database usually we use dtos for this purpose so inside the user directory I'm going to create a directory called dto and inside it we're going to create a file called user. dto dots okay and here we can create our create user dto but before doing that we need to install two packages here the map types and class validator so here in the terminal I'm going to say npmi at ns/ map types and then we need to install the class validator and I think we need to install the class Transformer here okay so we have installed these three packages and now we can use them in our dto files so here I'm going to export a class called create user dto and to speed up the process I just paste the body of this create user dto here and here we should import this decorators from the class validator package and let's import e email decorator as well okay as you can see our dto object should have a name email and also a password inside it so with this dto we can easily validate our input data which come through the body of a HTTP request so let's save this dto and and go to the user service and before doing that if you're feeling that these are kind of too abstract for you again I highly recommend you to watch my crash course for njs I'm not going to teach you about the detail of the njs framework we just want to focus on authentication part so as you can see we are doing these configurations real quick so let's get back to our create function here and now we can use the create user dto so here we have a dto as the parameter of the create function which its type is the create user dto okay and first we should check inside our database if the user is already in our user table or not so we're going to say const user and set it to await this. Prisma do user. fine unic and inside the option object we're going to specify the where API okay and here we're going to specify email and send it to dto doil so this will check if the the email of the user is already in our user table or not and then we can check if the user is existed we can throw an exception here I'm going to say Throw new conflict exception okay and then pass the custom message inside it we're going to say email duplicated and then we can create our new user so I'm going to say const new user set it to await this. Prisma do user. create and then pass the option object and specify the data here and here we can spread the dto here it contains the name email and the password of the new user but here we should hash the password of the user before inserting the user in our database we need to install the bcri package here so I'm going to say npmi bcrypt okay and then we need to install the types of the bcrypt so I'm going to say npm i-d add types SL bcrypt okay so now here we can import the hash function from the bcrypt module so here I'm going to say import from bcrypt and then we can grab the hash function here okay and here we can set the password to hashed version of the password so I'm going to say await hash function again this hash function comes from the bcrypt module and then put the dto do password and then pass the number of salt rounds so I'm going to put the default value which is 10 and the number of salt rounds determine the computational complexity of the hash algorithm and actually affects the time it takes to calculate the hash the number of 10 is the default value for the hash function inside the book Crypt module so we just go ahead with the 10 okay and then here we can return the new user to the client so we can just return the new user but before doing that we can extract the password from the user object and then pass the user with that password so here I'm going to say cons an object and set it to new user okay and we just extract the password and put the rest into the result object okay so the result object is just ID email and name of the user and now we can return the result okay and now we can move to the heart of our project which is the off module so here I'm going to create a module called off Nest GMO off and create a controller for it Nest G Co off and also we need to create a service for this module okay and let's close this off and here as you can see we have the off module here so let's get rid of the test file inside this module we have a controller a module and also a service inside our o module okay so we're going to go to the O controller and here the first thing we should do here is to create the register endpoint which is for registering or signing up up a new user so it's going to be a post request so I use the post decorator here and let's name it register we can also name it sign up but I think register is better for that okay and let's import the post from the nj/ common package and then we're going to create our function which is a async create register user and here we can access to the body of the request with the body decorator okay and here we can turn the body to a create user D so for doing that make sure that you have installed the class Transformer okay so I'm going to say dto and set it to create user dto and then inside it we can call the user service. create function so in order to do that we need to inject user service into the a controller so inside the Constructor I'm going to say private user service which is going to be type of user service class okay and and here we can use the user service here so let's fix the typo here okay so here inside the register user function we're going to say return await this. user service. create function and pass the create user dto to the create function and that's it it will create a new user inside our database okay so now let's run our server and test this register function so I'm going to say npm Run start col Dev okay it gives us an error and that's because we are using the user service inside the off module but user service does not belong to off module so we're going to go to the off module here and here in the provids list we're going to add the user service here okay and that should solve the problem but we have another error here and also we should go to the user module and add the Prisma service here because we are using the Prisma service inside our user module okay okay again we have another error and also we should add the Prisma service in the off module and also we need to register the Prisma service in the app. module here so here we're going to add the Prisma service in the provider list of the app module okay and we got another error and that's because we didn't save the off module here okay so if you are using a service inside a module which should add it in the providers list of that module so as you can see our application is running without any error okay and now we can use the insomnia client to test our register API but before doing that let's go to the main. ts5 and change the port of the application to 8,000 because later we are going to use next CH and next CH as you know use the port 3000 as its default Port so we're going to change the port of the NJ project to 8 ,000 okay so now we can go to the insomnia client and here as you can see we are going to send a post request to the Local Host 8000 sloff SL register so we're going to send that and as you can see it will create for us a user that has the ID a one and it Returns the email of the user and the name of the user okay so now let's go to the Prisma Studio to see if the user is really in our database or not so I'm going to say MPX Prisma Studio okay we have the user model here and as you can see we have the user here Sakura gmail.com and as you can see the password is hashed in our database let's go back to our insomnia you can see we pass the password of the user as one 2 three but here you can see the password is converted to a hashed version so yeah that's it for the register section of the off module and now we can go ahead and create the login API for our off module okay so I go to the off controller here and here we're going to create our login API and this is where our authentication process actually starts and for authentication purposes inside our NJ application we can use the passport Library the passport Library which is a great and convenient way of authentication in Nest but here we're not going to use passport library because it's too abstract and you can't actually learn and understand what's going on in our off module we're going to implement the off module and authentication process from scratch so it can understand what's going on deep inside our off module and actually I have a tutorial for using the passport library for authentication in NJ and you can watch it if you want but I highly recommend you to watch this section till the end if you want to master and understand deeply how authentication Works in njs and in general in nodejs applications Okay so let's get into it the first step we should take here is to create a login API so we're going to create another post endpoint for our login which is our login endpoint so I'm going to use the post Creator here and let's name it login okay and now we can create our function I'm going to go ahead and create the login function which is going to be an async function and here our client must send the username and password inside the body of this post request so we can access to the body of the post request with the body decorator and we can turn it to a dtoo here so let's create a login dto for our login API so inside our off module I'm going to create a director called dto and inside it we're going to create a file called off. dto dots and inside it we're going to export the login dto class which expect a username which is an email and a password which is going to be a string so let's import the E string and E email from the class validator and we're good to go so we can use this login dto in our login API so let's get back to our a controller and here we can Define the dto which is going to be login dto class that we've just created and here we should call a login function from our off service but we haven't created this function yet so now we're going to create it so let's go to the off service here and create our login function so I'm going to create an asnc function login which takes a dto which is going to be type of login dto class okay and here first we need to validate the user so for validation I'm going to create another function in this class I'm going to create a function called validate user it takes the dto again which is going to be login dto and here first we need to check inside our database if a user with the provided user that is inside our dto is inside our user table or not so first we need to go to the user service and create a function for retrieving the user based on the username from our user table so I go to the user service and here create a function called find by email and it is going to take an email as its parameter which is going to be string and then we can use the Prisma service for finding the user so I'm going to say return await this. Prisma user. find unique okay and then pass the option object and specify the where object inside it and then we can specify the email here and set it to the email parameter that you've got here okay and now we can go to the off service again and here use the find by email from the user service so first we need to inject the user service inside our off service so inside the Constructor we're going to say private user service which is going to be type of user service okay and now we can use it inside our validate user so let's close this up to have more space here and here I'm going to say const user equals to await this the user service. find by email and then pass the d. username so we are are using the email as the username of the user okay and then we can check if the user is existed if user and then we can check the password of the user so we're going to do it with the compare function of the bcrypt package so let's import the compare function from bcrypt module so I'm going to say import from bcrypt and then we can grab the compare function from it okay and here we can use a parenthesis here and inside it we're going to have wait compare and then first we need to pass the provided password which is coming from our login API so I'm going to use the d. password and then pass the hashed version of the user password which we can get from the user object here I'm pass the user. password so again remember that we've got this user object from defined by email from the user service it is the user that we've got from the user table so the compare function first hash the Dil password and then compare the hashed version of the dto do password with the user. password which is already hashed inside our database so if this condition is true it means that the username and password are correct so we can return the user from the validate user function which means that the credentials here inside the dto object are correct and valid so we just return the user but for more safety we can extract the password from the user object so we can grab the password out of the user object and then return the result so the result object is actually the user object without the password okay and if this condition here is not correct which means that username and password are not correct we should throw an unauthorized exception here so here we can throw a new unauthorized exception here okay it actually returns a 401 error message to the client we can also pass C message inside it for example we can say username or password are not correct okay so now we can go back to our login function here and use this validate user inside that function okay so here we can say const user and set it to wait this. validate user and pass the dto inside it okay so if the credentials are correct and we've got the user here we should return the user object with a JWT access token and also a JWT refresh token to the client so we need to create two jwt's here the access token and refresh token from the user object so in order to create the jts we need to install a package called nj/ JWT so I open up my terminal again and here I'm going to say npmi at nj/ JWT okay and now we can use the JWT service from the JWT module of the nestjs so we're going to inject it in this service so here inside the Constructor I'm going to say private JWT service and set it to JWT service that comes from the nj/ JWT and since we are using the JWT service we should register it in the off module so inside the off module here I'm going to add it to the providers of the off module okay and we're good to go so I go back to our off service again and here inside the login function first we need to create a payload so I'm going to say const payload which is going to be an object and it has the username inside it which is going to be user. email okay and it has the sub object which is going to have a name inside it which is the name of the user so I'm going to set it to user.name okay so we are going to create our JWT is from this payload object so here we're going to return an object here which has the user inside it and also it has a backend tokens object which has the access token inside it and now we can create a JWT with JWT service and set it to this access token so I'm going to say await this the JWT service. sign async and then pass the payload object inside it and then we need to pass an option object first we need to set the expiry time of this JWT we're going to set the expires in and set it to one Edge which stands for 1 hour and then we should specify a secret key for creating the jbt okay so I'm going to go to the EnV file and create a JWT secret key and now we can set it to a random and complex secret key you can set it to a random string here but the better way is to create a complex secret key with open SSL command so if you are on Linux machine you can open up your terminal and paste this command open SSL rank and then base 64 and you can create a random and complex secret key with this command so as you can see it will create a really complex secret key so I copy that and put it in front of the JWT secret key okay and then we can have another key here for creating the refresh token so I'm going to call it JWT refresh token we can use the same secret key for creating the refresh token but it is recommended to have different key for refresh token so again let's call the op SSL command again and let's copy that and paste it in front of the jbt refresh token and for the type safety and our completion for our EnV variables we can create a type file for our in variable so here I'm going to create a file in the root path of our application I'm going to call it module. d. TS I'm going to declare a name space nodejs and then export an interface for EnV just pay attention to the spellings here and then it should have the database URL inside it which is going to be string and also a JWT secret which is going to be string and then a JWT refresh token which is going to be string as well so let's save this and close this off and let's close the anv file as well and here inside our login function we can set the secret here to the process. EMV the jbt secret key okay and here in order to be able to access to the EnV variable you should have installed the nexj config module and here configure the config module here in the app. module. ts5 as you remember in the first step of this tutorial so let's close this off and get back to our login API and here as you can see the backend tokens contains an access token which is a JWT that is Created from the payload that we've created here and and here we pass the secret to the process. EnV JWT secret key that we have just created with the open SSL command okay and then the backend token is going to have a refresh token so let's copy this and let's change it to the refresh token and let's set the expires into 7 days and let's set the secret to the JWT refresh token actually let's rename it to the refresh token key in order to avoid confusion here so I go to the EnV file and add a key to the JDP refresh token and let's copy that and go to our module. D.S file and change it to the JWT refresh token key so now let's save it here and get back to our off service and let's set it to JWT refresh token key okay so here as you can see if the credentials of the user is correct we return the user object and then we create a backend tokens object which contains jwbt access token and also a jwbt refresh token so let's get back to our a controller and here inside the login API we just return the login function from our o service this. o service we didn't inject it in our o controller so let's quickly do that and here we're going to say private o service and set its type to the a service class okay now we can use it here so I'm going to say this. a service service and call the login function and pass the dto inside it so yeah that's it for the login function now we can test it inside the insomnia so I go to insomnia and here I've already created login API which send a post request to the Local Host 8,000 slof SL login here as you can see we have the username and the password in the body of this post request so let's send the request to our server and as you can see we have a user object which has the ID the email and name inside it and also we have the backend tokens which contains an access token and refresh token later in this video in the next JS section of the video you can see that we save this access tokens inside the next off session and then we can use them whenever we want to access to a protected API in our njs server okay so now let's pass wrong password here okay and then send the request and you can see here we have the unauthorized Ed error so as you can see our login API works correctly okay in this section we're going to protect our apis with JWT access token so as a first step I'm going to create an endpoint inside our user controller and then we're going to protect it with the jbt access tokens so here I'm going to create a get endpoint here so I use the get decorator okay so let's import it from the next / common and this API will return the user profile so we need to get the ID of the user as a primes in this get endpoint so I'm going to put a colon here and then pass the ID here okay and then I'm going to create an asnc function here I'm going to call it get user profile and it is going to access to The prams Decorator here and then pass the ID here because we name our prams to ID here and now we can have access to the ID prams here so I'm going to name it ID here and set its type to number okay and and here we can return a function from the user service which Returns the user object based on the provided ID so let's quickly create this function I go to the user service and just copy the find by email function okay and let's rename it to the by ID and here we should have the ID which is going to be a number and in the where object we can specify the ID and set it to ID parameter here okay so that's it with the find by ID and now we can get back to the user controller and use that function so here I'm going to say return await this the user service so we didn't inject it in the user controller so inside the Constructor we can inject it so I'm going to say private user service and set its type to user service class okay and now we can use it here so I'm going to say this. user service. find by ID and then pass the ID here okay and now we can go to the insomnia and here as you can see I have created a user profile which send a request to the SL user SL1 and this one will be our ID pram so if I send the request you can see oh we have a internal error so let's get back to our NES here and see what's going on here and here the Prisma is expecting a number but the either primes is a string so the type of the PRS that comes from our HTTP endpoints are always string so we need to convert them to number if we want them as number so we can manually do that or we can do it with the njs pipeline so I go to the main.ts file and here I'm going to say app.use Global pipes and then pass a new validation pipe okay and then we're going to pass the option inside it we're going to set the wh list to True forbid nonwhite listed to true as well so for example if our dto object M contains username and password if we pass an extra property in the body of our request it will actually block that request and send a proper message to the client that says the extra property should not be included in the body object and then we can set the transform to true so by setting the transform to true it will automatically turn the ID which is a string to the number here so if I get back to insomnia and send the request you can see that it will return the user object to the client so we are going to protect this API from unauthenticated user so how we can do that as you have seen earlier in this project when the user loging into our njs application we create a JWT access token and send it back to the client and our client which is a NEX application should keep that access token inside the next off session and whenever the client want wants to access to the protected API it should include that access token in the Heather of its request so here in our protected API we should check if a valid access token is inside the header of the request so in order to do that we're going to create a guard for our application and whenever we want to protect an API we can decorate our API with that guard and it will automatically checks for JWT access token in the header of the request so let's get right into it so I go back to our NS application and here inside the O module I'm going to create a directory called guards and inside it we're going to create a file called jbt Dog guard. TS if we are going to use the passport library for our authentication this JWT guard can be easily created with the jbt strategy that is coming from the passport library but as I said we don't want to use pass passport library because it's too abstract and we're going to create this JWT Guard from scratch without any specific library and then I'm going to show you how we can use this guard to protect our API okay so as a first step we need to export a class named jbt guard so I'm going to say export class jbt guard and that class implements the can activate interface which is come from the nexj SL common and then this class should have a can activate function so I'm going to say async can activate which as you can see here since we implement the can activate interface it will automatically create the function for us so this class is kind of like a middleware that sits before our API endpoint and in this can activate function we're going to decide if we are going to allow the request to go ahead and reach our API so actually in this function we're going to extract the JWT access token from the header of the incoming request and check that JWT and if that's a valid JWT we're going to return true from this function which means that the njs allows the request to reach our protected API and if the jbt is not in the request header or it is not a valid jbt which is return false therefore NS will block the incoming request so it will protect our API so let's define the body of the can activate function so first we need to access to the request object so I'm going to say const request and set it to context which is from the parameter of the can activate function here and then call the switch to http function and then call the get request function okay so in this way we can access to the request object which is actually a Express request object and then we need to extract the token from the header of the request so I'm going to create a separate function for that purpose so here I'm going to create a private function extract token from from Heather and take the request which is type of request that comes from the express Library so as you know NES by default uses the Express framework under the hood so the request object is a request that comes from the express Library okay and then inside this function we're going to check the Heather of the request object so here I'm going to define a tuple here which have a type and also a token and then set it to request. Heathers do authorization and then call the split function so I'm going to split it based on the empty space so I'm going to pass the empty space here so the access token must be inside a authorization header in the request and then if it's not there we just return a empty array here okay and then we can check the type of the token so here we're going to return if type of the token is a bearer we can return the token and else which is return undefined so this function first check if a authorization Heather is inside the Heather of the request and if it's there it will split it to the type and token and then we check if the type of the token is bare it just return the access token and else it returns undefined okay let me show you an example here when we are going to include the access token inside the authorization hether of our HTTP request we put something like this in the authorization Heather first we put put a barer string and then a widespace and then we put our actual access token that we've got from the login API so the authorization Heather is something like this in the extract token from Heather function first we split this authorization Heather based on the white space here so this authorization Heather will be broken down to the type and the token and then inside the extract token from Heather function first we check if the type is be we return this token as the return value of the function otherwise we just return undefined so let's get back to our jbt guard class so now we can call the extract from Heather in the can activate function so I'm going to say cons token and set it to this. extract token from Heather so we have a typo here so let's fix it okay and now we can check if the token is undefined we can throw an unauthorized exception so here I'm going to say if not token then just throw new unauthorized exception and if there is a barrer token we should verify that token if it's valid or not so I'm going to say const payload and we should use the JWT service here so here in the Constructor of this JWT guard service I'm going to inject the jwbt service here so here I'm going to say private jbt service and set its type to jbt service class and as you can see the jbt service comes from the initi slj module okay and now we can use it so here I'm going to say await this the JWT service. verify async and then we can pass the token and also pass the option object we should pass the same secret key that we have used in order to create that jbt access token in the login function so I'm going to say secret and set it to process the env. jbt secret key okay if the token is valid the verify async function will extract the payload from the token and returns it but if the token is not valid it will throw an error so we can wrap it inside a try catch block here okay and then we put our catch block and then after calling the verify function from the jwbt service we can put the payload inside the request object so later we can extract the payload from the request object so I'm going to say request and set the user key here and set it to payload okay and if the verify async function throw an error here we catch it here and we just throw an unauthorized exception here and then as a last step in this can activate function we just return true so if we don't throw an unauthorized exception here and also here we reach to the return true statement and return true so we are allowing the request to reach our protected API so let's remove this bull in here to fix this error and also this observable error and that will fix the first error here and here we forgot to past body block of our Constructor so let's put it here and we're good to go and also as a last step we need to decorate this jbt guard class with the injectable decorator so later we can use this in our controllers okay so let's save this and let's go to our user controller here and here we can use a decorator called use guards which comes from the nestjs and then pass our guards here which is our jbt guard that we've just created so now now let's go back to insomnia and here let's check if the authorization here so let's remove it okay and let's send the request to our user API and I think our server is not running so we have an error here and that's because we should register the JWT service inside our user module so I'm going to put it here and let's save this and the aror is gone let's get back to insomnia and send the request and you can see this time we got an unauthorized error then that's because we didn't provide the access token in the he of our request so let's get back to our login API and let's provide the correct password and username here and send the request you can see we have an access token here let's grab the access token okay and let's get back to our user profile and inside the Heather we need to have an authorization hether okay and then we need to add the beer token a space and then our access token so as you can see our access token start with the bearer string and then a wi space and then our actual access token so now if I send the request and again we've got an unauthorized error here and let's check here and that's because we misspell the bear here so let's fix this okay and let's send the request and as you can see this time the jbt guard allows us to reach the protected API so if I tamper with the token and then send the request you can see that again we've got an unauthorized error message here so yeah in this way we can protect our apis inside the njs application okay now we are moving to the next section which is about creating a refresh token API so let's go back to our application and inside the a service here you can see that we set the expires time of the JWT access token to 1 hour so let's change it to just 20 seconds okay and now let's get back to insomnia and send a login request to get new access token let's copy that and let's get back to our user profile API and let's paste it here for the first time you can see it allows us to reach the protected API but after 20 seconds if I click on the send again you can see with the same access token we got 41 unauthorized error message here again and that's because our access token will be valid only for 20 seconds here so I put the 20 second here for the testing purposes but in the real world application usually we set the expired time of the JWT access token to about 5 hours but here for testing purposes I just set it to 20 seconds which is not realistic anyway we need to create a refresh token API so if our access token is not valid anymore we can send a request to the refresh token API and provide the refresh token in our header of the request which is usually valid for one week then we can get a new access token so let's create this API in the a module so I go to the a controller and here we're going to Define our refresh API it should be a post endpoint and let's call it refresh and then I'm going to create the refresh token function here okay before defining the refresh token function in the earth service let's create another guard for our refresh token API so go to the guards directory inside the off module and here let's create a file called refresh. guard. TS and let's go to the jbt guard and copy everything from this file and just paste it here so it is almost the same with the jbt guard all we need to do is to rename the class to the refresh JWT guard and here let's change the extract token from Heather here we expect the refresh token to be inside the authorization header but the type of header in instead of being a be we expect it to be a refresh okay and here when verifying the refresh token we need to pass the JWT refresh token key because when we are creating the refresh token inside the login API here as you can see we use the JWT refresh token key as the secret key so when we are going to verify that token we need to provide the same secret key so let's go back to our refresh guard here and I think we are done here so it's almost exactly the same as the JWT guard we are passing the JWT refresh token key as the key for verifying the token here and here we expect that the type of the token should be refreshed inside the authorization Heather of the request and here as you can see just like the JWT guardar we extract the payload from the token and then put it inside a user key in the request so let's get back to our PA controller and there decorate this refresh token API with the use guard and then pass the refresh jbt token guard okay so now we are going to access to the request object so here we put the request decorator inside the refresh token function and then we're going to call it wre so the wre is actually the request object so here incoming request first goes through the refresh JWT guard and if it has a valid refresh token inside its Heather it will pass from the refresh J guard and let's go back to the JW guard and here as you can see the payload object will be embedded inside the request object with the user key so here we can access to the w. user so now we are going to create a refresh token function in the O service and then we can call it here so I go to the O service and here we're going to create a refresh token function so I'm going to say async refresh token it is going to expect a user object which actually is the pay object that is embedded inside the request in the refresh jbt guard so the type of this should be any because it's not actually a user type it's just a payload that is extracted from the refresh JT okay so now just like the login function we can create a payid here from the user object so here the user object doesn't have an email I just mentioned that it's not actual user object it's a payload so here as you can see when we are creating the payload in the login API we create a username property inside the payload so now it has just a username and also a sub object so here we set the username to the user. username and we are passing the so to the just user. and that's because here we have a so object inside our payload so again this user object is actually this payload object that we have used to create the jdb access token and also refresh token and let's copy the backend token object here and we can return it as the return value of the refresh token function so I'm going to say return and put this object here so the refresh token just return object that contains the access token and refresh token inside it it doesn't have the user object inside it it will actually renew the access token and also the refresh token so now let's get back to insomnia here in the login API if we grab the refresh token here and go to the refresh token API as you can see it will send a post request to the SL off/ refresh and here inside the authorization Heather we have the refresh string so let's change the first letter to a capital letter because here in the refresh guard here we expect it to be with a capital r letter so let's get back to insomnia and let's paste the refresh token that we've just got from the login API and if I send the request oh it will returns nothing and that's because inside the O controller we didn't call the O service. refresh token so we just return await this. off service. refresh token and pass the rec object. user okay so let's save this and get back to insomnia and this time if I sent the request you can see we got an object which has a new access token inside it as well as a new refresh token so yeah in this way we can easily create a new access token and also a new refresh token with the refresh API in the a module so let's quickly recap what we have done here first we create a refresh JWT guard and inside this guard we check that if the refresh token is inside the authorization header and if it's there we verify that refresh token with the same key that we have create the refresh token in the login API and then if the token is valid we just extract the payload from the refresh token and put it in the user key of the request app object otherwise we just return unauthorized exception so if I tamper with the refresh token here and send the request the refresh token is not valid and we've got a unauthorized error message here so in this way we can create a refresh token API so now I think we're done with the NJ project and we are ready to move to the next section of this tutorial which is about the creating our front-end application in which we are going to create our frontend client with a nexj project and also handle the authentication with the next off package so let's get right into it but before moving forward if you're still watching this video please consider subscribing to my channel I have a variety of tutorials about nextjs njs and typescript that I'm sure that they will be useful for you so now let's create our nextjs application okay in this section of this tutorial we are going to create this application with Nexus version 13 and we are going to integrate it with the next a and also we are going going to consume our backend apis that we have created earlier in this video so as you can see it has a homepage link a dashboard link and also a sign in and a sign up button here and if I click on the sign in here you can see we are headed to the signin page that is created by the next off and if I click on the sign in you can see now the name of the user is shown in the Apper and a sign up button is there instead of the sign in and sign up button there so if I click on the sign out you can see we we are headed to the homepage of our application and if I click on this sign up here we can register a new user in our backend server so now let's get back to our homepage and if I click on the dashboard page you can see we are headed to the login page automatically and that's because we are protecting the dashboard page from the unauthenticated user with the next off middleware so if I click on the sign in and sign in here now we can access to the dashboard page which is a protected page and also we have a user profile here in the dashboard page and if I click on that we are headed to the dynamic route of the user slid of the user and here we are getting the data from the user API in the backend server which is protected by the jbt guard so we are using our access token that we've got from our backend server to be able to access to the protected API in our backend server so in this section you are going to learn how to integrate the next off with your next year's application how to implement the credentials provider create a sign page protect your pages with the middleware and also you are going to learn a robust way of refreshing your access token with the next off this solution works on the client components as well as the server components so without further Ado let's get to this section of our tutorial okay I open up our nexs project and the first thing we should do here is to install the next off so I'm going to open up my terminal and say npm I next off okay and then we should should create our next o rout hander so here inside the app directory I'm going to create an API directory and then inside it I'm going to create the off directory and then inside it we can Define our catch all route for the next off so inside square brackets I'm going to put three dots here and then next off and then inside this directory I'm going to create the route. ts5 which is our rat Handler so every request to this slash API SL off and then slash whatever just like this will be handled by this file so let's open it and inside it the first thing we should do here is to define the off options and also we should export it from this file so I'm going to say export const off options and then set its type to the next off option and as you can see the next off options comes from the next off and then we set it to an object here and then inside it the first thing we should Define is the providers list so as you know next app provides a variety of providers like Google provider GitHub provider and so on but the most basic one is the credentials provider which is used for authenticating the users with a username and password so our users must have a username and password in order to be able to signing into our application so here I'm going to specify the provids list and set it to a list here and inside it I'm going to put the credentials provider so first we need to import it from the next off/ providers SL credentials and then then put it here credentials provider and then inside it we should pass a option object and then the first thing we should Define is the name for our provider which I'm going to set it to credential and then we should Define a credentials object which actually describes our sign in page which will be created automatically by the next off so here I'm going to put the credentials object which has a username object that describes the username input in our signning page it has a label its type is text and it has a placeholder and also we have the password input here the label and type of the password inside it so this credentials object is for creating the signin page so next up we create a signin page for US based on the credentials object here although we can create our custom login page and I have a tutorial for that and its link is now on the screen so let's get back to our credentials provider here and the most important section of the credentials provider is the authorized function it's an async function that takes the credentials object and a request object and here don't confuse the credentials object in the parameter of the authorized function with this credentials object when a user in the signin page click on the signin button the username and password of the user will be packed inside a credentials object and will be passed to the authorized function and then inside this function we need to decide whether the user can be authenticated or not inside this authorized function actually we check the username and password of the user and if they are correct we should return a user object which means that the user is authenticated and if they are not correct we have two options either we can return a null value which result in sending a error message to the signin page of the user which says that your username and password is not correct and the second option is to throw an error here with redirect the user to the error page of the next op so let's define the body of the authorized function here the first thing we should check here is to check the username and password if they have a undefined value so if that's the case and one of them has undefined value we just return now to the next off otherwise we grab the username password from the credentials object and since we have an external API for our login we should send a post request to that login API in in our nestjs server so the nestjs login API checks the username and password for us as we saw in the nestjs section so here we need to send post request to our backend URL SL off/ login and let's import the backend URL from the leap. constant file where I have defined it and set it to the HTTP Local Host Port 8000 which is the address of our nestjs server so let's get back to our credentials provider here and then we should check if the status code of our request is 401 which means that the user is not authenticated we first lock the status text of the request and then we just return now to next off which means that the user is not authenticated so remember that in our login API in the NJ server if the username and password was not correct we just throw an unauthorized exception which actually sends back a 401 error message to the client so otherwise we can grab the user object from our response object and then we we can return the user object to the next off that's it for the authorized function okay and then we need to Define our actual route Handler so here I'm going to say const Handler and set it to next off function which comes from the next off and pass the O option that we have defined here so I'm going to put it inside the next o function and then we can export this Handler as the get function and also as the post function and one question you might ask is that why we didn't pass the off options directly to the next off and why we should export it from this file you will find this answer later in this video but I'm going to quickly tell you the answer if we want to access to the next off session in the server components we can use the get server session function from the next off and this function will require the off options as its argument so we need to export it from this file and later we can use it in the get server session function but one of the common mistakes here is is to export this Handler instead of the off option object and then when we try to use this Handler as the parameter of the get server session we will not get the session from the get server session function of the next off so again don't export the Handler and use it as the off options Define the off options as a separate object and then export it from this file and then use it in the next o function so yeah that's it for now for the route hler we will get get back to this file here in this video to add some more configurations but for now we are done here okay so now in our Nexus project when we want to know if the user is authenticated or not we can get the next off session and in order to have access to the next off session we have two options in the client components we can use the use session hook which actually saves the next off session inside a react context API but in the Ser components we can use the get server session function from next off that will return the next off session in our server components and also in the API routes so now let's configure the use session hook as I said it's actually a react context API so we need to wrap our whole application in a session provider which is actually a react context provider so here inside the components directory I'm going to define a provider's component okay and then inside it we just create a component that takes the children as a props and then wrap them inside a session provider which as I said is actually a react context API provider so first let's define an interface for the props of the provids component it has a children inside it okay and then we need to import the session Provider from the next off/ react okay and then we go to the root layout of our application and wrap all the pages inside our application with the provids component that we have just created okay and now every client component in our application can have access to the use session hook of the next off okay and one thing we forgot here is to set the provider's component to the use client okay and let's get back to our root layout so the provider's component is a client component and here you might ask wrapping the children of the root L inside a client component the provider's component does it make all pages to client components and the answer is no we can have a server component WRA inside a client component and that doesn't turn into a client component okay so now let's move to the next section which is creating our signin button so here I'm going to go to the components directory and create a signin button here okay so let's create a component here so here if the user is already authenticated we should render the name of the user and also a sign out link and if the user is not authenticated we just need to render the sign in and also sign up buttons so here in order to see if the user is authenticated or not we can use the use session Hook from the next off so I'm going to use the use session hook and let's import it from the next o/ react and then we can grab the data object here and just rename it to the session and now we can check if the session is existed and also it has a user object inside it we can say that the user is authenticated so we're going to render the name of the user and also a sign out link so as you can see we render the name of the user inside a ptag session. user.name and also we have a link here which calls the/ API SL off/ sign out so as you remember every request to the SL API slof and then slash whatever will be handled by the rout Handler of the next off that we've just defined here okay and then we need to just import the link from the next link it's a link from the nextjs and if this condition is not true which means that the user is not authenticated yet we need to render a signin link and also a sign up link so here instead of this return here we return a link that goes to the SL API sl/ signin and also we have another link for signing up or registering a new user which goes to the/ sign up so as you can see this route here will be handled by the next off automatically but this sign up route here will not handle by the next AU because it doesn't start with the SL API slof so we need to create our own sign up page and we will create it in the next section of this video so here just in case know that instead of having a link here we can have a button here and inside the onclick event of that button we can call the sign in function which comes from the next off and that will automatically send us to the signin page of the next app and also here instead of this link we can call the sign out function from the next off which actually sign out the user from our application so you can choose between these two options here okay so this is our sign in button component and then we need to go to the Apper component and as you can see it's say Apper that has to link the homepage and also the dashboard page which we haven't created yet and then we need to put our signin button here so I just put it here and import it from the signin button. TSX file okay so now let's run our application okay so we have an error here and that's because the use session H can't be used inside the server component so let's get back to our signing button here and Mark it with the use client directive here so let's save this and let's get back to our browser and as you can see we have the Apper here which has the signin button inside it so if I click on the signin button here you can see it will send us to the signin page that is created automatically by the next a okay so if I click on the sign in here it will pack the username and password of the user into a credentials object and call the authorized function and let's get back to our next off Route hun and you can see here inside the authorized function we send a request to our NJ server to the/ off/ login API and that will check the username and password and if they're not correct it send us an 41 error message otherwise it returns an object that has the user object inside it as well as the access tokens so let's get back to our signin page and click on the sign in here and as you can see we have authenticated because the sign out button is here but here we don't have the name of the user and that's because the type of the return object from our login API in the NJ server is not compatible with the type of the user object inside next off in the nextjs project so let's get back to the signin button and here let's check the user object here you can see it has an email image and name but if I get back to the insomnia here you can see that the return object from the login API of our njs application our backend server is an object that has the user inside it but that user has the ID email name and then a backend tokens object that has the access token and also the refresh token inside it so we should change the type of the user object inside the next off session to be compatible with this whole object so in order to do that I go back to our nextjs application and inside the lip directory I'm going to create a type file I'm going to name it next- off. D.S okay and then the first thing we should do here is to import next o from the next o package okay and then we need to declare a module next off and then inside we can change the type of the session object so I'm going to Define an interface here and name it session just pay attention to the spelling here and then here we can Define the shape of our session object it has a user inside it which is going to have a ID email and name so let's put it inside the user interface here and then it has the backend tokens object so here I'm going to put another object here backend tokens object which has the access token and also the refresh token inside it okay so let's save this and if I go back to our signin button here here and now if I click on the session you can see it has now a user object as well as a backend tokens object inside it and then we can use the user object and now we can access to the name of the user okay so let's save this and get back to our browser and let's sign out now okay and let's sign in again okay and as you can see we still doesn't have access to the name of the user so let's get back to our signin button here and here let's just log the session object to see what's what going on there so let's open up our console here and let's sign out okay and sign in again and we have the session object here and let's expand it and as you can see it doesn't have the backend token inside it and the user object doesn't have the ID name and also email inside it in order to fix this problem we need to use next off callbacks so I go back to the route hler of the next off and after the providers list I'm going to define the callbacks object so what is the callbacks they are asynchronous functions that we can use to control what happens when an action is performed so we can Define four callbacks here a JWT redirect session and sign in we're going to use JWT and session here so what are the JWT and session callbacks so let me show you a diagram here when a user sign into our application a jwbt callback will be called and it receive the token and the user inside it we're going to check the token and user in a second and then the jbt Callback Returns the token object and the token object will be received by the session callback and also when we are checking the session of the next off the jbt Callback also will be called but this time the user object is undefined and then it Returns the token and the token will be received by the session callback so in the JWT callback the user object is only available when the user sign into our application so now let's get back to our next o rat Handler and Define the JWT callback I'm going to say as JWT and then it receive the token and also the user and then it just need to return the token from it okay and now let's log the token and user object here to see what's going on so let's lck them here okay and now let's get back to our browser and let's sign out okay and let's sign in again let's click on the sign in with the credentials here okay and now let's check the vs code terminal here and as you can see the first time we have the user object here when the user user is signing and the second time when we get the session from the use session hook inside the sign button here we have the token but the user is undefined but the first time you can see that the user object is actually the object that the backend login API will return as the response so now all we have to do here inside the JWT callback we need to check if the user is available we embed the user object into the token object so the user data can be received by the session call back so here I'm going to check if the user is available we're going to return an object here that contains the token data so I'm going to spread the token here and also we need to spread the user data here otherwise if the user is not available we just return the token and now we can Define the session call back here and receive the token from the JT call back so I'm going to say async session call back here and it receive the token and also the session object here every time the session will be get by the use session hook or get server session function the session call back will be called so here we need to say that session. user and set it to token. user so as you can see we have spread the user object here which is not this user object it is the whole object that contains the user object and also the backend tokens so don't confuse them with this user object here you can name it whatever you want want and I should have done it in order to avoid confusion but keep in mind that the user object that is received by the jbt Callback is the whole object that returns by the login API okay so let's get back to our session callbacks here and we can set the session. user to the token. user as you can see the token doesn't have a user object inside it so if I hit the control space here you can see that the token doesn't have a user object so what we need need to do here is to change the type of the token the type of the token itself is the J that comes from the next off so we need to change the shape of the JWT type in order to do that I go to the next off. D.S file and here we need to import the JWT type from the next off/ JWT and then we're going to declare the module next off/ JWT and then we need to define a JWT interface so here I'm going to say interface JWT and then we just need to copy the user type here and also the backend tokens type here and put it inside the JWT interface so let's save this and as you can see the shape of the JWT is exactly as the same of the session interface so let's get back to our route Handler of the next off and now if I hit the control space here you can see now we can have access to the backend tokens and also the user object here so we set the session. user to the token. user and then then in order to save the backend tokens inside the session object we need to say that session. backend tokens and set it to token. backend token and then we just need to return the session from the session call back okay so let's save this and if I sign out here and again sign in here and let's check the session object here in the console and you can see now session have the backend access token and also the user inside it and we already have the name of the user in the signin button so in this way we can change the type of the session object and make it compatible with the type of the object that our backend login API is returning okay in this section we're going to create our sign up page for registering a new user so if I click on this sign up here you can see we are headed to a 404 error page because we didn't Define the page for the sign up route here so now let's create this page in our nextjs application so I go back to our nextjs project and inside the app directory I'm going to create a route for sign up and inside it we're going to create our page. TSX file okay and then we're going to create a component here and let's name it sign up page okay and to speed up the process let me paste the jsx here for the sign up page so as you can see it has three input boxes here the input box is just an input element with a label text attached to it so you can find it inside the components directory of this project so let's import it from the components directory okay and then we need to define a state for our form here so we're going to define a user of here which its type is form input so now let's paste the form inputs here is a type that has a name email and password inside it so the type of this user of here is an object that has name email and password inside it and here as you can see we bind the name to the first input box the email to the second and also the password to the third input box so we use a user here and that's because we don't want to rerender the page every time user enter a character in each of our input boxes and after the input boxes here as you can see we have a button here so let's import the button from the components directory and we have also a link here that is for cancelling the form it redirect the user to the homepage and on the onclick event of the button we call the register function so let's define the register function here you can also use the server actions here but for the Simplicity we just go with a normal function here and here let's import the backend URL from the constants file okay so the register function will send a post request to the backend URL SL off/ register API and then put the name email and password of this form to the body of the post request and then if we check if the response is not okay we just show the error message to the user and then return the function and if there is no error here we can grab the response object here here which is actually the user object that has been inserted to our database and we can just show a user registered message to the user so let's save this and we need to mark it with the use client here so let's go back to our browser and click on the sign up as you can see we have the sign up form here and let's put my name here and let's go ahead with a duplicated user because this email is already saved in our database so let's click on the submit and you can see we have a conflict error here and let's turn it to Aura 33 for example and click on the submit here and as you can see we have the user registered message here so now we can grab this email and click on the sign in here let's put the Sakura 33 here and our password is also 123 and click on the sign in here and you can see now we are signing with the new user in our application okay and in the next section we are going to quickly create the dashboard page here and we are going to protect it from the UN authenticated user with the next off middleware so now let's quickly create our dashboard page I go back to our project here and let's create the dashboard route here inside our app directory and then inside it we're going to create our page. TSX okay and let's create a functional component here and let's rame it to dashboard page okay and let's create a layout for our dashboard route okay and let's paste the code for the dashboard page here as you can see we're going to have a a sidebar here and inside it we have a link here and that link will be sent us to a dynamic route SL dashboard SL user and then ID of the user which will retrieve the user profile from our backend API and then show them to the user and then we are going to render the children of the layout in a div here so this will be our sidebar so this is a server component and in order to have access to the session of the next off we can't use use session hook because as I said it's a server component so instead we are going to use the get server session so I'm going to say const session and set it to await as you can see it's a acing component so we can use the await keyword here and then we can use the get server session that comes from the next off so as you can see it is coming from the next off okay and then we just need to pass the off option that we have exported from the next off Route Hare this off options object so I go back to our dashboard layout and just pass the off options okay as you can see it is imported from the next o route H hander and as I said in the beginning of this section one of the mistakes that we might have here is to export the Handler that we've got from the next off function and then we try to use the Handler as the off options in the get server session and it won't work it will return a session that has an undefined value so keep in mind that from the route Handler of the next off first create a separate off options and put your configurations here and then export it from this file so don't forget to export the off options from the next off Route Handler okay and let's save this and let's get back to our browser and let's go to the dashboard page here okay and as you can see we have the layout here and this is our page and this is the link in inside the layout file and if I click on that it will direct us to the/ user sl3 which is the ID of the current user that is coming from the session of the next off and here as you can see we are getting that with the get server session so now let's create our Dynamic route for the user here inside the dashboard I'm going to create a user route and then an ID Dynamic route and then page. TSX okay again to speed up the process I just paste the code for this user page and as you can see here we have defined a type for the props for this page and then inside it we have the prms object which is an ID here and with that we can access to the ID PRS here and we have the page here which is an Asing server components and inside it it sends a get request to the backend URL and then slash user and then slash ID of the user that we've got from the prms doid okay and then we've got the user from the response of this get request and then we just render the name of the user here and also the email of the user but if I go back to our NJ application you can see inside the user controller in the/ user slid API we protected with the JWT guard it means that we should have an authorization header inside the header of our request to this API so we didn't provide the authorization header inside it so let's run this request and see what we get back as the response of this get request okay so I go back to our browser and click on the user profile which will direct us to the dashboard SL user1 which is the ID of the current user but we don't have any data here so let's go back to our nextus project and open up our terminal and see what we have here so here as you can see we have blog due response but here as you can see the status code is 41 and the status text is unauthorized and that's because we didn't include the authorization Heather inside the Heathers of this get request so now let's include the authorization here I'm going to say authorization okay and then we put the beer text here and then we need to put our access token so in order to have access to the access token of the current user we need to have access to the session of the next off so here I'm going to say const session and set it to await get server session and then pass the off options okay okay and now we can put the access token here in the authorization hether so I'm going to use the session. backend tokens. access token okay so let's save this and get back to our browser and let's refresh to page and as you can see again we don't have any data here and let's get back to our nexts project and as you can see here again we have a for one unauthorized message and I'm going to tell you why it is happening here I go back to our NJ application and inside the off service here you can see that we have set the expired time of the access token to just 20 seconds so now if I sign out and sign in to get a new access token and then if I click on the dashboard and user profile you can see we have our data here but after 20 seconds the access token of the user is expired and if I refresh the page you can see again we don't have any data because the access token is expired now so later in in this video we are going to implement a refresh token functionality in order to automatically refresh the token when the access token is expired and we are going to use a solution that works in the server component as well as the client components but before doing that I'm going to protect the dashboard page and all of its children pages from the unauthenticated user so if I click on the sign out here and if I click on the dashboard you can see I can have access to the dashboard page even though I'm not sign in in our application so we can protect our pages in two ways with the next off we can get the session from the get server session in our pages and then check if the session is not undefined it means that the user is authenticated and we can allow user to access to the page and here we can get the session from the get server session and if the session is undefined it means that the user is not authenticated and we can redirect it to the login page manually but we can do this automatically with the next off middleware so here in order to do that I'm going to create a middleware TTS file inside the SRC directory and here we can just export default from next off middleware and then we can export a config object here that has a match list inside it and inside the matro we can Define our protected pages so we are going to protect the dashboard page and all its children pages so let's save this and now if I go back to our application and if I refresh the page you can see the next off automatically will direct us to the login page so let's get back to the homepage and again click on the dashboard page but again we are headed to the login page because we're not signning so if I sign in here again I click on the dashboard page we can have access to the dashboard page because we have sign in into our application and that's it we can easily protect our pages with the next off middleware okay in this section we are going to implement the refresh token functionality for our next CH application so as you can see when our access token is expired we can refresh the access token automatically in next Chas so let's get right into it so as a first step we need to go back to our njs application our backend server and here in the OD service in the login function we return the backend tokens which contains the access token and also the refresh token we need to export another property inside the backend tokens which is expiry time so first of all we need to Define a constant here con expire time and we're going to set it to 20 seconds so it is going to be 20 * 1,000 milliseconds is going to be 20 seconds and here in the login function after the refresh token we can have a expires in property that takes the con time of the server and then add the 20 seconds to the current time of the server so the expires time here is the 202 after the current time of our server so as I said the 20 seconds is not a realistic time for expired time of the access token usually we set it to more than 5 hours or a day for the access token and 7 days for the refresh token but here for the testing purposes we can't wait 5 hours for our token to be expired so I set it to 20 seconds here and we also need to add the expires in property in the returning object of the refresh token function as well so let's copy that and here in the refresh token function inside the return object we include the expires in property okay so now our backend tokens object has the expires in property inside it so let's get back to our NEX s application and let's go to our next off. D.S file and here we can include the expires time in the backend tokens interface here and also we're going to include it in the JWT interface here okay okay so let's save this and I go to the rout Handler of our next off and here in the jbt Callback we can refresh our token as I said earlier the JWT function will be called every time the session is checked so here instead of returning the token we can check if the current time of the next year server is less than the backend tokens that expires in which we've got from the backend apis which is return the token this condition here means that the the access token is not expired the time of our system is less than the expired time of the access token so we just return the token but if this condition is not true it means that the time of our system is now greater than the expiry time of the access token so it means that the access token is now expired so now here we can refresh the token now we can define a refresh token functions and call it here to refresh the token and then return the token from the JWT carb back with the refreshed tokens so now we are going to Define our refresh token function here outside the off options I'm going to Define async function refresh token which take a token which its type is the JT and just return a promise that resolve to a JWT type so again this token inside the JWT callback is type of JWT okay so here we can get the token and then renew its backend access tokens and then return it with the refresh token so let's define the body of this function we just need to send a post request to our backend URL and then SL off SL refresh which is for refreshing the token and then inside the authorization header of this post request we need to put the refresh string and then the token that backend tokens that refresh token so if I go back to our nestjs application in the AR controller you can see we have a refresh token API and we protect it with the refresh token JWT guard that expect the request to have a refresh token inside its authorization header so we put the old token. backend tokens. refresh token the expiry time of the refresh token is 7 days so it's not expired yet now let's import the jdb type from the next off/ JWT to get rid of that error and we have a typo here let's change it to a lowercase and we're good to go and then we need to get the response of this post request and now we can return a new token with the refreshed access token and now we just return an object here spread the token and we set the backend tokens to the response of this backend refresh API so let's save this and let's get back to our jbt callback and here we can say if this condition is not true which is return await and then call the refresh token function that we've just created and pass the token inside it so in this way we can easily refresh the token every time the token is expired so now let's log the refreshed string here so every time this refresh token function is triggered we can see it inside the console of this project so let's open up the terminal and let's get back to our project and let's sign out okay let's sign in again we can have access to the data of our backend API so let's wait for 20 seconds and after 20 seconds here if I refresh the page you can see again we don't have the data here let's check it here we call the refresh function but the status code is 401 so let's go back to our NJ project go to the refresh jbt guard and here check the extract token from the Heather and yeah we expecting the type of the refresh token to start with the r Lether in the uppercase so let's get back to our NJ application a and here let's go to the next out rout Handler and in the refresh token function and let's change the first layer of the refresh to the uppercase so let's save this and let's refresh the page okay and now let's sign out here again sign in and then go to the user profile now I pause the video for 20 seconds okay I have waited for 20 seconds and if I refresh the page and now we can see we are getting our data from the backend AP pi and that's because here as you can see the refresh token function has been triggered and in the backend side also you can see we have access to the refresh API so this mechanism will automatically refresh our tokens if the access token is expired so let me recap what we have done in this section in the JWT callback first we check if the time of our system is less than the expired time of the tokens we just return the token but if the time of our system is greater than the expired time of the tokens it means that the access token is already expired so we call the refresh token function and pass a token inside it and the refresh token function will send a post request to the backend server and then SL off SL refresh and put the authorization here with the refresh string here and put the refresh token of the current user inside it and that will give us a new access token and then here we just replace the backend tokens with the response that we've got from our backand API which contains the new access token new refresh token and also a new expiry time so that's it for the refresh token and in this video you have learned the basic of authentication in a full stack project and that brings us to the end of this tutorial so stay tuned for my next video and have a nice time bye-bye
Info
Channel: Sakura Dev
Views: 22,684
Rating: undefined out of 5
Keywords: fullstack auth, nextauth, next-auth, next auth, nestjs, next nest authentication, next js, next js 13, 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: khNwrFJ-Xqs
Channel Id: undefined
Length: 93min 47sec (5627 seconds)
Published: Thu Aug 31 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.