Learn The Mern Stack [9] - Backend JWT Auth

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] this video is sponsored by dev Mountain if you're interested in learning web development iOS or UX design dev Mountain is a 12-week design and development boot camp intended to get you a full-time position in the industry to learn more visit dev mountain comm or click the link in the description below hey what's going on guys so I've had a bunch of requests over the past few months to continue my learn the myrn stack series on YouTube where we use nodejs and Express on the backend created a shopping list API and then created a front-end with react and redux and connected them together we also used react strap which is a package that allows us to create bootstrap components as react components so what I want to do in the next few videos is this implement authentication that's the main request that I've gotten is to add JWT or JSON web tokens so that we can protect certain routes and then we can login to get our register to get a token and then we'll send that token to the backend to access protected routes ok so that's what we're gonna do it's it's quite a bit of code we're gonna start off with the backend implement it there and then we'll move to react so it'll probably be three maybe even four videos now in this series we used em lab which is a service that offers remote MongoDB databases and M lab is now owned by MongoDB so what you want to do if you're going to follow along is create an account at MongoDB comm and you want to use Atlas which is is the remote MongoDB service so you just create an account login and create a new cluster and once you do that if you hit connect and then hit right here you'll see it will give you a connection string so that's what you want to use in your application alright now this is the github repository which I'm just gonna clone and I'm gonna go from there ok so it's basically where we left off the only difference is I did update the client I did update react to use version 2 of create react app so I'm going to jump into vs code 9 already have the command here to just clone the repository so I'm going to go ahead and do that I'm gonna clone it into this folder and I want to install my dependencies on both the the client side and the server side so let's go ahead and run npm install and this is on the server side so it's going to be installing express mongoose concurrently which is used to run the serve the front end and back end at the same time and then body parser which we actually don't even need any more because Express includes a body parser but that installed those so now it's CD into the client folder which is where react lives and let's install our dependencies there as well and if we look in client we look at package dot Jason it's installing all this stuff so react scripts react of course react Dom react Redux Redux react strap and bootstrap Axio so we can make requests so it's gonna install all that stuff on the client side all right and then I think the first thing we should do is create our user model on the server side so that we can actually register users and if we look at the package Jason on the server we have a script we have a few scripts one will run the server with node lawn one will run the client and then NPM run devil actually run both using concurrently so we set all this stuff up in the series so if you want to create all this stuff from scratch then go ahead and watch that series okay so let's um let's see D dot dot back into we in the root here yep so let's run npm run dev so this should run the back end and the front end see what was that invalid connection string parse error oh I didn't put them I didn't put my MongoDB connection string in so it'll run but it's not actually connected to any database I'm going to just jump over to MongoDB Atlas hit connect connect to your application and I'm gonna just copy this string right here and if we go back and we go into in the backend we want to go into config Keys j/s and put in the URI we also need to put in the password and save and now that should work there we go alright so let's see could not proxy requests should have a proxy in here if we look in client package Jason we have our proxy let me just restart this ok so it looks good let's go back and now we should be able to access our database which there's nothing in there but we should be able to add an item so let's try that out so we'll just say eggs add item and there we go chicken okay and we're using a react transition group to get that fade effect and again if you want to create this application how it is now from scratch just go through the series so if I go to my cluster here and actually we want to click on collections you'll see that now there's an items collection that has eggs and chicken in it okay so we're now we're connected to the database so we're basically in the spot where we left off so now let's jump in and let's create our user model so under models you'll see we have our item J s which just has a name and a date let's create a file here called user J s and I'm just gonna copy the item schema here are the item model and paste that in here and we'll change this to user schema and down here we want to make sure we change this variable to user and then this to user and this to user schema all right and then we just want to put the fields that we want so I do want a name I'm going to keep that and then I'll just go ahead and copy this down two more times we as we need an email and for the email I'm also gonna say that I want this to be unique so we'll say unique is true and then this field is gonna be the password so we'll go ahead and change that to password and that should be good well let's actually change this to say register date and that's just gonna put the the current date in okay so whenever they register it'll put that date and time in so let's save that we now have our user model and we want to have some routes okay we want to route to be able to register a user so in the routes folder we have API as a folder and then our items that has all of our items routes inside API I'm also gonna create a file called users dot Jas okay and now in our server j/s we have to add that file as a route so what I did here for items is I set a variable to the the routes file and then down at the bottom right here I said app use API slash items and use that variable now I'm going to cut this down a little bit and just put this required directly in instead of creating a separate variable I'm just gonna put the require right in here alright and then we'll copy that down and we want one for users so API slash users it's going to go to that users route file ok it's going to give me an error because there's nothing in that file we need to actually implement the Express router and all that stuff so let's go into users j/s and I'll actually copy items j/s real quick everything we have in items j/s and the routes and paste that in because we want to bring in Express we want the router we want the user model so we'll change this to user and this will be model slash user and then we want a route to register which I just want I want the route to be slash API slash users which is going to be this route here so it's changed this to API slash users and this is going to register new user it's going to be public and then I'm just gonna get rid of everything in here for now and let's just do a res dot send and we'll just say register just to test it out and then I'm gonna get rid of every other route here these other two okay make sure that you're exporting the router as well so if I save that now we don't get an error now this warning right here is from Mongoose it says collection dot ensure index is deprecated use create indexes indexes instead so if we want to fix that if we don't want to see that warning anymore we can run it we can go over to server J s and right here where we connect to MongoDB with Mongoose the second parameter with this object we have this used new URL parser I'm just gonna add to that and I'm gonna say use create index and we want to set that to true okay so that should get rid of that error all right now we have our register route let's test it out we're gonna be using postman so I'm going to open up postman which you can get it I believe get postman calm and we want to make a actually we want this to be a post request so we want to change that and that to post okay and then let's do post to HTTP localhost 5,000 slash API slash users and if we send that we get a response back a 200 response that just says register okay so we know that we can access that route so let's continue on here and let's actually register a user obviously we're going to have to send some data now Express the latest version of Express includes a body parser back when we did this we had to this is the server JS file we had to install body parser separately and then add the middleware so what I'm gonna do is just get rid of this and instead of this we're gonna do Express dot Jason all right and then we can actually remove that package we no longer need it so I'm just gonna stop the server down here and do an NPM remove of body parser because we no longer need it okay so another thing I want to do is install let's see I'm gonna install bcrypt because we're gonna want to hash our passwords when we register a user so let's do B crypt we're actually going to use B crypt j/s you can use the standard B crypt but I always run into issues with it dependency issues and stuff especially on Windows so especially if you're on Windows I'd suggest using Big B crypt Jas so let's do run dev again actually you know what we don't even need to do run Devas we're not dealing with react right now so I'm actually gonna do run server which will just run the back end so NPM run the server alright so now let's head back into our users route here and we're going to be getting the data in requests dot body right so what I'm going to do is just use some destructuring and I'm gonna pull out some values from that so let's pull out the name email and password so whatever we we pass along is the name email and password there now in variables and I'm just going to do some simple validation here so we'll do if let's say if not name or not email or not password then let's send a response so we're going to return res dot status we want to send a status of 400 which is a bad request it means that the user didn't send the correct info to get the correct response and then we'll just add on some Jason and let's just pass in a message and we'll say please enter all fields okay now if they do send the name email and password let's go ahead and check for existing user so to do that we're going to use them the user model okay we're going to which is we're using Mongoose and we're going to use the find one method and we want to find by email so we pass in an object we want to say we want to look for the email that's equal to the email variable and since these are the same I can simply just do that okay and then that's gonna give us a promise back so we'll do dot then if you want to use a sink away you can but I'm not gonna I'm not going to use a sink away and then here this is going to give us a user possibly if there is one and if there is one then we want to send 400 response saying there's already a user registered with that email so let's say if a user so basically if this will be null if there's not one if there is it'll return the user so we want to check for it actually won't even need we can put this all on one line so if there's a user then let's return res dot status 400 dot JSON and in here let's just put a message Jesus I can't type let's put a message and we'll just say user already exists okay so if a user doesn't exist then we want to create a new user so I'm going to create a variable called new user set it to new and then our user model passing an object and we want to add the name the email and the password which are getting pulled from the data that's sent to the to the endpoint okay now this user has a password that is not hash we obviously don't want to put that in the database so we want to bring in bcrypt which we already installed so let's say cons bcrypt and we want to set that to require and remember we're using bcrypt je s so we want to make sure we say bcrypt je s okay now down underneath where we created this new user object we want to do a couple things you want to generate what's called a salt which is used to create a hash okay a password hash from a plaintext password and that's what we want to put in the database so let's say hash I'll say create salt and create salt and hash okay so we'll take bcrypt and we're gonna call gen salt and this takes in the number of rounds we want to use the higher the more secure but it also takes longer the default is 10 so I'm just gonna use that and then it takes a callback function so I'm gonna use an arrow function it takes in an error and then our possible error and then the salt okay so once we get the salt we can then call bcrypt dots hash and this bcrypt hash is going to take in a couple things it takes in the plaintext password which is going to be this new user dot password so pass in new user dot password then it takes in the salt that was generated so we'll pass that in and then a callback with a possible error and the hash okay now once we get the hash we will actually let's check for the error first so if there's an error we'll just go ahead and stop it and throw the error okay then we want to save the the new user the password which was plain text we want to now save it to be the hash okay now then we can actually save the user in the database so we'll do new user dot save okay we're going to use new user save and then that's going to give us a promise back and in here it'll give us the user and then we can decide what we want to do once we save it which since this is a basically a REST API we want to just send a response back ultimately we're going to generate a token here and send the token and the user but for now we're just gonna send the user so let's say res dot Jason I'm gonna have an object with a user object we'll have the token as well later on but for now we'll just have the user and I don't want to send that the entire user back with the password so we want the name X let's do let's do the ID as well so user dot ID user name and then let's do email okay so it'll send that stuff back and we should be good so we'll save that and let's try and register user so we'll go back to postman and we already have our request here but we need to add some data to register with because right now if I try it we get please enter all fields so in order to send data we need to go to our headers and set a content type so the content type of applications slash Jason and then in the body will choose raw Jason and it's put in our double quotes here let's send a name so for name let's just no just to me yeah that's what a comma here and then we want email I'm just gonna do Brad at Gmail and then a password so obviously we put in our plain text password I'm gonna do one two three four five six but it should get hashed so let's send and then we get a response back 200 response with the user ID name and email and if we head over to Atlas and I reload we should have a users collection which we do and if we look in users collection we have the user we just registered and take at the password it's completely hashed all right so we now have the ability to register a user so now we want to do is is implement tokens okay I want to make it so that when we register we get a token just like when we login so that we can immediately log in from our front-end so if we go to JWT dot io this tells us a little bit about what JSON web tokens are and I actually have a video on JWT where I just kind of explain it a little bit I give you a basic example a node without a database but basically it's it's it looks like this so it's easy to send back and forth and it has three parts to it as the header which has the algorithm and then the token type it has the payload so we can send any data that we want with it so a lot of times it'll have an issue dat which is the time that it was created you can also have an expires which will do so it expires at a certain time you could send usually you send that the users ID or the end or the name some other data and then it has the signature okay it has the the encrypted signature so those are the three different parts and you can see that they're actually highlighted here in the token and you can take any token and put it in here and it will show you that info all right now in order to generate one of these things we have to use a package called JSON web tokens so let's jump over to vs code and let's stop the server and let's do NPM install Jason web token all right and then we'll just do NPM run server actually you know what I'm going to install on something else here just to deal with configs right now I have any any keys or whatever config values I have in this keys j/s which isn't the best way to handle this you definitely don't want it if you if you're pushing your code to github you don't want to have this kind of stuff in there I'm not going to go over that kind of stuff like security too much here just know that usually you want to put this stuff in environment variables on your server and you don't want this clearly exposed in your repository and I'm mentioning this because to use JWT we need to have a secret a JWT secret and I'm also going to put that in the config so I'm going to install a package here called config so that we can handle this a little differently and we'll go ahead and run the server instead of having this keys dot j/s I'm gonna have a JSON file inside config called default so default dot jason okay and in this default jason we're gonna have a json object with any secrets any api keys connection strings stuff like that so let's put our uri in here so i'm just going to grab that from the keys j s and put that right in here and then i'm also going to put in a JWT secret value and i'll just set that to I don't know SL which is shopping list underscore my JWT secret it doesn't really matter what this is okay so I'm gonna save that and then I'm gonna actually delete the keys JS file so now in server J s down here where we connected to Mongoose I'm sorry to MongoDB C where's the URL we put it right here in this DB variable we use that keys file and then we just use that URI I value so instead of doing that I'm just gonna bring in config okay and now I can simply do instead of this I can do config dot get and then pass in URI oh I forgot the quote okay so we can now get our config values with config dot get which is a little bit cleaner so let's save that and then let's go back to users and we're gonna bring in config here as well because we need that JWT secret so let's say Const config equals require config and then we also want JSON web tokens so let's bring that in we'll say Const JW t equals require jason web token all right now down where we did the register we're gonna want to change this up a little bit so this is all the same the hashing we're gonna save the user and then in the response is where we want to also create the token so right above where we did the res dot Jason I'm gonna take the Jade JSON web token and I'm gonna call dot sign okay so we want to sign the token and the first parameter is gonna be the payload that we want to add so this could be absolutely anything you want what I want it to be is that the user ID so I'm gonna say it's gonna be a JSON object with ID and I'm gonna set it to user dot ID so that way when we send a token from react or from postman wherever it's coming from the user ID is in there so that it knows which user it is okay otherwise any token could access anything so you want to make sure that you send that ID and you verify it to do so and things okay so that's the payload and and you could add more stuff if he wanted the name and stuff like that all right the next parameter is gonna be the secret so let's do config dot get and we want to get the JWT secret value now this next one is optional it's if you want it to expire and I do I'm gonna say expires in and I'm gonna set it to 3,600 all right so what I did here is set it to an hour so 3,600 seconds so this token will only last for an hour and it's up to you you know if you want to set it longer or if you don't even sometimes you don't even have an expires now the next parameter is gonna be the callback case because this is asynchronous you can also do this in a synchronous way but I like to use asynchronous so on the next line here let's put a callback this will give us a possible error and then the token okay so we're gonna set that and let's see let's first just check for the error and I'm just gonna do throw error now this is where we want to send our response now we have our response down here with the user so I'm going to grab that and I'm gonna cut that out and I'm gonna put it in here okay inside the callback for a JWT sign now in addition to the user I want to send the token so I'm just going to simply add token which is the same as doing token equals token okay so once we register not only will it give us the user back it should give us a token so that we can then authenticate with private routes which we haven't set up yet okay in many past tutorials and like in my myrn stack course we used passport j s we use that middleware to create private routes and all that but i'm actually going to show you how we can write just very simple custom middleware to handle that but before we do anything else let's test this out so let's make sure that this is saved and let's go back and let's try to register a new user I'm actually going to delete the user from that we just created just so I don't fill up my database here ok so now we have no users in the database and let's see we'll go back to postman and let's do the same thing we're sending a post request to API users and I'm adding the same data in the body the name email password although this time we should get a token back as well so let's send or register and if we check it out we have the user and we also have the token now if I take this token which again is broken up into three separate parts and I go to JWT IO and I paste this in here and we take a look we have the header let's look at our payload we have the ID so this is the ID of the user all right and we have the issued at and then the expiration which is an hour from now okay now just to make sure this is the ID of our user let's see it's 5 C 7 f e if we look in our database let's reload we should see our user and the 5 C 7 Fe so it's the same ID as the user so we want to make sure that that's in the payload alright so we have our registration down now we also want to be able to authenticate and get a token as well so to login and get a token so let's go back to vs code now if you want to put your authentication stuff in this the same routes file the users routes you can do that however I'm going to create a new file in routes slash API just called off dot J s ok so I'm gonna just copy everything for me the users route and paste that in here so because we want to bring in most of this all of this stuff actually and then let's see we want to bring in our user model and then let's have a route that is a post request to API slash off so this is going to authenticate the user it's gonna be public obviously it's gonna be public because this is the way that we actually get the token so that we can then send it along to private routes and then we're gonna just grab the email on the password no need for the name validation we'll just check for email and password it's the same thing please enter all fields so we'll go down we'll check for the user by the email now if there's not a user that's when we want to send back an error so we're gonna say if not user returned 400 and we're gonna say user does not exist okay so user does not exist and then we don't need this let's see so instead of generating a hash here we need to actually compare the plaintext password that's sent with the body request to the the youth the hashed password in the database which comes from here so user dot password so I'm just gonna get rid of all of this even though we will be doing some of the same stuff I'm just gonna get rid of this whole block here okay so let's see we're gonna start off by validating the password so let's say validate password and we're going to use bcrypt and there's a method called compare now this compare takes in password which is our plaintext password that's sent in and we want to compare it to the user dot password which is the hashed password okay now this returns a promise so we'll do dot then and this will give us a boolean which I'm gonna say is match so does it match or not okay now if it doesn't match then obviously they're not gonna we don't want them to authenticate so we'll say if not match then let's return a response status of 400 because it's a bad request since it's not it's not a correct login and we'll say Jason and let's do will say message invalid credentials all right now if there if it does match then that means that it's a correct login so in that case we want to send the token and the user just like we did in our registration so I'm just going to grab from users J s I want to grab this whole JWT sign with the response inside the callback so it ends right here so I'm just going to grab that chunk and I'm gonna put that right here okay so again we're signing the token we're passing in the user ID as a payload we fetch the user here so we're passing the ID and then we get our secrets it's going to expire in an hour we have our callback and then we send the response with a token and the user okay so that should do it let's save and let's go back to postman and now let's make a actually I'll just I'll use this one so instead of a post request to API users we want to do API slash auth and as far as the body goes we don't need a name because we're not creating a user we're just validating but let's do a user that doesn't exist like Brad one at gmail okay so if we go ahead and we send that oh we never added the we never made the file available to the route so we need to actually go to server J s and just like we did with the other two routes right here we need to bring in API off and API off okay so let's try that again and we get a response that says user does not exist now if we do Brad a Gmail which does exist and we do a password that's wrong we get 'invalid credentials so let's try with the password that's right and send and we get a token and we get the user so same response whether we register or whether we authenticate if we login so this makes it pretty easy on the front end all right now the last part of this is to create the middleware so that we can have private routes that are only accessed if we send along this token okay so what we'll do here is create our own middleware so let's see we want to be in the root I'm just going to close all this stuff and in the root let's create a folder called middleware and inside here we'll create a file called off dot j/s okay so in this file we want to bring in our JSON web token we also want to bring in config so I'm gonna bring that in first okay and then we'll bring in Jason web token we'll set that to JWT okay so we're just going to create a middleware function and just call it off and when you have a middleware function you want to pass in three things the requests the response and next okay when you're done with whatever this piece of middleware does you want to call next to move on to the next middleware okay now remember the purpose of this function here is to get the token that's sent from either react or postman angular whatever front-end you're using where it's gonna send along a token so let's create a variable here called token and we want to fetch that from the header so a header values are in requests so request header and we're gonna send it in X - authe - token so that's the header value we want to check for the token okay so we'll say check for token and we'll say if there's no token that's X - off - token then we're gonna send along let's say res status now this status is different this is a 401 status which means that you you don't have the correct permissions or what the hell is it how do I explain it 401 status status unauthorized that's so that's the word I was looking for so we're saying that the user is unauthorized okay so let's also send some JSON and I'll just send a message that says no token authorization denied okay so actually I'm gonna need curly braces cuz this can be a single line now if there is a token then we need to verify it okay so let's say verify token and the way that we do that is I'm going to create a variable called decoded and set that to JWT dot verify and we want to pass in that token okay and this also takes in that JWT secret so we can say config get and JWT secret all right now we want to take the user from the token okay because remember we set the ID it's sending the user ID and we want to put that into request dot user so that way whenever the token is sent we have that user stored in the request value all right so let's say add user - let's just say add user from payload so request dot user because you can set any request variables in middle and up in your middle air functions and we want to send it set it to decoded okay and then we just want to call next which will call the next piece of middleware now actually what I want to do is wrap this in a try-catch because if the token isn't valid then we obviously we don't want to do that we want to send back an error response so let's just do try let's say try catch and we'll have our exception and then we'll just take this and let's grab this too and let's move this up into the try block and then in the catch we're gonna do a res dot status this will be a 400 request cuz it's it's a it's a bad require 400 response because it's a bad request and then we'll just send Jason and let's do message and we'll say token is not valid okay now the last thing we want to do is export this middleware so we'll say module dot exports equals off and that's it so now whenever we want a private route we can simply add this piece of middleware as the second parameter in the endpoints so for instance let's go to let's go to our items routes so 8th routes API items and what I want is the the post here to create a new item and the delete I want the I want to be have them to have to be authenticated so what we'll do is bring in our middleware so we'll say Const off equals and we just want to set this to require we want to go let's see dot dot slash outside of API outside of routes actually we need quotes around this so outside of routes and then into middleware and then in and then we want the auth file ok and then all we have to do to protect this this post request right here to create a new item is simply add off as a second parameter just like that okay it's for same thing for delete we just want to add off so now those routes should be protected so if I go back to postman and I try to add an item let's make a post request and let's do HTTP localhost 5,000 slash API slash items and I want to add let's see headers is gonna be content type application Jason and then for the body I want to send raw Jason and we just want to send a name I believe it's a name so a name of let's say steak so I'm gonna send this and check out what we get a 401 unauthorized response and it says no token authorized denied authorization denied so in order to do this we need to have the token so let's go back here and this is the route to actually log in and get the token sorry about that and I'll press send and then we have our token so I'm going to copy this go back to our post request to add the item and we're gonna add in the headers a value here of X - off - token so we would do this within react or angular or view whatever it is we're using on the front end and then we want to set the value to the token okay so now I'm gonna send and it gets added okay and just to make sure if we go to Atlas and we go to items we should have steak and there it is now the last thing we want to do is we want to create a route inside auth J s because in this route what it's going to do is check for the current user get the current users data by using the token the reason we want to do this is because JWT authentication is stateless okay it's not like using sessions where you have authentication data stored in memory or whatever on the server you just send your token it decodes it and then it sends you the response so we need a way to constantly validate the user that's logged in in our front-end so we need a route that's just going to take the token and then return the user data so in awe a I want to bring in our auth middleware so I'm gonna say Const off set that to require and let's see where are we so we're in I want to go outside of API outside of routes into middleware and then off okay and then down here I'm gonna copy this this little comment block here okay so this route is gonna be a get request to API slash off slash user and let's just say get user data and this is gonna be private in fact I forgot to set in the items routes delete is now private and so is post okay so they're protected or private whatever so back here let's let's create let's say router and it's gonna be a get request and remember we're in the auth file so we just have to do slash user we want it to be protected so we'll add the off middleware and then our request and response and we're going to take our user model we're going to call find by ID and we just need to pass in the ID now we can get that by doing request user dot ID and I don't want to return the password so I can simply do dot select and then just do pass in here - password okay so that will just disregard the password and then this will give us a response and we want to it'll give us the user I'm sorry it will give us a promise with the user and then we want to just send that user okay and it will - the password and that's it so that will validate the user with the token so let's try this out and post in so I'm going to take this token so this is the token that belongs to the Brad Travis II user so I'm going to take that and I'm gonna make a get request to http local host 5000 / API slash auth slash user and I want to attach a headers value of x - auth - token and pass that token and then it should give me the user that this token belongs to so if I send there we go we get the user - the password now if I authenticate with a different user I think we have do we register any other users let's sort of gesture a user real quick so if we go post request to users and let's just do like John at Gmail send please enter all fields that's right because this is registration we need to add a name okay so we'll send that and now this token should reveal that this is the John Doe user so if I go back to this off user and I put in this token I just want to replace this and send now we get John Doe so you can see that it knows what user it is based on the token because of the ID that's embedded in it in the payload alright so hopefully this wasn't too confusing and I know this was a long video but like I said this this stuff isn't it's not that easy really especially dealing with the front end and the back end together so at least we have the back end all set so in the next video we're gonna start to work and react we're gonna we're still using our shopping list application we need to create a login and register component so that we can send this data so that we can get a token and we can send that if we want to access a private route we'll implement an auth reducer and redux and and we'll go from there all right so thanks guys thank you for watching and if you do like this stuff please leave a like and I'll see you in the next one
Info
Channel: Traversy Media
Views: 103,418
Rating: 4.9745474 out of 5
Keywords: mern stack, mern, react, react node, redux, jwt, jsonwebtoken, json web token, node jwt
Id: USaB1adUHM0
Channel Id: undefined
Length: 48min 57sec (2937 seconds)
Published: Thu Mar 07 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.