Authentication in Nest.js: JWT Protected APIs and Refresh Token

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's going on developers in this tutorial we're going to implement the authentication in next year's with passport Library in the first section we're going to authenticate our users with username and password and in the second section we're going to protect our API endpoints with JWT access token and in the last section we're going to implement the refresh token functionality in our next JS app so without further Ado let's get into it okay I open up the previous videos project but before moving forward let me tell you that you should have some basic understanding on sjs framework so if you're not familiar with the niches I highly recommend you to watch my previous video which is a crash course on niches and by watching that video you will have a solid understanding of the fundamentals of messages okay let's moving forward so the first thing you want to do is to create an aft module so in the terminal I want to say Nest G module off and then create a service for this off module so I'm going to say Nest g s off dash no spec because we don't want it to create a test unit for this service and also we want to create a controller for this module so I'm saying this GCO of null spec okay so if I go to the auth directory you can see we have an off module of service and also off controller okay I go to the auth service and here in this service we're creating an async function called validate user so I'm going to say async validate user and this function takes the username and password as its parameters and then check if such a user is existed in our database and if so it just return the user and if not it just return now so here we're gonna have a username which is going to be string and also a password which is going to be string as well so first we have to check that if any user with this username is existed in our database so we're going to do this with the help of user service so before doing that let me inject the user service inside this service so I'm going to create a Constructor and then insert it we're going to have private with only user service which each type is the type of user service class okay and in the validate user function we're going to say currents user equals to await this stack user service and then call the find one with username function and then pass the username into it so if I go to the user service you can see we have a find one with username function which takes the username as its parameter and then use the user repository that find one function and find the first user in our database that its email is in match with the username parameter so in this application we consider the email of the user as their username so let's go back to our auth service here and after find one with username function we check if the user is not now so we're going to say if user and if the password parameter is in match with the password of the user in our database which is returned the user or otherwise we just return now but since the passwords in our database are hashed we can't compare the equality of the passwords we just this operator we have to compare the passwords with the compare function of the bigcrypt library so before doing that let me import TV Crypt so I will say import store as decrypt from Big Crypt and by the way if you remember from our previous video we installed the bookcrypt library with npm I decrypt that's it so let's go back to our validate user function and call it the Crypt the add compare function and then pass the password parameter and also user dot password so this compare function is an async so we have to put a weight before it so we're gonna put it inside the parenthesis so here we check if the user is not null and also the password parameter and the user that password are the same with return the user but we don't want to return the user object with its password so we're gonna extract the password out of the user object so we're going to say const an object and set it to user and then back to the object extract the password and then put the rest of the user object into a result object and then return the result so the result object is our user object without the password property and also if this condition is false we just return now so I'm going to say return now so that's it with the validate user with with this validate user function we text the username password as its parameter and then check if such a user existed in our database we just return that user without the password property or else we just return now and next we're going to define the login function inside this auth service but before doing that we're going to install three packages the first two one is the initials JWT and since we're going to use the passport library in this project we're going to install the password jw3 as well so I'm going to say npm I dash dash save messages slash JWT and also password Dash JWT and next we're going to install the typist for the password JWT so we're going to say npm all right save div at type is slash password JWT okay let's close this off and Define our next function inside the earth service which is the logging function so I'm going to say async plugin and this logging function takes a user object and then creates a JWT access token for this user and then Returns the user along with its access token into the client so we're going to have a user which is type of our user entity and then inside it we're going to create the JWT access token and in order to create the JWT access token for the user we're going to use the JWT service that comes from the initials slash JWT package that we just have installed so first of all we're going to inject the JWT service inside our Constructor so here in the construction I'm going to say private JWT service which is going to be type of JWT service which comes from the app niches slash JWT okay and then we go back to our login function and here to create a JWT access token we should create a payload object and then from this payload object we're going to create a JWT access token so first of all I'm going to say const payload it's going to be an object which has the username inside it which is going to be user dot email and then a sub object which is going to have name which is going to be user.name and also here we can add another info about our user but here we just want to keep it simple so after that we can return an object which contains our user so I'm going to spread the user object and then it contains an access token so this access token is going to be created from this payload object so here we're going to call the this dot JWT service and then call the sine function and then pass the payload object so we have an error and that's because we forgot to close our curly braces here and the arrow is gone and also we should remove these core braces here so okay we're good to go and here as you can see in the login function we first create a payload object and then we return an object that contains our user and also an access token that is Created from the payload object with the jw2service.sign function okay and that's it for the of a series but here because we have used the user service and also JWT series inside the of a service we have to register them inside the earth module so here inside the providers list I'm going to add the user service and also JWT service and then inside the Imports list of this module we're going to register and configure the JWT module so we're going to say JWT module which comes from the messages JWT and then call the register function and then pass an option object to it which is going to have first of all the secret keep which we are going to read it from the EnV file so I'm going to say process that EnV the JWT underscore secret and then we're going to have a sign in option and it is going to be an object and inside it we're going to specify the expire in property which Define the expired time of our JWT token so I'm going to set it to 3600 second which is going to be one hour okay we're good to go now let's save this and we can now go ahead and create our Envy file and then put this JWT Secret inside it so I go to the root path of our project and create a pnb file so I'm going to say that EnV and inside it we're going to put a JWT secret variable and it can be set to a key for example we're going to have a secret JWT and put a random number so what is this JWT secret key well it is used to sign and verify the jdbt tokens so when a JWT token is going to be signed it is signed using this secret key and the recipient of the JWT can then use these same secret key to verify the Integrity of the token and ensure that it has not been tampered with so it is really important to keep this secret key secure and I'll change it with anyone who should not have access to it because having access to this secret key allows an attacker to create forged tokens that could be used to gain unauthorized access to our system and that's why we didn't put it directly inside our typescript file and instead we put it inside the EnV file okay I hope this little explanation makes sense for you now I save this and close this Envy file and now we can install the passport libraries so I open up the terminal and here paste a script for installing the messages passport passport itself and also passport local so we install this through a library okay and then I'm going to install the typist for the passport local okay and I close this off and now we can go ahead and Define our our passport local strategy so what is the password local strategy with passport local strategy we can authenticate our users with username and password so the users have to provide a username and password in order to log in into our system so in order to Define our passport strategy I go to the auth directory and insert it I'm going to create a directory called strategies and I started we're going to create a local dash strategy .ts file and in this file we're going to export a class named local strategy and extended from passport strategy which comes from the messages slash password and then as the strategy class which comes from the passport local so here as you can see we have two strategy class the first one comes from the passport JWT and the second one comes from the passport Dash local so here we import the strategy from the passport Dash local because our strategy is local and then inside it we're going to have a Constructor and then inside the instructor we're going to inject the AFT service which is going to be to type of class of service and then inside the body of the constructile we're going to call this superclass and then after the Constructor we're going to define the validate function so it's a async function async validate and it's going to take a username just going to be string and also a password which is going to be a string as well and then inside it we're going to call the validate user from the off service that in the beginning of this video we just created so let's go back to our local strategy file and here we're going to say const user equals to weight this there are service and then call the validate user and then pass the username and password to it and then we check if the user is now then we throw a unauthorized exception that is come from the Nexus slash common so we're going to error and that's because we have to instantiate a new object from this unauthorized exception class and then if the user is existed we just return the user and for the last thing don't forget to mark this local strategy class with the injectable decorator from the messages and then we go to the auth module and inside the providers list we add the local strategy class and then for the next step we're going to create the local guard so I go to the auth directory and inside the auth directory I'm going to create a electrical guards and inside it we're going to create a local dash offs dot guard dot T is filed and here we just have to export a clause named local ask guard actually the name of this class is up to you but I think the local auth card is a good name for it and then extend it from the earth guard function which comes from the messages slash passport and then pass the local string which means that we are going to create a local guard here and then just put a empty body for this class and that's it okay and let's save this and you will see the usage of the local off guard class in a couple of minutes in this video so now we can go ahead and create our login endpoints inside our auth controller so here inside this off controller we're going to create a login API so I'm going to create a post API and let's import the post from the industries slash common and then create an async function called login and inside the parameters of the login with an access to the request object and we're going to do this with the request decorator that comes from the industry slash common and let's call it Rick and then inside the login function we're going to return weight and then call the login function from the off service so let's inject the off service inside this controller we have a Constructor and then private of service which is going to be type of the auth service class and then we can access to the off service here so we return this that opservice.login and then pass the work the user okay and if I go to the login function inside the off service you can see it receive a user object and then create a payload object from the user and then just return the user object and also create a access token using the JWT service and then return this whole object to the client and if I go back to the auth controller you can see we extract the user from the request object and then pass it to the login and it creates a access token from this user object but before calling this login function we have to authenticate the user so in order to do that we can just decorate this login function with the use guard which comes from the niches slash column and then pass our local strategy glar and that's it oops uh I didn't specify the login route here so when the post request come to the slash off slash login it first called the local strategy guard and then local strategy guard calls the local strategy and then local strategy class called the validate function inside it then the validate function calls the validate user from the auth service and the validate user inside the auth service check if any user with this username and password exist in our database it Returns the user so inside the local strategy we have the user object that is returned from the validate user function of the arc service if it is null it means that the user is not authenticated so we throw a unauthorized exception to the client and if it's not null it means that the user is authenticated so we return the user object and here login function is called and the user object returned by the local strategy class is captured within the request object and then we return the request that user into the login function of the auth service and then it creates an object which consists of the user object and also an access token which is a JWT token that is signed with the data of the authenticated user and then it returns this object to the client so let's save the controller and before testing this login API inside the insomnia let's create a register API so we can create a user so we're going to create a post API which is going to be off slash register and then create an async function and we call it register user for example and then access to the body of the request with the body the crater and let's call it the create user dto and then it's typed it's going to be create user detail class which we have defined in the previous video and then inside the body of the register user function we call the userservice.create function so in order to do that we have to inject the user service inside the auth controller so we're going to have private user service which is going to be type of user service class and now we can access to the user service class we'll just return wait is that user service dot create function and then pass the create user detail to it so if I go to the create user detail class you can see that our dto or our body request should have a name email and also a password so let's close this off and let's save the auth controller and then since we have used the user service inside the auth controller we have to register the user service as a provider inside the off module so we just add the user service here and now we are good to go to run our server so before running our server let's run our Docker compost file and now the postgres container is running so we can go ahead and run our server so here we have an arrow let's see what is it and it says that the user repository is not is used inside the auth module so here we go to the off module and inside the Imports list we say typorem module and then call the for feature function and then pass a list and we say we want to use the user repository inside this module and let's save this um yeah the arrow is gone and let's open up the insomnia and let's make it a little bigger okay here as you can see we have a post request to the slash off slash register and then pass the name of the user which is test user the email of the user test user at somewhere.com and the password one two three and if I click on the send you can see that it creates a user for us with the name of test user email test user at somewhere.com and also ID of six so we can use the email of this user as a username and then one two three for its password in the login API so I go to the login API here as you can see we have a post request to slash off slash login and username will be test user and the password one two three so let's pass a wrong password here and see what's happened here so you can see that it returns to us a unauthorized 401 error and if I correct the user which is one two three and send the post request it gives us an internal server also I go back to the we scored and see what is the error so it says that secret or private key must have the value so I go to the RF module here and here we have the secret inside the JWT module so it has a weird error we just have to put it inside the back text and then interpolate the process.env.jwt secret and if I save this and go back to insomnia and again send our login request again it gives us an internal server error so I go back to vs code it has a secret or private key mirror we have set the secret key option and release it from the EnV file so I go to the EnV file it has the same spelling go back to the auth module and here we register the JWT module and yeah here we have register the JWT Service as a provider so we'll remove this and as you can see the jdbt module and JWT service are from the same package and since we registered the JWT module inside the import section of the auth module we shouldn't include the JWT service inside the providers of the auth module so let's save this to see if it solves the error or not so if I click on the send and yeah it returns an object that contains the ID of the user the name of the user email and most importantly this is the access token of the user so now we can protect some of our API endpoints and require the user to have this access token inside the header of its request so if the user doesn't have the access token inside the header of its request or have a wrong access token we can verify the access token and then reject the request of the user and if the user has the correct access token inside each other request we can allow the user to call that API so up to this point of this video we have successfully implemented the local strategy of our passport authentication system which means that we can allow a user to login into our system with a username and password and now we can go ahead and implement the JWT strategy of our passport authentication which means that we can allow a user to call an API route if it has the access token inside the header of its request so again local strategy means that the user can log in into our system with a username and password but the JWT strategy means that the user can call an API if it has a correct access token inside the header of its request so with the JWT strategy we can authenticate a user with a access token so let's go ahead and implement the JWT strategy for our next JS application okay go back to the vs code and here inside these strategies directory I'm going to create another file called jwt-strategy .ts and then inside it we're going to export a class named JWT strategy and then extend it from the class that passport strategy function returns so it's a function that returns a class and inside this function we should pass the strategy that we want to use so here we want to use the strategy from the passport JWT but as you remember inside the local strategy we pass the strategy that comes from the passport Dash local so here in the JWT strategy we pass the strategy that comes from the passport jdbt so don't confuse these two strategy class they have the same name but come from different packages okay and as a second parameter of this passport strategy we can pass a name for our strategy which is optional so when we use the strategy from the passport JWT the default name for the strategy would be JWT but if we want to create a more than one strategy from this passport-jwt we should specify a different name for these two strategy and since we are going to create another strategy in refresh token strategy from this passport JWT strategy here I'm going to specify a name for this JWT strategy so I'm going to go ahead and specify the JWT for the name of this JWT strategy and then we're going to create the body of the class and inside it we're going to create our Constructor and in the Constructor we call the superclass and inserted we're going to pass an option object and the first property would be JWT from request and then set it to extract JWT and then call the function from off header as bear token so this extract datability comes from the passport JWT and then set the ignore expiration to false and then we should provide our JWT secret so I'm going to say secret or key and set it to process that EnV the JWT Secret so this is the same secret key that we have used in order to sign the JWT access tokens so with these three function first of all we specified that the access token is inside the authorization header of their incoming request and here we specify that if the access token has been expired then reject the request and as the third option we provide the same JWT secret that we have used to sign the JWT access tokens and after the Constructor function we're going to define a validate function so I'm going to say async validate which takes the payload which is type any and then just return an object with the user which is going to be payload that sub and also username which is going to be payload the username so what is this payload parameter it is the payload object that here we have used in order to sign the JWT token so after a request comes to our JWT protected API endpoint the JWT strategy first of all extract the access token from the header of that request and then decode the payload object from the access token with this secret key and then pass it to this validate function so we return the user which is the payload.sub because here we set this user object which has the name inside it into this sub-object of the payload and then the username is the payload.username so if I go back to the payload object you can see that it has a username which is the user.email and a sub-object which is our user object with just a name property so here inside the JWT strategy we do the reverse thing for the payload object we just extract the user from the panel desktop and the username from the payload.username so that's it for the JWT strategy and now we can go ahead and create our JWT guard so I go to the guard directory and create a file name jwt-off Dot curve.ts and inside we're going to export a class name JWT guard which extends the class that returns by the auth guard function which comes from the initiate slash password and then we specify the name of our strategy so it would be the JWT because in our jw3 strategy we set the name of JWT strategy to just JWT so I go back to the JWT guard and leave the body of the class just empty and then we just have to mark it with the injectable decorator that comes from the NHS slash common so that's it for our JWT guard and the last thing we should do is to go to the AFT module and inside the providers we add the JWT strategy and that's it and we can now go to our API route and decorate them with the JWT guard so for example if I go to the user module here inside the user controller I go to the this route which is slash user slash ID of the user and then slash comments so we can now decorate it with the JWT guard so I'm going to use the use guard decorator and inside it we're going to pass the JWT guard and that's it so now let me go to insomnia in order to test this API route and here I go to the user commands which inside it we have a get request to the slash user idl1 and then slash comment so if I click on this send we got an unauthorized error message and if I go back to the vs code and remove this JWT Guard from the slash ID slash comments of the user controller and now let's save this and go back to the insomnia now if I send this get request to the slash user slash ID slash comment we can see that this wrap Returns the response for us so now if I go back to the insomnia and then I'll come in the use guard and save this and then send the request again we got an unauthorized message again and that's because we have to have a access token inside the header of our request so first of all I'm going to log in here I'm going to log in again and this is the access token of the user I just copy that and then go to the user comment and inside the header of this request I'm going to specify a authorization and then the value of the authorization would be the bearer string which it has to be there and then a blank space and then we paste the access token that we've got from the login request so now if I click on the send it returns us the response from the API but if we tamper with the access token for example let's remove the last character of the authorization header and then click on the send you can see the we get an unauthorized message again and that's because our access token is no longer valid so if I fix this and again click on the send you can see the response is returned to the user and that's because now our access token is valid so in this way we can easily protect our API routes with the JWT guard so let me quickly recap what we have done in this section first of all we create the JWT strategy which inside it we have exported a class name JWT strategy and then it extends the return class from the password strategy and inside this passport strategy function we pass these strategy that comes from the passport JWT and then we set the name of the JWT for this JWT strategy and here we pass the option that says the access token is inside the authorization header of the request and then we set the ignore exploration to false and then we provide the same JWT secret key that we use to create our access token and then we create the evaluated function which decomposed the payload object and then we have created the JWT guard we just extend the off guard and then pass the string that specify the name of our strategy which is just JWT and that's it and as a last thing we go to the auth module and inside the providers we register our JWT strategy and that's it and now we can go ahead and go to our controllers and protect our API routes with JWT guard so in in this case every route with the JWT guard the Creator is protected and the incoming request to this API routes should have invalid access token inside the authorization header of the request so that's it we can easily protect our API routes with JWT Guard from passport awt and as a last section of this tutorial I'm going to create a refresh token strategy so what is the fresh token strategy if I go to the AFT module you can see that we configure the JWT module and in the signing option we set the expired time to one hour which is 3600 seconds so in the real world application we usually set the expiration time of the access token to just for five minutes and after the five minutes the access token is expired so when the user want to access a protected route after the five minutes each request will be rejected with unauthorized message because the access token is now expired so the user have to log in again and get a new access token in order to access the API so this is a really bad experience for the user so we have to have a mechanism to refresh token when the access token is expired so in order to do that we go to the off.service file and here inside the login function in addition to access token we provide a refresh token as well so I'm going to provide a refresh token here and set it to this that JWT service and call this sine function to create a new JWT and pass the payload and as a second option and as a second parameter we pass the option object and then we specify the expires in property and set it to for example seven days so the refresh token will be expired in seven days an access token will be expired in one hour so let me go to the auth module and set the default expression time to just one minute 60 seconds so let me go back to the login function again our access token will be expired within the default expiration time which is 60 seconds and the reverse token will be expired within the seven days and now we should create a API in the auth controller for refreshing the token so the user sends its refresh token inside the body of the request and get a new access token so as the name implies it refresh its token so before creating these API routes let me create the refresh token strategy and refresh talking guards so as before we go to the strategies directory and create a new file called refresh token.strategy.ts and this refresh token strategy would be almost the same as the JWT strategy so just copy the code inside the JWT strategy and go to the refresh token strategy file and paste them here so the first step is to rename the strategies so I want to say refresh JWT strategy and the strategy here would be the same as the JWT strategy but in order to distinguish between these two strategies JWT and refresh JWT strategy we should provide a different name for them so the JWT strategy the name was JWT but here inside your fresh JWT strategy we're gonna go ahead with the jwt-refresh so in this way we can distinguish between two strategies that are extended from passport JWT strategy and then inside the Constructor and the option object that is passed to the super function we set the JWT from realquest to extract JWT Dot from body field and then name of the field inside the body of the request that the refresh token should be exist so in this case we're going to pass the refresh so the refresh token inside the request that is coming to the refresh token API should have a body and inside the body of the request we should have a refresh property which contains our refresh token and then the rest of the refresh JWT strategy is the same as the JWT strategy so we save this and now we can go ahead and create our refresh jability guard so inside the guard directory I'm going to create a file name refresh Dash JWT dash off dot TS so the refresh guard is as the same as the JWT card so I go to the JWT guard and copy the code inside it and here I'm gonna paste it inside the refresh token auth card and just rename the name of the Guard to refresh JWT guard and then since here inside the refresh token strategy we pass the name of the refresh JWT strategy to JWT Dash refresh just copy the name here and here inside the refresh card we pass the JWT refresh as the name of our as the name of the refresh of guard so let's save this and go to the auth controller and create a refresh token API so here I'm going to create a post request and then set it to refresh so the route our API would be slash off then slash refresh then create an async function and we'll call it refresh token and the parameter of this refresh token would be the same as the login so here we extract the request with the at request equator from the initials and then here we'll return the this that up service the refresh token and then we pass the wreck dot user so obviously we haven't created the refresh token inside the off service so let's go to the off service and create a refresh token function so it would be almost the same as the login and let's copy that and paste it rename it to refresh token it takes the user as username create a payload object and then here instead of returning the user data access token refresh token which is return a object that only contains the new access token so let's save this and go back to our off controller and here decorate the refresh API with the use guards and then pass the refresh JWT card and as in last step we should register our refresh JWT strategy inside the providers of the app module so now we have the refresh API we have the slash off slash refresh API for refreshing our token so now let me go to insomnia to test the refresh token API and here we've seen the login request with this username and password and you can see now we have a refresh token as well as the access token so I copy the access token and go to the protected route which is the user comments and inside the header we paste our access token and if I click on that you can see that we have the response from this API so I'm going to pause the video and wait for 60 seconds and then send the request again okay I have waited for 60 seconds now and let's send the request again and you can see that we've got an unauthorized error message and that's because after 60 seconds the access token will be expired so we have to refresh our access token using this refresh token that we've got from the login API so I copy the refresh token and go to the slash off slash refresh API and inside the body of the request we set the refresh to the refresh token that we've got from the login API so if I click on the send you can see that we have a new access token here as a response of this request so I copy the new access token and go to the user comment go to the header and replace the axis talking with the new one and send the request and you can see now the response is returned to the user without any error so yeah that's it for the refresh token section and let me quickly recap what just we have done so I go back to the vs code step one we create a refresh token strategy and here inside the option of the strategy we said that we are going to expect the refresh token for the body field of the request and the name of the property inside the body that contains the refresh token is refresh and then we we find the refresh datability guard that extend the auth card with the name of JWT Dash refresh and this JWT Dash refresh comes from the refresh token strategy and here we specify the name of this strategy to the JWT Dash refresh and then we go to the auth module and register our refresh JB it is strategy and here we inside the auth service we have created a refresh token which create a payload from the user object and then return a new access token with the JWT service and return it to the controller and here inside the off controller we have created a refresh token API a post request and then Mark it with the use guards and then pass the refresh JWT guard so it expects the incoming request to this post refresh API to have a body inside it and inside the body it expect a refresh property which contains the refresh token so if the refresh token is valid it calls the off a service that refresh token and as I say just create a new access token for us and return it to the user and that's it for the refresh access token it is very simple with niches and password so yeah I think that's it enough for the authentication with necessing passport and in the next video in the initials playlist I'm gonna come up with a comprehensive tutorial for the type program that covers everything you need to know to master the type RM so stay tuned for my next video and if this video was useful for you please hit the like button because that will encourage me to move forward so stay tuned for my next video and have a nice time bye bye
Info
Channel: Sakura Dev
Views: 16,845
Rating: undefined out of 5
Keywords: nestjs authentication, nestjs authentication jwt, authentication, nestjs, nestjs jwt authentication, jwt authentication, nestjs tutorial, nest.js, nestjs passport, nestjs passport jwt, authentication in nextjs, nestjs auth, how to use jwt authentication in nestjs?, how to implement jwt authentication in nestjs, jwt authentication in nest js, nest authentication, nestjs jwt, nestjs authorization, nestjs authentication уроки, user authentication
Id: twaUdKr06kA
Channel Id: undefined
Length: 46min 37sec (2797 seconds)
Published: Sun Apr 16 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.