JWT Authentication | Node JS and Express tutorials for Beginners

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hello and welcome hi i'm dave this tutorial is part of a nodejs and express for beginners tutorial series i'll put a link to the full playlist in the description below today we will add protected routes to our express api by using jwts let's discuss the jwt strategy we're going to implement today so what are jwts what is the acronym jwt and abbreviation 4. well i'm very excited about the upcoming launch of the james webb telescope but in this case that is not the correct answer concerning our node and express rest api jwt is an abbreviation for json web tokens jwts can be considered to be a form of user identification that is issued after the initial user authentication takes place when a user completes their login process and they are authenticated our rest api will issue the client application an access token and a refresh token the access token is given a short time before it expires for example 5 to 15 minutes and the refresh token is given a longer duration before it expires possibly several hours a day or even days while no security measures are perfect we do want to consider the risks of cross-site scripting and cross site request forgery i will provide links about both in the description below our api will send and receive access tokens as json data to avoid the previously mentioned risks it is recommended for front-end client applications to only store access tokens in memory so they will be automatically lost when the app is closed they should not be stored in local storage or in a cookie essentially if you can store it somewhere with javascript a hacker can also retrieve it with javascript just keep access tokens in memory which you might also refer to as the current application state our api will issue refresh tokens in an http only cookie this type of cookie is not accessible with javascript refresh tokens do need to have an expiration which will then require users to log in again refresh tokens should not have the ability to issue new refresh tokens because that essentially grants indefinite access if a refresh token falls into the wrong hands so the overall access token process involves issuing an access token during user authorization the user's application can then access our rest api's protected routes with the access token until it expires our api will verify the access token with middleware every time the access token is used to make a request when the access token does expire the user's application will need to send their refresh token to our api's refresh endpoint to get a new access token of course the refresh token is also issued during user authorization our rest apis refresh endpoint will verify the token and cross-reference the refresh token in our database too storing a reference to the refresh token in the database will allow refresh tokens to be terminated early if the user decides to log out and again refresh tokens need to be allowed to expire so indefinite access cannot be gained we're going to start with the code repository from the last tutorial but if you don't have it you should be able to easily follow along without it or you can download or clone the starter source code from the link that i've provided in the description below let's get started today by installing the node packages that we're going to need so i'm going to press ctrl and the back tick you could also go to the terminal menu and open a new terminal window from there i'm going to type npm i and then we can add all of the packages that we need all on one line so the first one is dot env the next one is json web token no spaces there and then the last one is cookie dash parser and we'll press enter and all of those packages will install and then we'll check our package json just to make sure the dependencies have all been added and that was fairly quick let's go ahead and look at the package.json and we can see under our dependencies we've got the cookie parser we've got dot env and we've got the json web token package with that complete i'm going to close the terminal window and over in the file tree i'm going to create a new file at the root level and i'm going to name this dot env just like that and now we can put our environment variables in here i'm going to use all caps and type access underscore token underscore secret and set that to an equals and then we'll get the value in a second and then i'm just going to copy that down and change the word access to refresh because we're going to create an access token and a refresh token so let's save this much for now open the terminal window back up and now we can type node in the terminal to go into node and now we're running node at the command line interface node has a common core module called crypto so right here at the command line we can type require and now we can put crypto in here and from there we can add random bytes with camelcase with a capital b the number 64 and then dot 2 string and we'll say hex and this will give us a random crypto bytes string that we can use as our access token secret so i'll press enter and now i'm going to copy this and we don't need the quotes at all inside of our dot env now ctrl c to copy and i'll just paste this in here as our access token secret now i can press alt z in studio code to get that to wrap so it doesn't go beyond the edge of the screen so that is our full crypto line that we just created there now let's go ahead and create one more i can press the up arrow in the command line just to pull that command back up press enter and it generates another random crypto line here that we can copy and paste right into our dot env file and with that i'm going to press ctrl s to save and close the terminal actually i'm going to open the terminal back up real quick because we didn't exit node we press control c and then it says press control c again so we press it again and now we have exited node at the command line now i'll close the terminal window one other thing we want to do with the dot env file is make sure it has been added to our git ignore file you do not want to send your environment variable values that you're storing in the dot env file or you could just say you do not want to send your env file to github you want to keep this in your dev environment and then when you host somewhere whichever host you have they should have a way to put the environment variables into their hosting service then you can pull those out now we need to go to our controllers folder and open up our auth controller that we've created in the last tutorial and we left a note for ourselves that this is where we want to create the jwts on line 15. before we get started on line 15 let's go ahead and pull in everything we will require today so let's define jwt set that equal to require and then pull in our json web token package after that we need to go ahead and require dot env and then we need dot config after that and after that we need our fs promises because we have not integrated or any other database technology yet so we are still working with simple files and json values so we need this fs promises and we'll set that equal to the fs module and after that we need dot promises and then finally we need the path module we'll set that equal to path now let's scroll down so we have just a little more room to work on the screen and we're back here and now line 15 turned into line 20 where we're creating our jwts and let's define our access token we use camelcase with a capital t on token and we'll set this equal to jwt dot sign the first thing we need to pass into the jwt is a payload so what we're going to use is our username object you don't want to pass in anything like a password or anything that would otherwise hurt your security because this is available to all if they get a hold of your token so what we want to pass in is just the username i'm going to do this on a separate line and so we'll create this object with username and here above we had a found user and then we can say username now this is coming from up here where we found the user that was logging in after that the second thing we need to create our access token is our secret that we defined in the dot env file so we access this by process dot env dot access token underscore secret and then finally what we need is an options value here and we can say when this token expires and this is camelcase expires in and we're going to make this very short for this tutorial that will allow me to show the token expiring and see what happens but what you might want to do in production would be maybe 5 minutes or 15 minutes some small window of time but 30 seconds might be too short it is all a preference though and with that defined let's go ahead and highlight all of this and then i'll just press shift alt and the down arrow to copy it all down and we'll just make a few changes to go ahead and create our refresh token as well so i'm going to type refresh here instead of access we're once again going to pass in the username but then we need the refresh token secret now a refresh token needs to last much longer than the access token but you do want it to expire at some point and so i'm going to make this one day and i'm going to give a link to the package the json web token package on npm js and there you can see another link and more documentation on the different values you could put in here but one day is what we're going for and then we want it to expire and we want our users to have to log back in you could make an indefinite refresh token but that means if someone gets a hold of it and they're not the correct person they will always have access and you do not want that with both tokens created i'm going to scroll up for a little more room again and we want to save our refresh token in the database which will also allow us to create a logout route in the future that will allow us to invalidate the refresh token when a user logs out so let's start by doing that and once again we're just working with our json files for now and we haven't connected this to an actual database that we will do in future tutorials but of course that lets us modulize these tutorials and then we can attack say or go over to postgres or anything we want to in separate tutorials so for now just the json file and i'm going to define other users we had a found user so now we'll set other users equal to the users db dot users dot filter and now for each person that we have we're going to say person dot username not equal to and now let's have that not equal to i believe it was the user that we came in with the request right here however we also have our found user dot username and i believe i'd like to use that since we have found it so let's say found user dot username and now that creates an array of the other users that are not the username that is logged in and now let's create a current user we're going to set this current user equal to the found user and then we're also going to add in the refresh token that will be saved with this current user and now let's set our users once again and we can say users db dot set users and in this new array we'll go ahead and add the other users and then we'll add the current user that we just created i really don't know why i'm putting spaces there really don't usually do that in an array and okay let's go ahead and put the semicolon and let's write our new users file this would be await and then fs promises dot write file i'll go down to a separate line i'm going to scroll up once again just to put that in the middle say path dot join we'll pull in the directory name then we need to go up one directory and then we need to go into the model directory and then we need to go ahead and name this users.json as our users file is after that what we want to put in we need to json stringify and pass in usersdb dot users which will write our new users file and so i should have put a little comment here at the top this is saving refresh token with current user which again doing this will allow us to invalidate that refresh token as the current user logs out if they log out before their one day has expired so as a quick review we have created the jwts once we have authorized the login which was with bcrypt in the previous tutorial but now that we authorize the login we create the jwts we have a refresh token that's being saved into the online database and an access token and yet we still need to send both the refresh token and the access token to the user the easy part of this is to just remove what we were sending in our json and instead send the access token we can send that as json and on the front end the front end developer or as a full stack developer if you're developing the back end and the front end you really want to store this access token in memory it's not secure in local storage and any cookie that you can access with javascript could also be accessed so anything that really that javascript can access where you would store it it's not really that secure so if you store the access token in memory which has a very short life span we only gave it 30 seconds here but like i said maybe you'd give it 15 minutes by keeping that in memory you're not storing it anywhere vulnerable after that the refresh token well what we're going to do i've definitely seen tutorials that also just send it along in the json but that kind of creates a dilemma for the front end developer or as you develop the front end because you do need to store the refresh token we want to send it as a cookie and i know i said a cookie could be vulnerable to javascript but if we set the cookie as http only it is not available to javascript so that's what we want to do so let's say res.cookie and now here we can name the cookie i'll just name it jwt from there we want to pass in our refresh token and after that we want to give options and the first option i'll give a space here http only set that to true and after that we want to set a max age here we go and now i'm going to set this to 24 which would be 24 hours 60 times 60 times 1000 and this is in milliseconds here so what we're really getting is one day is that's what that is equal to as we set the max age of the cookie and i'll go ahead and cap that off here you could set it for longer as well now cookie is always sent with every request but the nice thing about an http only cookie is that it is not available to javascript and while it's not a hundred percent secure it's much more secure than storing your refresh token in local storage or in another cookie that is available to javascript so let's save this and now we know we are sending our refresh cookie that is http only to the user we're also sending the access token oh here we're sending our refresh token is what i meant to say in a cookie that is http only we're also sending the access token as json that the front end developer can grab and we're also storing this same refresh token in a database here that can be cross-referenced when it is sent back to create another access token with our auth controller complete let's now go look at the middleware folder and we need to create a new middleware file here and let's call this verify jwt dot js and we're going to need jwt and env once again in this file so i'm back in the auth controller just long enough to copy these two and then go back to the verify jwt js and i'll paste in our required packages right at the top after that i'm going to create verify jwt set this equal to a function that has a request response and next as middleware should and now let's define the auth header at the very top and this is going to be equal to request dot headers oh and then we need a bracket not a dot and then authorization and of course we need to check to see if that is actually received so now we can say if no auth header we're going to send a response which we need to return and then just send the status 401 which stands for unauthorized after that i'm going to go ahead and put a console log statement to just go ahead and log the auth header for when we test this we'll be able to see that in the console you'll see a line that looks like this and it will say bearer and there will be a space and then there will be the token after that so we can define our token now and we can set this equal to the auth header and then we can call split on that space that i just described and we'll put the space in here on the split and then we need the token so it wouldn't be in the zero position it's in the one position after that and now we can verify the token with jwt dot verify and here we'll pass in the token first after the token we'll pull back in our secret and this will be the access token secret because that's what we'll verify with this middleware and after the access token secret there will be a callback that gets an error and then we'll call this you could call it token if you want we'll call it decoded because it will have decoded information from the jwt and now we'll say if we have an error let's go ahead and return and send a status once again this status will be 403 forbidden because at this point we'll know we received a token but something about it wasn't right in other words it may have been tampered with and so this means we have a invalid token so we'll send a 403 instead of a 401 which means you are forbidden from accessing this and then we'll set the user equal to decoded dot username remember we passed in the username to the jwt so now it's been decoded and we can read that and then we'll call next from our middleware and that pretty much wraps up that whole middleware function right there except we need to remember to export it so we'll say module.exports set that equal to verify jwt and save with the middleware now complete we can add it to a route or routes that we want to protect so let's open up routes and api and go to our employees js file that has all of the employee routes in it and we need to import that middleware here so we'll say const verify jwt equals require and now we need to go up out of the api folder up out of the next folder the routes folder and then go to middleware and then choose verify jwt and once we have that we can just put it let's say in our git route if we only wanted it in the get route before we call the controller and so it will go through the middleware first and then go to the employees controller here so let's save this and now let's test this with thunder client so over here to the left i'll open up thunder client and we're going to need to log in first so i'll go to our collections and i have an auth collection that i created and i want to go to the auth route i'll click this and now i'm going to click over here again to hide the tree so we can see better and i'm also going to press control and backtick to open our terminal window we haven't started the server yet so that's something else we need so we need to type npm run dev to go ahead and start our server and it's running on port 3500 and so you can see the route we're going to go to is a post route it's localhost 3500 auth that we had previously set up to log in with the password so in the body we're sending wall 1 and password and the password that we had in there previously and this is in the users file that i have if you haven't done this you need to go ahead and either create this in the file or use the register route that we previously created and create a new user and then this will work but we're right now we're going to log in with user walt 1 and this password using this route so i'll go ahead and send and you can see over here on the right the response we get is a 200 and we get this access token this access token will only be good for 30 seconds though so let's see if i'm fast enough to come back here to our collections open the employees api and now let's look at this and i need to go ahead and in auth i need to send a new access token now we can send and we got our employees back but this will expire and notice down here we also got the console log statement i put in here's bearer and then the space and then the token so now if i send this again the token should have expired and now we get the 403 forbidden because the access token that we sent was only good for 30 seconds now let's look at the employees.js file again and i will go ahead and click the file tree so we can see our files also we're only applying this verify jwt middleware to the git route right now and this is a good way to do this if you have select routes that you want to protect or verify but not all of them however if you know you want to protect all of the routes in your api there's an easier way to do this so let's go ahead and remove this and we'll pull this out of here as well and i don't think we'll just retype it in the server file because that's where we're headed next so we've removed the verify jwt from the employees js file all together let's go to server js our main file and here we can just pull this middleware in so i'm going to do it right underneath the error handler that we had middleware for so we'll say verify jwt set this equal to require and here we want to go into we don't need to go up at all actually we just want to go into dot slash middleware slash verify jwt and now that we have that we can use this just like we've used other middleware in our file but we probably don't want to use this verified jwt middleware for all the routes probably not the root route that we have here definitely not to register a new user or we'd never be able to register in the first place and not even to auth because they have to visit auth first to get the token but we do want to put it before the employees route so i'll put an extra line there and then right here we'll say use verify jwt and if you remember this works like a waterfall so in this order everything after this line will use the verified jwt middleware so any route we do not want to have verified with a jwt we need to have above this line right here so let's go ahead and save this once again and now we can go back and let's log in again and get another well we close up the api there there we go here's our offline let's log in and get another 30 second access token here we are okay now let's go back to the employees and once again we can just use the get route before it was forbidden because it expired but now let's go to the auth tab here in thunder client select all delete that paste in the new token and submit and we've got our employees list once again but if i continue to submit it will expire as soon as the 30 seconds is up and there is our 403 and just to show that this is on all routes now let's go back to our employees api to the post route for posting an employee here in the body we've got john doe so that looks like we could go ahead and post to the employees for john doe let's see if we can send this and we get unauthorized so our verify jwt middleware is working on all routes okay let's go back to the file tree we can close the terminal once again we can close out of thunderclient for now and let's close up the middleware what we do want is to go back to the controllers and we're going to create a new controller here called refresh token controller.js because we're going to have a refresh token route and before we get started on our refresh token controller because we're going to need it let's go back to the server.js quickly and at the top of the server.js we pulled in the verified jwt we also need to go ahead and define cookie parser the other package that we had required at the beginning of the tutorial and let's require cookie dash parser there we go but we'll define it with cookie parser capital p camel case right here so i can go ahead and copy that now much like where we used the express.json and express.url encoded that we use for form data and of course express.json is for json data we just want to add middleware or cookies right here so we'll say app.use and now we'll pass in cookie parser and we want to call that into action right there and save our server.js file now we're ready to go right back to that refresh token controller and we'll begin by copying the auth controller ctrl c i'll just copy everything and paste it in but we will make some modifications so we need the user's db we will not need bcrypt because we are not doing user password authentication there we do need jwt and dot env but we won't need fs promises or the path in this either so we can remove those dependencies now instead of handle login let's call this handle refresh token and this does not need to be async so we'll just have the request and response here after that we won't be looking for a password but we will be looking for a cookie so let's say const cookies and set this equal to request dot cookies and so we will have a similar if statement here at the beginning but we'll be checking for a couple of things one is to make sure that we have cookies but now let's use optional chaining with a question mark and a dot the optional chaining operator and put jwt after it so we're checking to see if we have cookies and then if we do have the cookies we're also checking to see if there is a jwt property and this is saying of course if these do not exist then we're going to return something here and we're going to return a 401 and we do not need a json message after that so i'll just eliminate that portion of it and save this it looks like i may need to go ahead and press alt z to wrap any lines that exceed the edge of the screen so there we've got a 401 if the cookies do not exist and maybe we have cookies but no jwt either way that gets a 401 which is unauthorized now let's go ahead after we've confirmed that at least and let's log to the console cookies.jwt so when we run this you'll be able to see what values we get from that and likewise let's go ahead and define the refresh token now that we've received now that we know it exists within the cookie and we'll set that equal to cookies.jwt and once again we do want to find a user but now we're receiving a refresh token and not a username or password for this so we'll say person and there is a refresh token that should be saved with each user if they have created one and so here we'll just match that to the refresh token that we have now defined here so this would be our found user then if that user exists and once again we can say if we do not find a user let's now send the status forbidden here and i'll just highlight that okay we're not evaluating a password here we are evaluating a jwt though so these lines will change as well so we can get rid of the const match line and instead well we can even get rid of the if match here as well and instead of that we'll type jwt dot verify and now we'll pass in the refresh token that was received now we'll say process dot env dot refresh token secret and then we'll have an anonymous function that once again has error and decoded its callback function and before i type the rest i think i'm just going to get rid of this because it doesn't need to be there at this point either so let's just go ahead and clear it out now and with that cleared out we can finish our function here for the token verification and if we do not have a valid token we can say if we have an error or we can also check the found user dot username because we did have the username encoded in the token so if it's not equal to the decoded dot username in other words maybe it was tampered with again then we can return a response with a send status and say 403 once again otherwise everything is good and we're ready to create a new access token to send because the refresh token has verified so we'll set this access token equal to jwt dot sign and then inside of the access token will once again have a username and this username will be the decoded.username because it should be the same username that was verified before and after that we can say process dot env dot access token secret if we can find that access token secret there we go and now we need to put an expires in once again let's put expires in and let's set this to 30 seconds as well however remember you might want to set this longer in your production app this is just for the demonstration of this tutorial so i can show it expire and then of course after we've created this access token we need to go ahead and send the access token so we'll send this json down and it'll say access token and once we've created that much all we need to do is export it so now instead of handle login we once again have handle i believe it was refresh token yep [Music] and we should be able to save that and i don't know why i put a semicolon there it's not really needed so once we have saved that we should be good to go with our refresh token controller and we can create the refresh token route okay in our routes file now we can open that up and we can look at our auth route i'll just highlight all and copy and we'll create a new route called refresh dot js i'll go ahead and paste that in but instead of the auth controller we need the refresh token controller so spell all of that out and instead of handle login we need handle refresh token and before we're finished with our refresh route let's change the http method from post to git as well so this is now a get route for refresh okay now we need to insert this route into the server along with the other routes so we'll go to the server.js file and you can see we've got root register auth and of course we want this to also be before we verify the jwt because the refresh route actually issues a new access token and that's what verified jwt verifies so what we want to do now is just copy a line down i pressed shift alt and the down arrow in windows to do that and i'm going to change off to refresh and now the refresh endpoint will receive the cookie that has the refresh token and then that will issue a new access token once the access token has expired so we'll save this and we should be ready to try it out so i need to open up the terminal window again and we can see our server is running on port 3500 now let's open up thunder client and we're ready to check out the refresh route but first we need to go to the auth route and here it looks like the auth path i'll hide the tree over there and so now we're going to localhost 3500 auth we're once again going to authorize walt here with his password so let's send this and we got a new access token but what we also get from our auth route is a cookie and this cookie has a refresh token and here's the jwt name for the cookie and here's the refresh token now a cookie is sent every time we don't need to paste it in in an auth area like we did with our access token the jwt cookie is sent every time we make a request to the domain that it's associated with so we'll go back over here to thunder client we'll come down to our refresh route and i'll hide that tree now we're going to local host 3500 refresh and you can see we don't need to post anything in the body we don't need to post anything in the auth because we have the cookie that we're going to send so let's send this cookie and now we got a new access token and you can see we also logged our information as we set it up in our path to log the refresh token that we received from the cookie down here so we've got a new access token and our refresh token is used to do that so now every time we hit this refresh route and we send our cookie with the refresh token we should get a new access token and you can see every time we're getting a different access token over there so that is what refreshes our access and that's why it's called a refresh token and so now we have a new limited time access token to use again in production you might want to set it to 5 minutes or 15 minutes instead of 30 seconds or something like that but then our refresh token has the longer duration that we store in an http only cookie and that's because we don't want it to be available via javascript so it increases our security nothing's 100 perfect but it's the best way to go i believe for that so we're sending the http only cookie that has the refresh token and that issues us the new access token now that we've finished testing the refresh route one extra measure of security or one extra step we can take is to offer a log out route and with the log out route we could actually then delete the refresh token and not let it last for the full duration and that just gives our users the opportunity to log out and of course delete any existing tokens and of course the access token should also be erased on the front end when the login or log out link or button is clicked as well of course we're working on the back end so we won't be doing that today but let's go ahead and add this new controller for the log out so we'll have logout controller dot js and now that we have that let's go ahead and copy our refresh token controller and we will just make some modifications to handle the logout because we need the same requirements at the top we've pulled in the users so we can check our database we've got the jwt requirement and we've also got dot env i'm going to close the terminal window and now i said we had the same requirements we don't quite have the same requirements i'm sorry we don't need the jwt or the env what we do need is the fs promises that goes with accessing our database because we're just using the json file so we'll require fs dot promises and we once again need path so we'll require the path and again these are only to access the current json file we're using for our users database this is a mock database this will be replaced of course with or postgres or whichever database technology we work on in a tutorial in the future so we've got this down for the requirements and let's move forward with the log out so instead of handle refresh token now we're going to handle the logout and we'll have a request and response and then let's just add a note here for the front end if you're doing full stack development like on client also delete the access token we can't do that here on the back end you need to do that in the memory of the client application just zero it out or set it to blank or whatever when that logout button is clicked what we can do though is take care of the refresh token so here once again we need to get the cookies as they come in now let's erase our logs here we were doing for the cookies and the cookies jwt before if you wanted to see those in the console and we'll once again verify that we have got cookies and then that we also have a jwt in the cookies and if we don't well that's okay because we were just going to erase it anyway so let's send a status 204 that means it's successful and there's essentially no content to send back that's what that status is so you've had a successful request and we're not sending any content and this needs to be send status instead of just status there we go response.send status got that now let's go ahead and define our refresh token and we'll do that in the same way setting it equal to cookies.jwt now let's see if we have that refresh token in the database so that's what we're checking here is refresh token and db so once again we try to find a user that has this token so setting this equal to the refresh token just as we did in the previous refresh token controller is exactly what we need and if we don't have a found user at this point we can go ahead and clear the cookie so we're going to do something just a little different here and it won't be forbidden either so we'll get rid of that and let's go ahead and look at how we clear the cookie first so if we don't have a found user but we did have a cookie to get to this point we can just go ahead and erase the cookie that was sent and that's going to be with response dot clear cookie and then inside there we'll look for the jwt cookie and then you have to pass in the same options that it was set with so once again we'll say http only set that to true and that should be all we need to do there except for sending the proper status so once again we're going to return and send the status not a 403 but of 204 which once again means this was successful but no content okay i'm going to scroll up just a little bit and now we can pretty much erase everything here and we're going to create some new content below because if we've reached this point that means we did find the same refresh token in the database so now we need to delete the refresh token in the database right here and we're using a file system of course for that instead of or postgres at this point but we will change that in the future right now let's define other users which would be all of the other users that are not the user that we found and set that equal to users db dot users dot filter and we'll just filter this out we'll pass in a person and now the person dot refresh token is not equal to our found user dot refresh token as well there we go okay so i'm going to press alt z to wrap that line of code so we can see all of it and that's all the other users so now our current user [Music] is going to be equal to our found user and then we're going to set the refresh token to blank so we'll leave the refresh token property but now we're just erasing it from the user and now we can update our users db with our set users and we'll go ahead and pass in our other users and then we'll pass in our found user oh and i'm sorry that's not found user that should be the current user that we just defined there we go so found user was before we erased the fresh token now the current user has the updated refresh token that is zeroed out or blank if you will now let's just write this to the file so we'll await fs promises dot write file and now on a separate line here i'm going to say path dot join pass in the directory name after that we'll need to come up one folder and then we'll say in the model folder and then we'll name the users.json file okay then we need to go ahead and use json.stringify and write in the usersdb.users and that should update our users file and so after that we need to go ahead and delete the cookie which we saw how to do before as well so we use clear cookie and we reference a jwt and we need to pass in the same options as well http only set to true now i will add in production both when we send the cookie and when we delete the cookie you also want to add the flag secure true and that will make it only serve so it only serves on https we're just using a dev server that uses http but you want a secure connection with https so we don't add this in development but we would in production the option of secure and set that to true okay and after that we want to send our status again which once again is a 204 all as well but we have no content to send back and after that we need to change our export from handle refresh token to handle logout and save okay with the controller complete let's create our route file and we can just go here to the refresh file we created select all and copy and now i'm going to create a new file in the routes called logout.js and now i'll just paste everything in from the refresh route and we'll change that so we need express we need the router but instead of refresh token controller we'll select all three of those with control d and i'll just type log out and this will be a get route again and the export to router is correct but we do not have handle refresh token here we also have handle logout as the function for the controller and with that complete now we can go to the server and add that route as well we won't need to verify jwt to log out so i will just once again shift alt the down arrow to copy a line down and i'll change refresh to log out and save now let's open a terminal window again oh and we've got an error so let's see what our error is here in node a weight is only valid in an async function ah we did not do that in our controller let's go back to the log out controller and we used a weight when we used fs promises so let's make the handle log out an async function and save and let's see if node restarts and yes the server is running on 3500 all looks good there so now we can go to thunderclient and we'll hit our auth route to make sure everything is logged in we're going to log in our user walt one and we've got an access token and we've got a cookie so now let's go back to thunder client and i have a log out route that is a get route as well so we have get localhost 3500 log out you don't need to pass anything in the body or the auth when we log out but let's go ahead and do that and we hit log out and everything seems to be fine we can see our cookie has now been erased so now if we go to any of the other routes like refresh that would use our refresh token cookie we don't have a cookie to refresh with so now let's try localhost 3500 refresh and it's a get route and see what we get well we can see in the console we logged or attempted to log a cookie but it didn't exist here and we're not getting a response so let's look at that i can cancel this here in thunder client let's go ahead and look at our refresh controller and see what's going on there so refresh token controller and here is where we're logging the cookies we can get rid of these lines actually now so we don't need those but let's see if we can figure out what is going on and yes here's the error i said response.status401 it needs to be response dot send status 401 just like we had down here with send status 403 so if i've typo to any of those others throughout this code it looks like i had send status everywhere else but just in case you see that to actually send the status it needs to be send status instead of just status status is chainable if we're sending a response after that but now this should work so let's once again go back to thunderclient and we'll hit our refresh token route although we don't have a cookie and we'll see what happens ah we immediately got our 401 unauthorized because now it sends the status so that's correct let's go back and log in again with our auth route localhost 3500 auth send that we have an access token we have a cookie and everything seems good so all routes are working as expected okay i thought i was at the end of the tutorial but after playing around with some front end code there were a few things i thought i needed to go ahead and clear up or include one is here this is front end code by the way this is not what we were working on in express if you use fetch to access what we had set up say our auth route well you're going to need to include a credentials option again on the front end to have fetch send the cookie now if you use axios i believe there is a with credentials flag that needs to be set as well and we could do that in a future tutorial but right now just looking at credentials for use with fetch so you have to set that to include but that sets off a chain of events so even though this is required here to send the cookie then what happens is i'll pull up chrome here we get a course error and you will be blocked by cores because the value of access control allow credentials in the header of the response is blank and it needs to be set to true so cores will block this if you don't have that set before you reach the course check now what is happening is a pre-flight options check it's an options http method request but then you also need to have the same access control allow credentials set to true when you do send the cookie back as well because that's what's expected with fetch so there's a way to fix that of course and now let's look at some of our back end code and let's start in the config folder and i went to course options first and we did have what was called a white list in here which that's traditionally what it's called and i've seen that in articles as well i don't like the name so much either just maybe in modern day it sounds a little racist or something so we've switched that to allowed origins which is what it is it's a list of allowed origins and i put it in its own file because we're going to use it in middleware also but i only want to update it in one place so we have our allowed origins formerly called the white list in the tutorial and we're exporting allowed origins so we import that into our cores options and use it here but then we also create middleware called credentials and now this credentials middleware of course has a request response and next and we import allowed origins here also all we're really doing is to say if the origin that is sending the request is in our allowed origins list so it's just a little bit of extra security if that is the case go ahead and set this header on the response because that's what cores is looking for access control allow credentials and we set that to true so now that we have the middleware created we go to the server file and we pull that middleware in and then you want to use the middleware we're using credentials right here and of course i'm importing it right up here above you want to use that before cores because of course sees that that response header is not set it throws that error so that will fix that issue and i would hope that would be the end of the issues but no there was one other issue and let's take a look at what that was i'm going to open chrome again and i had to do a screen capture now i was in the dev tools in the network tab and i was looking at the auth request and then i could pull up the cookie and then there was this little triangle and the reason i had to do this screen capture is because i had to mouse over the triangle for this message to pop up and it's very small print i'm zoomed in quite a bit already just to see this and it said the set cookie header didn't specify a same site attribute so that defaulted to same site equals lacks and then it was blocked because it came from a cross site response which means our front end application was not on the same domain as our backend api and that's often the case so there's nothing wrong with that it's just that's why they blocked it says the set cookie had to have been set with same site equals none to enable cross site usage so that tells us something else another option we need to go and put in our set cookie response so let's look back at the back end code here and then where did we set the cookies well let's look at the controllers that's where the cookies were being set and i believe the auth controller is what sets the cookie specifically and so not only do we have http only true but then we went ahead and set same site to none as they request here and then after you do that they give you another message in the same spot and that says secure must be set to true now previously i didn't have secure set to true there because i thought you could only use it with https even during development but no it's working in the dev server even though we're just using http then after that i went ahead i've got the code wrapping by the way because down here on the next line you still have the max age option now when you delete a cookie you need to set the same options however and i'll put a link to the documentation in the description below however max age actually does not need to be set or in there when you delete the cookie it's one of only a couple like the expiration and max age are the only two options that don't need to be identical when you delete the cookie so when we go to the log out controller and we have our res.clear cookie we need to have http only same site and secure all set as before but max age does not need to be in here and we've got that in here a couple of times in the log out controller as well so we did make those changes but after you do that everything should work as intended so it's just a couple of things i discovered as i was working with this front end code and of course it is good to test it out with actual code and a browser besides using an extension like thunder client because thunder client showed everything was working as we expected it to but of course we ran into a few issues with chrome and now i've walked you through how to fix those as well give this video a like if it helped you get started with the express framework for node.js and thank you for watching and subscribing you're helping my channel grow have a great day and let's write more code together very soon
Info
Channel: Dave Gray
Views: 1,202
Rating: undefined out of 5
Keywords: jwt authentication node js express, jwt, jwt tokens, authentication jwt, jwt authentication node js express example, jwt authentication node js express exemple, json web tokens, json web token, tokens, token, token authentication, jwt express, node jwt, jwt node, node.js jwt, jwt node.js, nodejs jwt, jwt nodejs, node js jwt, jwt node js, verify jwt, express, authentication jwt node js, jwt tokens explained, jwt tokens for api security, jwt tokens tutorial, jwt authentication
Id: favjC6EKFgw
Channel Id: undefined
Length: 60min 3sec (3603 seconds)
Published: Tue Oct 05 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.