JWT Authentication using Node, Express & Postgres

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so for this video you're going to need the following software installed you're going to need visual studio code so go to code.visualstudio.com and download visual studio code for your os you're going to need node so go to nodejs.org and download node you're going to need version 14 or greater and you're going to need postgres so go to postgresql.org and download and install postgres for your relevant os okay at some point you're probably gonna want to add login functionality to your website now the kind of preferred way to do this nowadays if you just want to add a standard email password or username password login is to use something called json web tokens or jwts now there's a really good article by hazora so if you go to this web site here this has a very in-depth article all about json web tokens why you should hold the first access token in memory but then have a refresh token that you hold in a cookie but it's a special type of cookie a http only cookie and to do the sort of uh tldr summation of this the modern way of doing logins is to use json web tokens you should send two json web tokens back to the client an access token which is going to be fairly short-lived maybe 15 minutes and a refresh token which can be a few days it's quite a good user experience because you don't have to keep asking the user for their email and password every time they try and get into your site it will remember the login for a few days so it's a good user experience but of course it there's a little bit of a security concern there so you have to be a bit careful and so that's why we're using these http only cookies to hold that refresh token because they cannot be accessed by client-side javascript so they're secure that's about it really i don't want to get it too involved this is a whole massive article on this here um but i'm just going to go through actually how you implement this process from scratch using node and express and let me just show you the finished api working so don't really consider this as a final login screen this is just to show you how you would access the authentication api from your front end obviously there's a million on one ways you could create a front end you could use react views felt angular i've just done a very basic vanilla javascript example code really so it should give you pretty well everything you need to implement this in whatever front end you want to do so let's see this working so i know that i have a user that has an email of bob at email.com with a password of bob and i can hit login and we've logged in successfully it's actually taking this data from our json web token so we're passing back in our json web token our user id and our email and our user name and so one thing to understand about json web tokens is that they're totally readable on the client side uh so don't think that a json web token is secure in that you can't read them but their kind of superpower is that you can't change them or at least if you do change them and you send them to the server the server is going to know that you've changed that json web token so you can't mess with this id and pretend that a different id has a valid json web token that just won't work so this access token which is one of the json web tokens we send back is in memory so as soon as we do a refresh we are logged out and so that's not a great user experience but we that is why we have our refresh token so we can hit this refresh token button and this will log us back in without bob having to put his email and password back in again and of course you could do this automatically i've stuck it on a button but the idea if you go back to the asura website and scroll down a little bit this is the flow that they're suggesting so when you have a new session you're going to try and silently do a refresh so you would essentially do the code that's underneath this refresh token button and if it fails then the user will have to log in but otherwise it's all good so bob is logged in so he can get users ah but i have got my access token set to a very short time just like 40 seconds so as you saw there we tried to get users but our json web token our access token had expired so we're going to have to click on refresh again and then we should have 40 seconds to be able to get our users there you go and if i waited 40 seconds which i can't be bothered to do but you know eventually this will run out our refresh token is in that http only cookie so the good thing about that is we can if i right click here i can clone the tab so this is a different tab from this one and i can still click refresh and it will log me in so that's a good user experience and works quite nicely now we also have this delete token button here because this refresh token you could have it set to like two weeks or something like that but you might want to give the ability for the user to log out and so what you can do is actually delete the http only cookie and that will essentially log the user out so if we do that then our refresh token won't work anymore and obviously i'll get users won't work anymore and we will have to log back in again and we could actually log in now as a different user so i've got fred in here and he can log in with a password of fred login and now we're logged in as fred and again fred has the ability to get all users which is probably in reality not what you want to do but for this example let's say that's fine and that is kind of the basics of an authentication system based around the principles outlined in this azura post so let's get started so the first thing you want to do is open visual studio code i'm going to presume you've got node and visual studio code installed so all i've done here is gone file open folder and i've just created myself a jwt tutorial folder select folder blank folder we're all good to go so if we open up our terminal and let me just show you that i'm using node version 14.16 you're going to want a fairly up-to-date version of node version 14 or greater should be fine because i'm going to be using es modules so the first thing we want to do is initialize our app by doing npm init dash y that'll create us a package.json file i'm just gonna keep the name jw tutorial it's fine and i'm going to install a whole raft dependencies here so npm install and we want be crypt cookie parser cause dot end express of course json web token and postgres so let's hit enter and go away and make a cup of tea and come back and then we actually want a dev dependency of nodemon which will just mean we don't have to keep stopping and starting our express service that'll do it for us we've got our dev dependency here of nodemon we should have all these in our dependencies and let's just do our scripts while we're in here so we want a dev script where we run nodemon like so now we'll actually run this index.js because that's set to our main and we want a start script so when we deploy it when we don't want to use nodemon we want and you actually want to use node of course so there you go there's our two scripts now we are using es modules in node so we need to specify type here and not common js we want module so ctrl s to save and i think we're good okay let's now work on our index.js so new file index.js so the first thing we want to do is import express and we're going to be sending back json so we want to import json as well and that's all from express uh we want to import cause just so we don't have any cause issues so import cause we want to import dot and because we want to set up some environmental variables and dot end will help us do that on our dev server i will have to do it manually on a deployment server or actually you can actually upload a nv file to your deployment server but i just tend to do them manually and then uh cookie passer because we are using cookies and then we don't get [Music] an underscore underscore dr name for um when we're using es modules in node so we need a little bit of help from path so we need dr name and join from path and you'll see why in a set and then we need um file u r u r l to path from l okay so that's our imports done for the moment and the first thing you should do is call dot end dot config and what that will do is look for a dot env file and pull in any environmental variables from that file so that needs to be done early on the second thing we should do is like like i say unfortunately underscore underscore dr name when you're using es modules for some reason you have to create this yourself so we can do that with file url to path and then we can get that from import.meta.url why do we need that well we're going to be serving up some static files and we need to specify where those static files are and you can't presume i guess that you're going to be running this application in the same folder as the sort of base folder of where you might be serving up your static files so if you go to the express documentation it actually explains it better than i did sorry about that uh here so this is why we need this underscore underscore dr name i think in most cases you can probably get away with just doing that but but i think this is just being super safe so let's create our express application so app is equal to express let's get our port so if you're deploying to somewhere like heroku uh that'll actually give you the port in an environmental variable called port uh but if that is not set then we'll just specify our own port i.e if we're on the dev server we'll specify port of 5000 uh causewise well so to make sure that our http only cookies get sent to our browser we seem to need to have to specify credentials equal to true and i'm going to give the ability to specify the url for our origin uh but if you don't specify the url for our origin i'm just going to say that um essentially anything can access our api now i want to use those cause options so app.use cause and send in calls options we also want to handle json so we send in the json middleware there and we also want to be able to handle cookies so we pass in the cookie parser middleware as well so that's all our middleware taken care of now we want to serve up that static kind of example login page that i showed you so let's do that and this is the line that i just showed you in the express documentation so that is essentially saying that uh we're gonna put static files in a folder called public okay so we have to start listening now so if we do app dot listen [Music] we need to specify our port and we can say something like uh using a backtick there server is listening on port okay so let's save that and what we want to do now is create ourselves a public folder new folder public and we'll just stick in a index.html file in here and let's just use emmet html colon5 hit enter to scaffold that out for us i'm just going to give it a title of jwd tutorial and let's do a header that says the same like so and now if we do npm run dev and to go to local host 5000 refresh kill that one uh yeah there you go so we're serving up our static html page using express so that's not super exciting but let's move on to our database so if we right click in here do new file and i'm going to create a database dot sql file and here i'm just going to type in the sql that we need to create our database so create database i'm going to call this jwt tutorial like so and then we want to create a table to hold all our users in so create table users and we want a user id and i want to use this uu id which is like a nice unique id and we can create that unique id by using uuid underscore generate and this underscore v4 method but we do need to use an extension so that we can use that method so we do create extension but only if it doesn't exist and this extension is called uu id dash o ssp so that's our user id taken care of we don't have to worry about that anymore that'll be automatic and we just want to make sure that our usernames are never null so text not null uh let's do use email again text not no and a user password again text not now and i'm just gonna put some handy bits of sql in here just in case you're not that familiar with sql so that would list all our users select all from users um you can insert into the users table by doing insert into users then in brackets you have to specify the fields you want to insert so say we want to put in a user name email and password we have to specify those and then we specify the values we want to put in so say we want to put bob into username let's say bob at email.com into user underscore email and password bob like so of course we'd never hold an actual user password explicitly like this uh we're going to be using bcrypt but just just to show you how you can use insert yeah um right and we can put comments into this file by double dashes and i just want to show that we can log into our postgres database by doing psql dash u postgres and this is actually our username and then it will ask you for your password and we can connect to a specific data by base by doing backslash c and what's our database name it's jwt tutorial so that would connect to our jwt tutorial database um that's another handy one uh listing our tables so that would be backslash dt like so and if you want to do this all on heroku you can do that command and that will connect you to heroku um and actually heroku gives you a database automatically so you never have to do the create database on heroku but you will need to do the create table okay so let's create this database now in postgres so if we open another terminal and we do p sql dash u postgres and you will need to type in the username that you're using for your local postgres database and you will need to type in your password here mine's just postgresql now we're in the postgres console so we can essentially create our database now so if i copy this line here copy come down here paste that in right click and then hit enter and if it says create database there then it means it's done that so now we want to connect to our database so we do this line here copy right click so now we are connected to our jwt tutorial database and now we want to create this table so let's select that copy right click enter and that's because i have not done this line up here so like i say we need this extension if we want to use this uuid so let's copy paste that in here and we've created that extension so we should be able to do this now yeah create table means that it's created that table and we can double check with a backslash dt and they see that we have a users table let's insert a dummy user so we can copy like so hit enter and that means that it's inserted one row you should be able to now do dt and that will say we've got one row in the users table and we can actually do this line here copy paste and as you can see we have one user in our postgres database and this is this uuid i was talking about quite a nice uh unique id there okay i'm going to control sync with out there i'm pretty well done with our database now so let's start accessing this database in our code so if we right click and do new file and we're going to call this db.js so we need to import pg from pg we need to pull out pull actually capital p pool from pg and let me just set up the local pool config which you've pretty well seen that our local database has following settings we have a username of postgres a password of postgres we're on localhost the default port that postgres uses is five four three two and our database name was jwt tutorial i think okay so that's our local database but we only want to use that if we're in dev mode so this will check for an environmental variable called database underscore url and if it exists then we're going to say that our connection string is equal to it but we want to set ssl reject on authorized equal to false otherwise we are going to use our local pool config let's just format all that a little bit nicer so let's put that there there like that so it's a bit easier to read and then we create a new pool using that all config and we want to export our pool so that's all the sort of boilerplate stuff that we need to connect to our postgres database uh dependent on whether it's our local postgres database here or the one on say heroku which will be this one here so that's that done you can close that save that close that so let's do something simple just to test access to our database so if we create a new folder and we'll call this folder roots and in this folder let's create a new file and we're going to call this users dash roots dot js so we need to import express from express and we want to import our postgres pool from our db.js and let's create ourselves a router from express dot rooter and then how this works is we do router dot get and we're saying this is going to handle the root of users and we want an async arrow function and let's put this inside a try catch and we're going to say users is equal to a weight and then we do pull.query and then we send it an sql query simple as that so select all from users and then we want to pass this back as json and i'm going to have a object that has a property of users where i'm going to pass back all our rows and if there's any errors can send back a status code of 500 but i also want to send back some json with and error property of error dot message right so and at the bottom here i need to export our router okay so that's about the simplest router you've probably ever seen which is good and how do we use that router well we come back into index.js and at the top here we have to import it obviously so we do import router from roots user's roots dot js so it's imported the router and then we can probably most sensible to do it after here we can do app.use and then we kind of attach that router to an endpoint so we sort of say api slash users is going to use users router so we would have to hit api users to hit this user's router and then this kind of gets tagged on the end so we could kind of extend the route by adding more here but this this is handling the route of the router which is here and it should hopefully pass back our users let's save that let's make sure that's saved and see if that works yeah the first time which hardly ever happens so uh that's great so we've got our json like i say we're passing back a json object and it's got a property of users and an array of all our users and we've only got the one at the moment um yeah for giggles let's stick another one in so how would we do that well we can just come back here database sql and let's um add in thread fred thread so let's copy that copy and i guess i should have kept our connection to um our database open but never mind let's go in here connect to our jwt tutorial database tube real there you go huh too many t's there you go and then we just paste in that we now have fred in there let's come back here do a refresh and now we can see we've got fred in there as well so that's definitely working which is good so we're hitting our database on this particular endpoint here specified by our root but we really want to be able to create users um and not do it where we're sticking the password in like this uh we need to um encrypt these passwords so let's do that next so if we come back to users roots let's import decrypt from bcrypt and so if we come down underneath here and let's do router but if we're adding stuff we need to do a post request now and we'll still use the route there and we still need an asynchronous arrow function and we will use a try catch as well and so what we want to do is we want to create a hashed password and so we can use bcrypt to do this it has a handy method called hash and we just pull the password out of the body of the post request and we can specify 10 rounds which should give us a nicely hashed password so i guess you might be asking what a hashed password is and it's considered to be the way you should be holding passwords in a database you should presume that someone is going to hack your website and get access to your database and that's kind of worst case scenario but if that happens then they shouldn't be able to get into your users table and see all your users passwords and so what you do is you never store the users passwords you store a hashed version of their password and hashing a password is like a one-way trip you hash that password and it's pretty well impossible to go from a hash password back to the original password when a user is trying to log in you can compare that hash password to their password and you can see if their password is correct compared to that to their hashed password and bcrip does all the hard work for you you should um do things like salt the password um it's all a little bit involved but so i won't go into it really but um i can put some links in the descriptions if you're interested but basically bcrypt looks after all that for you and all you need to do is bcrypt.hash the password and you've got a nice secure password in your database um which really is even more secure than what you find in wordpress i don't think wordpress even salts their passwords so um they're not that secure so this is a super secure method of holding passwords right so we want to create a new user we do a weight pull.query we want to do insert into users user underscore name user underscore email user underscore password values and do dollar one comma dollar two comma dollar three returning everything and what does that dollar 1.2.3 mean well dollar one is the first one in this array which is body dot name the second one which is body dot email and the third one which is our hashed password that we just created just reformat it a bit so it's a little bit clearer so what's going on here well if you remember rightly when we inserted we had these values here that we inserted bob goes in here his email goes in here password goes in here so if we come back to this this goes in here which then goes in here this goes in here which then would go in here and this goes in dollar three which goes in here so that's how that works so basically these values get pushed into this this and this and the returning just means that once the inserts done we're actually going to get that record back which is kind of nice and so for the moment what we'll actually do is pass back that created record so we can do res.json so we just passed back an object with a property of users and we want that new user new user dot rows and there should be just one so that'll be that zero and if we get an error we want to do exactly the same as we're doing up here so let's just copy that okay so we need to do a post request and i could use something like postman to do the post request but there's actually quite a neat uh little extension if you go into your extensions this box here and search for rest and there's an extension called rest client and so if you install this extension then what you can do is you can create a new file and let's call it requests dot rest like so and you can do post http colon forward slashes local host 5000 i'm hitting the users api we need to specify a content type of application json you need to uh put a space in here and then we can specify the body that we want to pass and let's specify a name of bob and email of bob at email.com and a password of bob now before we send that request because i think that would fail let me just double check we haven't specified unique under username or email but i would say we probably want our emails to be unique so let's just put that in there like so so we can actually drop our original table or delete our table by doing drop table users like so i need to put a semicolon on the end if you forget just put a semicolon then hit enter and that works so we shouldn't have any tables now and then if i copy that copy paste we've created our table now and this time we have the specification that all our emails need to be unique which is definitely safer so now if we go to our requests.rest and we do a send request we now as you can see it's passing back because we told it to pass back here our new user that's just added bob bobber email and as you can see we know his user password was bob but it's definitely not saving bob it's saving a hashed version okay so let's close all this now and let's work on our authentication so let's right click our routes folder and do a new file and we're going to call this auth dash roots dot js and in fact we probably need all these imports that we need for users so let's just copy those come in here and paste those in but we also want to handle [Music] json web tokens in here so we need to import our json web token module and we're also going to import a little helper that i'm going to create called jwt tokens and let's put that in utils jwt dash helpers dot js let's comment that out for the moment though and let's just create our router and let's down here just export default router so don't forget to do that and what do we want to do we want to handle our login so let's do router dot post and that's going to be at the login endpoint and again a good old try catch to log in we're going to have to specify an email and a password so we are going to pass those through in our body so we can pull them out of our body like so and then we want to look up in our database and see if there is a user that has that specified email so we can do a select all from users where user underscore email is equal to dollar one and we send in our email simple as that so if our users dot rows dot length is equal to zero then that means we didn't find a user with that particular email address in our database so we'll send back a 401 and pass back a json object that says error and inside error we'll just say email is in correct so let's save that let's hook this up so we can test it early so if we go back to index.js and we can go up here let's copy that line but this is the auth router importing from off routes and come down here and we'll put this under api auth and this is our fourth router so again how it works is we would hit api auth and then it we look in here and we're going to add login on the end so it's api auth login to get to this route here so let's set up the login request here so we need to put in hashes to start another post request and this time this is like that but it is auth slash login but we just need to send it email and the correct password but so far we've only done when the email is incorrect so let's just test that so if i just type in bob1 let's do a send request and there you go we've got an error email is incorrect so this this case is working great now so now we need to do the password check so if we've got to here we know it's they found we found the email so now we need to check for a valid password so we do a weight bcrypt.com pair and we pass in the password that we're sending to the login api and we're comparing that to the hash password that we're holding that user bob in this case so this will compare b crypt will compare the password we're sending in which is bob to to the hashed version of bob that we're holding and if the two compare correctly then valid password is set to true otherwise false so i can do if not a valid password then we want to return a status of 401 and you can say error incorrect password and what we'll actually do if um for the moment just for test purposes if we get beyond that then we'll return a status of 200 and let's say we can just do success or valid json but that should work so if we come back to here this should still say email is incorrect if we put a correct email in and send that we get our success back if we put in the wrong password and we get incorrect password so perfect we are doing pretty well here okay so we don't want to pass success back here we want to send back a json web token and to get any further i want to create this helper so let's do that now let's create a new folder call it utils and inside utils i'm going to create a new file and i'm going to call this jwt dash helpers dot js and we want to import jwt from json web token and i'm going to create a function and i'm going to call it jwt tokens and really this is just to sort of standardize our tokens that we're sending back because json web tokens have a payload that you send back with them that has a little bit of data in and so it's quite nice to sort of specify in one place what that payload would look like uh so i am going to include in my payload the user id the username and the user email just super handy information to have on tap in that uh token okay so we are going to create a user that has all these in like so and from that user we are going to create two tokens which i'm sure i've mentioned that we have an access token and a refresh token so we have our short-lived access token and what we do is we sign the token and we sign it with a token secret so we pass in user and then we say process dot env dot access token secret which i will create in a second and then what you can do is you can specify when this token will expire so i can say expires in and i am going to say 20 seconds so very short lived in reality you probably want it to be um well it's up to you but 15 minutes something like that i think is fairly standard and let's copy that line and let's create a refresh token and we're going to use the refresh token secret and we're gonna say this expires in say five minutes and again in real life this is just for test purposes but in real life this would be probably more like uh 14 days something like that and then we can return an object that has both of these tokens in and then down here we want to export it well i'm gonna export jwt tokens so like that so before we forget we want to create these two environmental variables and then you must remember that if you deploy to somewhere like heroku or whatever server you want to deploy to you will need to set these up as environmental variables on the server you're deploying to now we haven't got a dot amv file so new file dot env take that copy paste take that copy paste and you want these to be a big long string essentially which you never ever ever tell anyone about uh you definitely want it more random than that you can use um various methods for creating these secrets uh and i'll probably put some some uh links in the uh description like i say these do need to be secrets it's kind of written in the name yeah so do not share them so you do not want this dot env going to get so you know new file dot get ignore dot env yeah uh do not push this up to github perhaps that's just defeating the object yeah um and actually modules i guess pretty good get ignore there right so let's save that and because we're using uh nv config these will get copied to uh local environment variables so that this line here will return this here so that's how that works so we have our little helper here which means that we can come back here and do the rest of this so we can do let tokens is equal to the function we've just created jwt tokens and we need to pass it in the user that we've just looked up like so so that will have passed us back our access token a refresh token for this specific user and so we can just do res json tokens and those are the two tokens that we will pass back on a successful login if you remember rightly we want one of those tokens the refresh token to be in a cookie so we can do res.cookie refresh token and pull out our refresh token out of our tokens like so and now we want to specify that this is a special http only cookie so set that to true and that should do the trick uh let's do our error handling here so res dot status 401 json error and pass it the message that's in the error okay let's see if that works so we come back to our requests again got an incorrect password here but if we do a correct password this is what we get so we now have a cookie which is our refresh token it's http only cookie so that's good and we also have our access token and our refresh token okay so at this point you might be thinking to yourself that's great so i've got this access token that's getting uh sent back to me when i log in but you know what do i do with it uh you know what uses it to me and that's exactly what we're going to sort out now so for subsequent requests where you need to be authenticated we are going to send along with the request this access token now there's a standardized way of doing this and say if we look at say the twitter api they use the authorization header and basically in the authorization header all you all you do is say bearer then space and then your token and that's a pretty standardized way of doing things and so we're gonna do exactly the same thing so again we need uh a function to do this and what we're gonna do is we're actually gonna use express's middleware solution and we can kind of stick this authentication middleware into certain routes that need to be authenticated so this will make sense when we actually do it so let's do it okay right click new folder and we're going to call this middleware and if we right click in that folder new file and we'll call this authorize dot js and let's close this like so and we want to import jwt from json web token and then we want a function [Music] that we're going to call authenticate token and this will take a request a response and a next like so okay so we said that we were going to send the token in the authorization header so let's read the authorization header and so we can do that with request dot headers and we're looking for all the prization and we know that this is going to be bearer space token like so but we just want the token out of there so let's pull that out so we can do auth header and auth header dot split we're splitting on the space and we're taking the second one in the array so what that does is we double check that off header is uh not null so that you know that we do have a authorization header and if that's the case then we're going to split it on the space so it's going to put bearer in the first index of the array and token in the second indirect x of the array so bear is going to be at zero token's going to be at one we want the token so we do one here and that will give us back our token okay now if that doesn't work for some reason then we're going to return 401 and we're going to pass back an object with an error property that says no token but if that does work then we want to verify the token so we do use the uh json web tokens verify method and we do token and we verify the token against the access token secret so this is verifying that this token was created using our secret that obviously no one knows and also checks you know if someone's gone in and change this token then you know it will fail the verification and we need to pass in a callback and if there is an error i.e didn't get verified then we're going to pass back a 403 and we're going to say whatever the error was like so otherwise we are actually going to get our payload says user here but you know the user information is in our payload so this is the payload from the token we're going to stuff that in a user property on our request and then the way that uh the middleware works is we just call next which will then essentially carry on because it's kind of passed through this middleware successfully and so it just carries on handling the request and of course we need to export the authenticate token function okay so we want to kind of see this in action now so how do we do that well if we go to users roots at the moment anyone can uh get to see all the users but perhaps when you want to let authenticated users see all the users actually in reality we probably just want to have it authenticated admin uh users see all the users but um let's keep things simple so let's just double check that this allows everyone to see users at the moment so if we go to request.rest and let's come down here and let's do a get and let's just copy this because i'm a bit lazy so that users and let's do a send request and as you can see anyone can see all the users in our database at the moment in fact we've only got the one which is bob let's just add another one so let's uh put in fred here say and fred and a password of fred and let's just create another user here so we've just added thread and then if we do a send request there you go so we've got two users here and at the moment anyone can list uh see all our users now we want to just only allow authenticated users to see our list of users so how do we do that well if we go to our users root here and it's as simple as putting in our middleware by doing authenticate token here and actually that auto imported for me but if it doesn't you have to import it up here and now that's kind of inserted our middleware and it won't get through our middleware unless we're authenticated so let's save that go back here and now try again and we get this error now null token so that's actually hitting this line here because we basically haven't sent across a token in our header so it's hitting this line here so how do we send a token across well let's come back here and what we need to do is we come down underneath here and we can do authorization bearer and here we can stick in our token now we need a token that is valid so we need to log in first grab this access token here copy paste it in here and then send the request and now we were successfully authenticated and it sent back our users uh but eventually our web token will expire because we set it to like 40 seconds i think it was 40 seconds coming here uh how long was our oh 20 seconds yeah i thought that was a quick 40 seconds so yeah it expired just after 20 seconds so we get jw jwt expired because we hit this line here we got an error because the token expired and so that happened and so it doesn't matter how many times we try and uh get authenticated that's not going to work and if we start messing around with this token maybe try and delete a few characters or whatever then it will actually fail for different reasons and uh we need a completely valid token in here to get past the authentication stage okay so now we need to just handle refreshing our token so if we go into auth routes and underneath login we want to do router dot get refresh underscore token let's do an arrow function and a good old try catch so this is where we are going to try and use our refresh token to get a new access token and hopefully our refresh token is getting sent along in a cookie and that http only cookie so we read it out of the cookie like so and actually for the moment let's just console log out our refresh token to see if that works we'll have to jump back here so we can see our console so if we come back into here into and we want to do a get let's copy that but we want to do off slash refresh underscore token and then if we do send request as you can see we are getting our refresh token out of our cookie like that so that's good so this is working but let's check for it being null and we'll return a status of 401 and json an error of [Music] uh null refresh token like so but if it was good we'll get to this line and we will want to verify our refresh token make sure it's been created using our refresh token secret so verify refresh and in fact this should be refresh token this should be refresh token like so so verify refresh token against our refresh token secret and as we know this takes a call back like that and if there was an error we want to return to the status of 403. and we'll return some json so we can see the error message otherwise we're all good so we want to create our tokens again so we want this to use our jwt tokens with our user payload so which is this which we get we get out of the token out of the refresh token and again we want a new refresh token that we can put in our cookie so this has given us an access token and a refresh token and so we can pull the refresh token out of tokens here stick it in a cookie and we are now good for however long this refresh refresh token is good for and of course we want to do res dot json tokens so we want to return our tokens and let's catch our error it's going to be exactly the same as we're doing here so let's just copy and paste that and now we should be able to use our refresh token now to get a brand new access token and a new refresh token so let's see if that works so we can come back here now and do a send request and it's saying that our json web token has expired so that's probably because we've been uh coding for five minutes so uh let's just double check uh if i go into here yeah i said it for five minutes so our refresh token has probably expired so the first thing we want to do is we want to log in so that we get a access token and a refresh token let's see if we can quickly maybe not fast enough paste send request yeah just about quick quickly got in there within 20 seconds with our access token but that's expired now so we should be able though to use our refresh token to get a new refresh and access token let's do that and there you go this access token should be good for another 20 seconds so let's just paste that in here and there you go then that's going to eventually run out and instead of expecting our user to log in again which would be tedious on the front end we can just use our refresh token to get a new access token now i guess the thing that might not be completely obvious is that we're not setting a cookie here um so this get request is is kind of automatically sending the cookie across and that's kind of exactly what happens so you know if we look in here you can see that cookie obviously does exist and it's because it's getting sent by is getting set by the server here any subsequent request will automatically be sending across that cookie along with the request so the last thing i want to show is how to log out or essentially clear this refresh token and so what we can do is do a router dot delete refresh underscore token arrow function as for normal try catch and we simply want to clear our cookie and it's as simple as that so that will clear our refresh token cookie and then we can just return 200 saying refresh token deleted simple as that otherwise just going to do our standard error handling and if you want to see that in action we just come down here do a delete and that exact same route there refresh token deleted there you go so now you have enough of the api i think to have a handle on how to properly add users to a database hashing their passwords so their passwords are secure and then doing a login system that authenticates the user checks their password and then we have this whole json web token thing going on which basically gives a good user experience so they don't keep having to log in every time they come to your website or open a new tab or refresh the page all those things can now be handled using refresh tokens so i'm not going to go through the client code in any detail what i'll do is i'll just paste in the client side files and then i'll quickly go through how they're calling the api and i think we'll leave it there then okay so the html is fairly straightforward if you remember what the web page looks like looks like this so we have a login section users refresh token section and the delete token log out section so login users refresh token delete token and i guess the most interesting one is the login form and just the key here is that we've got this name email name password and we've got the submit button and that enables us to grab that form using get element by id and then we write a little arrow function to handle the on submit of that form and because we've named the form inputs we can do form dot email and form password like that to get the values for the email input and the password input so this is calling this login method and sending it email and password inside this data object here so i'm using fetch which is built into most browsers nowadays and it's a good easy choice the other choice is obviously axios but um fetch works fine and essentially this it's reproducing what we're doing here so a post a post request with a body that's got email and password in so if we come back here the post request with a body that's got email and password because data's got email and password in we just you need to use json stringify to turn it into a json string and that's about it for the login the only other interesting thing is that like i mentioned access tokens can be easily read on the client side so the payload inside them can be easily decoded and so we've actually i'm making a point of including this jwtd code javascript here which is just some basic javascript that actually just decodes our access token which means that we can pull out the username user id and email directly out of that decoded access token now if we go down a bit fetch users if you remember rightly to fetch our users we actually need uh our access token and so if we go down here we can see that we've just done this very very simple so we're using the authorization header and bearer space token and that's enough to get our users as long as we have a valid access token okay so the last thing i want to talk about is cookies and servers so this is a relatively simple setup in that my api is being served up on the same server as my front end and so the cookies are totally happy with that and you shouldn't have any problems with your http only setting to true and your cookies should work fine but if you're like me and kind of like to have your api separate from your front end then your cookies are going to get a little bit fussier so if i paste in what i mean you're probably gonna have to set same site to none which then means that if you want them to be http only i think you need secure setting to true as well so you may need all this for these cookies to be happy to go between your essentially your front-end server and your api server so just bear that in mind but i will probably do an example deploy to netlify with a back end of heroku so showing that it does work at the very least and i'll probably do another deploy where it's all on heroku if there's any change you know if if this is different um i will i will make a note of it somewhere but i'm pretty sure that the this should be enough to get it working with a front end on netlify and a back end on heroku and i think that's about it for this video all the source code is going to be in a github repo which i will put in the video description like i say i will probably do a couple of deploys one just purely on heroku and one with uh sort of split uh heroku and netlify and uh so you can test those out and i haven't gone through absolutely everything but there's not much more to it really and hopefully there should be enough there to for you to at least knock up a pretty simple login system let me know in the comments if you want a more detailed video on this i could probably do a whole react app using this kind of system so let me know if that would be helpful quite like to do it in svelte or something like that so that would be kind of cool as well or maybe even view so let me know if you'd like to see that and yeah i hope you found this video useful thanks very much for watching and uh this is the time that i asked you if you could subscribe please that would be super useful that would be really nice because that would encourage me to do more videos like this thank you very much you
Info
Channel: Morgan Page
Views: 28,275
Rating: undefined out of 5
Keywords: jwt, jwt authentication, jwt token, jwt refresh token, node js, web development, jwt authentication node js
Id: foL7tbTrS9E
Channel Id: undefined
Length: 103min 12sec (6192 seconds)
Published: Mon May 10 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.