Node.js REST API With Restify, Mongoose, JWT
Lesson 2 of 2 · Node.js Rest API With Restify, Mongoose, JWT – Part 2 · Programming
Node.js Rest API With Restify, Mongoose, JWT – Part 2
hey what's going on guys welcome to part 2 of our REST API using Resta phi and Mongoose and now we're gonna get into authentication with JSON web tokens
password encryption with be Krypton and some other stuff now you may have noticed where we left off in the last video when you make an update you get this warning here it says collection dot
find and modify is deprecated use find one and update okay or find one and replace now we did use find one and update as you can see right here so this is I think I don't know if this is a bug
or what but there's a simple solution to this it's just to go right above where we did the Mongoose dot connect and we just simply want to say Mongoose dot set and we want to set use find and modify
and we want to set that to false like that ok so that should actually get rid of that message so now I'm going to go over to postman and do a quick update so this is Kate Williams ID as you can see
it's the only record I have in my database so I'm gonna make a put request to change it to Kate Williams as you can see it's Kate Smith right now so let's go ahead and make that update make sure
it worked ok so now it's Kate Williams let's go back and that that error did not happen ok I should have cleared this first but it didn't happen in fact just to make sure let's uh let's go ahead and
clear this out run it again and go back to the put request send and now you'll see we don't get that error ok so I should've did that in the last video but I completely forgot about it
alright so let's move on now there's a few things that we need to install here so again I'm going to stop my server and let's clear this up and let's do an NPM install so in order to deal with tokens
there's basically two things we need to install one is called Resta phi – JWT – community we're also going to be using JSON web token and then we need to encrypt our
passwords you never want to store passwords in a database in plain text so we're gonna use something called bcrypt but we're gonna use bcrypt GA s because it's a lot easier to work with less
dependencies and stuff like that so let's use bcrypt j s and I think that's all we need to install so yeah let's go ahead and do that so that stuff should get added to our
package dot jason alright good so let's see where to start now obviously we're gonna need users to deal with because we're not we're not using like Twitter or Facebook or anything like that we
actually want to use our MongoDB database to store users and log in with or authenticate with with our API so we're gonna need to create a new model so I'm going to go to models and create
a fold another folder a file called user dot J s capital u okay and our user model is actually going to be very very simple we're just gonna have an email and a password so let's say Const
Mongoose equals require Mongoose okay and we'll create a user schema I'll set that to new mongoose schema and we're gonna pass in here an email okay type string and let's say required true I'll
do trim true as well all right and then we just want a password so password type also string and required true okay so that's all I want and then we just want to do down here
Mongoose dot model and say user and user schema alright so that's it pretty simple now we want to do is create a routes file so in our routes folder we'll create a file called users dot J s
just like we did with customers and I'm gonna go to the index real quick and just like we required the customers routes and and passed in the server object we're going to do the same thing
for users so we're just gonna go ahead and change this to users and pass in server ok because my first goal is to be able to register a user so we'll have an endpoint at slash register we'll enter
an email and password that should get stored in the database along with encrypting the password with bcrypt alright so now that we did that let's go to back to users and our routes and we
want to bring in first of all Resta phi errors okay let's see we also want to bring in our user model so let's say where are we we're in the route so we want to go dot
dot slash outside of routes and into models and we want user okay we're gonna call this user all right I think that's all I want to bring in for now so just like with the customer routes
we're exporting a function here what problem M we're passing in the server objects so we want to say module dot exports and we want to set this to a function I'm going to use an arrow
function server as our parameter and now we can create our route so we want a register route so let's say register user so I'm gonna say server dot and this is gonna be a post so server post
to slash register and okay and here we want request response next so for our register we're gonna sent when we make our requests from postman we're going to send an email and a password so what I'm
going to do is use a little D structuring to pull those out so we'll say email and password and we're going to pull that out of request dot body when that gets sent okay so now we have
an email and a password to work with now we want to create a new user so I'm going to say Const user equals new user from the user model we just brought in and then we want to pass in an object
and we want to just pass an email and password okay so this is just shorthand for like doing that so that'll create a new user it didn't save it yeah it's just it's just creating it now we need
to hash the password okay so we're going to use bcrypt j/s for that so let's try let's bring that in will actually bring that in right here so Const bcrypt require bcrypt Jas make sure you do be
Crypt is here so now what we want to do is call B crypt and there's a method called Jen salt which is going to generate a salt so that we can hash the password so this takes in a number this
is the the number of rounds so we're gonna use 10 here and then this takes in a function we use an arrow function and as far as parameters it takes an error if there is one and then the salt okay
so it'll give us a salt that we can hash the password with so in here we want to call B crypt hash dot hash and this is gonna take in the plaintext password now remember we have this user object we
created from the email and the password that were passed in from in our case it'll be postman if you built a front-end to this it would be from react or view or whatever whatever you use on
the front-end so we'll just pass in user dot password which will be the plaintext password alright then we want to pass in the salt that was given to us in the function right here from this parameter
and then we want a call back all right so this function here is going to take in an error and it's going to give us the hash I'm also going to label this asynchronous because I will be using a
weight in this function and now we should have access to the hash so what we want to do is now set this user's password not to the the plaintext that it is now but to the actual hash so to
do that let's just put a comment here we'll say hash password will just say user dot password is now equal to – all right now we want to save the user because we haven't done that yet we
croute we created the user object but we haven't saved it we needed to first encrypt the password so to save the user I'm going to do a try/catch ok so inside the try let's go ahead and create a
value a variable of new user and we'll set that to a weight and we're gonna say user dot save ok so saved it's just we're just using Mongoose to save the user you could if you don't want to use
a sink away you could do user dot save dot then and so on but I like to I like this syntax much better and then we want to just do a rez dot send and we're creating something so we want to send a
201 status which is created and then we just want to call next ok now if something goes wrong here I'm actually going to I'm gonna use Resta fie errors and I'm gonna return next with an error
so we'll say in here new errors dot and I'm gonna use an internal error and we'll pass in whatever the message attached to the air is like that ok and that should do it so let's save this and
hopefully we can now register a user so let's give it a shot let's run our server and p.m. run dev and let's go to postman and let's see I'm gonna open up a new tab we're gonna make a post
request you can close these other tabs if you want I'm just gonna leave them open in case I need them again so let's do HTTP localhost 3000 slash register and we want to add let's the headers we
want to add a content type of application oops of applications slash Jason and then under body let's go to raw and let's put in our email and password
so we're just registering a user now so I'll do Brad at gmail.com and let's see password now I'm gonna put a plain text password but it should encrypt it so let's do one two three four five and
send couldn't get any response let's see see what we got for an error here user is not a constructor okay so we brought in our user model models yeah user J s let's see we should be
able to instantiate it right here let me look at the model oh I just did Mongoose top model okay let's copy this in customer and do the same thing I don't know why I did that
so I'm just gonna change all these customer instances to user alright so const user equals Mongoose model user pass in the schema and export the user alright so that should
hopefully fix this this problem so let's try to register again let's send good so we got a 201 created status now just to check to see if this actually got entered into the database I'm gonna go
to M laughs and let's go to our database and you can see now we have a user's collection gets created automatically and we have Brad at Gmail and if you look at the password it's completely
encrypted okay so bcrypt j s allowed us to encrypt it now we need to make sure when we authenticate we decrypt it so that's that's another process but this is up to
this point we're able to actually register a user through our API which is what we want alright so next step what is the next step I'm trying to think of how with the best way to actually show
you guys this so let's create a separate file for our our authentication so basically to reach into the database find a user by the email that's entered and then to match
the password we want to do that in a separate file so I'm gonna close all of these for now and I'm gonna create a new file in the root okay so in the root I'm going to create a file called off jas so
this is like our authentication authentication strategy and the whole point of this is to check to see if there's a user by the email that's entered kay when we when we authenticate
also decrypt the password and and match that in the database okay and if it passes then we just want to resolve the user or return the user and this is going to be a promise so we need to
bring a couple things in we need to bring bring in bcrypt so let's bring that in require bcrypt j/s okay we also want to bring in mongoose
now we want to bring in our model but if I were to let's see I want to bring in our user model if I were to just say Const user you know model slash user like I did right here like I did here
it's going to give us an error saying that we already brought it in so another way that we can bring it in to the auth j/s file is we can simply take Mongoose and we can say dot model and pass in
user okay if you don't do that you're probably going to get an error now I just want to export one method from this call to authenticate so I'm going to say Explorer it's dot authenticate and this
is going to be a function it's going to take in an email and the password okay and I want this to return a promise so I'm going to say return new promise and a promise takes in a function I mean you
could do function if you want I'm going to use an arrow function and it takes in two parameters which is resolve and reject so basically when your promise is done doing whatever you want it to do
when you want to return something from it you call resolve and pass whatever you want in when if you run into a problem an error then you want to reject so and that's what the dot then and dot
catches the dot then is the resolved and then anything you know any errors that you reject will be in the dock catch so what I want to do here actually I'm going to add a sink here because I'm
going to use a weight we first want to do a try let's do try catch alright so in the Tri we want to first get user by email so we'll say Const user equals a wait
we're going to use Mongoose here on the user model and we're going to call find one okay find one we can find we can find a user by anything I'm going to look by email so basically I would do
like email email but we can just do that shorten it okay so that's going to find the user by the email now if something goes wrong here meaning it can't find the user then we want to reject from the
promise okay so down here we'll say actually to put a comment here we'll say email not found so we just want to reject and then I'm just going to send a message saying authentication failed I'm
not even going to say like email not found or anything right like that because I don't want the I don't want the person that's trying to login to even know that the email exists or
doesn't exist basically it's just an authentication failed okay I think that's a safer way to do it in fact I've done it the other way saying this email doesn't exist or whatever and
people have given me crap for it so we're just going to say authentication failed now inside here after we do this get user by email obviously if if it's found then it's going to keep going so
then we want to match the password so to do that we're going to use bcrypt so we want to say bcrypt and it has a method called compare and compare actually takes in the password which in this case
is going to be the password that the user enters okay so or in our case we're going to enter through postman when we try to authenticate and then it's going to take in the actual user's password
that is found here so to do that we say user dot password alright and it's basically going to compare those two now this will give us a function and this takes an error if there is one and then
is match so if the passwords match then this is going to be true so let's first check for the error I'm simply going to just say if error then throw error and then we want to check to see if there's
a match if the passwords actually match so this is going to be an if-else okay so we want to say if is match then what do we want to do we want to resolve right because remember I what I said
with the promise when it does what you want it to do you want to resolve a value so we want to simply resolve and then pass in the user okay else then we want to reject this means
the passwords didn't match I'll just say pass didn't match so we want to reject and I'll just do the same thing and say what did I say authentication failed sorry about that I don't know what the
hell that was what was that noise so authentication failed alright I think yeah I think that's good so so just to kind of reiterate we have an authenticate method that we're going to
use that's going to take in an email and password it's going to return a promise okay we're going to try to get the user by the email if the user isn't found then it's going to just reject and say
authentication failed if it is found it's going to move on it's going to compare the two passwords okay taking into consideration the encryption we're using bcrypt if they match then
we're going to resolve and we're just going to basically just return the user else then we're just going to reject and we're just going to say authentication failed so that's that's what this does
okay so this is our log our authentication strategy so now let's close that up and let's go back to users and we now want to work on our author out okay our author out is what we use
to authenticate and get a token back we haven't even started dealing with tokens yet but we just want to make sure we can actually you know basically match the email and password to the database so
let's go below our register so this ends right here and we'll say auth user so I'm going to say server it's going to be a post endpoint is going to be off okay and see we're going whoops I'm just
going to take in request request response and next let's see it's also going to be asynchronous async so what do we want to do we're going to get an email and a password right when we when
we try to hit this off point we're going to send an email and a password to try to authenticate so let's actually pull that out of the request body okay so we get the email and password
let's do a try-catch and in this try we want to authenticate the user using the the method we just created in auth J yes in fact we have to bring that in if we want to use it so let's go up here and
say Const off equals require and let's see that is what right outside so dot dot slash off okay so now we should be able to use the method authenticate so we'll say Const let's do Const user
let's put a comment here Const user equals auth dot off n takete and we want to pass in here the email and password that that's being brought in from in our case postman or whatever the front end
is so email password okay so if this fails then what do we want to do we want to say user unauthorized so I'm just going to use rust if I errors I'm going to return next and I'm gonna pass in I'm
gonna pass in new errors and we're going to use the unauthorized error and we'll pass in whatever is in this right here okay so yeah I think I think at least right now what I'll do before we do
anything with the tokens we have to call next here let's just console dot log and we'll just console.log the user okay so we can test we can at least test it out what's this schema hasn't been
registered for a model user come on we alright so I just paused it and checked it out and the reason we're getting this this error here is because in our off j/s this right here when we brought in
Mongoose Top Model this should be an upper case you okay so once I save that you can see the error goes away all right so let's test this out so we should be able to authenticate if it
happens then we'll console.log the user if not we'll get an error so let's go to postman let's open up a new tab make a post request to localhost 3000 slash off and let's just add a content type it's
due application Jason and in our body will choose raw okay so now we're actually trying to authenticate against the user in the database so let's put an email and let's do Brad let's do one
that's not remember we have Brad at Gmail I'm going to do Brad one at gmail because I want it to fail and then for password we have one two three four five but I'm gonna do one two three four so
let's see what we get if we try to use these credentials all right so something's happening here let's go back and authentication failed why isn't it showing it handle promised
rejection wait a second they sync Oh remember authenticate it remember it returns a promise here I didn't use a wait okay I also could do dot then I could do that because it's a promise but
I'm using a sink of wait so in that case I need to do and make sure that a sink is right here as well all right so now let's try it again it should still fail with it we
should see it down here and there we go unauthorized now if I have the correct email but the wrong password we should get the same thing but if I have the correct password and the correct email
and I send ok so we didn't we didn't actually send a response if it went through but if we look at vs code and we look in the console you can see that it's getting logged so this is happening
right here it just didn't do anything in postman because we didn't do like a res dot send 200 or anything like that so now what we want to do now that we know that our authentication is working is we
want to pass a token to the authenticated user and that's where the to the to do we install them yeah JSON web token and Resta phi JWT community that's where these two come in now jason
web token is responsible for creating the token okay so it'll create the token the expiration and all that stuff and then Resta phi JWT community we're going to use to actually protect routes okay
so if you need like for instance to create a customer you're probably not going to want just anyone to access that route you're going to want them to authenticate get the token and then pass
that token in through the header okay whether it's through postman or whether it's through react or a front-end framework or whatever alright so let's go back to users J s and let's bring in
those two modules so I'm going to say Const JW t equals require jason web token alright and then let's go down to our off and right here is where we're going to want to create the token all
right so create the way that we do this is we create a variable called token and we need to sign the token using JSON web token so we're going to say JWT dot sign I do
have a tutorial on just this where I go more in depth in explaining this process more so than I'm gonna now because we just we just focus on this but basically we want to pass in here the user so this
right here okay you can pass any data you want in the token but we want the user now we will get an error if we just leave it like this because it has to be formatted correctly so to do that we
just want to add the two jason method like that okay next we're going to need the secret okay the JWT secret so let's go to our config because that's where I want to put this and put a comma here
and let's add in JWT underscore secrets and let's set that to we'll do our process dot env and we'll call this JWT secret or and then for development just whatever you want I'm just gonna say
secret one it doesn't matter all right so we'll save that and now we should be able to just bring that in but we do have to bring the config file in so let's do that so Const config equals
and we want just dot dot slash config okay so second parameter of JWT sign is gonna be the secret so config dot JWT secret alright so let's see next thing we want to do is also pass in some
options okay actually just one option and that's going to be the expires in and I'm gonna set that to 15 minutes you can set this to whatever you want okay and you could set it to not expire but
let's say expires in 15 minutes now we want retrieve the issued at and the expiration and then we ultimately want to return to the user that's
authenticated the issued at the expiration and the token itself okay so let's say Const we want I 80 which is the issue that the exp and the token and we want to actually I'm sorry we don't
I'm not getting the token here it's open we already have right here but these we can actually get from doing JWT dot excuse me decode and just pass in here the token all right and then like I said
the final thing is to res dot send to the authenticated user we want to send the IAT the exp and the token itself and that should be it say respond with token okay so that's that's what we want to do
so let's save this and let's go back to postman and let's try to log in with something that doesn't work just to make sure that still works and we don't get the token so we'll send okay
unauthorized now we know one two three four five is correct so let's send and now we get the issue that the expiration and the token now right now this token is pretty useless because we don't have
any protected routes so let's go ahead and do that and that's that should be it so I'm gonna show you a couple different ways first thing I'm going to do is go to index J a sour entry point and I'm
going to basically say I want all routes protect it except for off okay so to do that we need to bring in we need to bring in what is it we'll call it R JWT and set that to require and this is
going to be the Resta fie GWT – what is a community I keep forgetting that community and what we can do is go we go let's go right under the middleware and let's say protect
routes okay so we can say server dot use and will say RJ WT and this is going to take in an object with the secret okay so we want to say secret and then the secret is in the config file so we can
say config dot JWT secret and then we want to tack on to this this first after this first parentheses we're gonna say dot unless it's the put an object in here unless it's the path and then this
takes in an array and we'll say slash off okay so unless it's the auth endpoint it should be protected that's what this is saying so let's save this and let's try it out so if I go back and
let's go to the first one we did which is the get request to get all customers and I send we get invalid okay if I go to let's see which ones this I want to go to this one right here where I can
get a single actually no I don't let's try to add a customer which is I know this is a little confusing so let's add a customer will say John oops John Doe
John will do no balance alright so if we try to send we get invalid okay so nothing's working because we haven't included the token so what I can do is go back to the author out I'm just gonna
send it again just to refresh and get a new token and I'm gonna grab it so I'm going to just copy this okay and then we're gonna go back to the customer's route in the headers I'm gonna add
authorization and then it since this is a JWT token we need to say JWT space and then paste the token in and then I'll send and now it works okay because we're authenticated we got the token now in
your front-end framework like let's say you're using react when you want to access any of these protected routes you have to make sure that you send the authorization header with the token okay
you log in you know you'll create your interface you're logging interface you'll get the token back you'll usually store it in local storage and then you'll send it along to any protected
routes and that's how that works and if you want to check out my myrn stack course on udemy that's that's what we do okay we don't use Resta Phi that we use Express so let's try to add add a
user or add a customer so we need to use the token so I'm going to just add in here authorization and pass in JWT space paste the token in and send and we got a 201 back so I'm gonna go back to the
other tab and send with the token and you see that John Doe has been added all right so that's one way to do it and you can add more routes in here but if you want to just let's say you only
wanted to protect a couple routes what you could do I'm gonna whoops I'm going to comment this out and I'm gonna copy this are JWT and let's say we only want to protect the the add update and
delete of the customers so I'm going to go to a customer's route and paste this in this are JWT we're also going to need the config so actually I'm going to put this let's put
this up here and let's bring in the config because we're going to need the secret so const config equals and it'll say dot dot slash config and then any route we want to protect like let's say
getcustomers we don't really care about get single customer we don't care about but add customer let's say we want to protect this row so what we can do is go right after the endpoint and before the
callback and just put in here RJ WT and put a comma here to separate that so basically it's just the second parameter now and we want to pass in here an object with the secret which we can get
from config dot JWT secret and that should protect that route so I'm going to copy this and I'm going to do the same thing for update so right here I'll paste that in put a comma and for a
delete I'll paste that in put a comma so whatever route you want to protect you simply add that piece of middleware alright so now let's go back and we should be able to get rid of this off
authorization header for the get request and it should work okay so that works now if I go to add a customer so this is the add customer let's say I want to disable the the token and try to add a
customer let's say like Mark Smith and we'll say mark alright so if I try this without the token I get invalid but if I go back and I enable the token the authorization and I send we get 201 and
if we go back and check mark should be added alright so that's how you can protects individual routes so you can do it either way if you want to do it this way by saying you know dot unless it
just depends on how many routes you have that you want to protect all right but I think that's it guys so we now have a full REST API with authentication with JW JSON web tokens so you could build a
front-end to this that may be something you want to look into it may be something I'll look into you know maybe I'll build it in react or view or something like that but that's going to
be it thanks for watching hopefully you enjoyed this two-part series and I'll see you next time
In this part of the project we will implement the user model and authentication with JWT as well as password encryption with bcryptjs
Code:
https://github.com/bradtraversy/resti…
💖 Become a Patron: Show support & get perks!
http://www.patreon.com/traversymedia
Website & Udemy Courses
http://www.traversymedia.com
Follow Traversy Media:
https://www.facebook.com/traversymedia
Posts by traversymedia
https://www.instagram.com/traversymedia