Adding User Signup | Creating a REST API with Node.js

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome to this video let's continue building our restful service with no js' and in this video I want to start adding authentication so that we can ensure that certain resources on our server are only available to users who are logged in now of course one important question will be how we actually implement authentication in a restful service because it's different to your normal node.js application you might have written and I'll have a look at this and then of course actually implement it in our project in this video so let's start let's start by first understanding how authentication works in a restful service as we are building it so we get a client and a server and remember a client is for example your web app your building so the front and facing the client facing web app which you might write with a framework like angular react or do or with an vanilla JavaScript or any other client could be a mobile app that connects to a back-end to also have a data layer to be able to store data and fetch data these are your clients I talked about them earlier in this series so make sure to go through all the earlier videos too so that's our client that's our server now we want to log in and for that the client is going to send some off data to the server with off data I mean email address and password of a user if we have a typical email and password of indication flow on the server we then if we're signing up we can then store this data in the database by hashing the password and storing it and so on or if the user is logging in because you already did sign up in the past then we would simply check these values on the server so we would verify if the user who's sending us this data actually has a valid account for this given data on our page so this is what we do on the server and then we return something in a normal node app that would be a session but in a restful service it can't be a session because remember restful services are stateless they don't save any information about connected clients at least not like this we don't care about whether a mobile app or a web app connected therefore we don't use sessions and we also can't use sessions because some clients might not even support the idea behind sessions say a mobile app might not support a session or for example if we connect to our API from an aviary I so from an average which runs on a server then also sessions wouldn't make any sense so we're not connecting through a session or we're not building such a session instead what we do is we will actually returned a token now a token essentially will be some object some piece of data that will actually contain some signature so that we can verify on the server if it's a Bella token so that we can't fiddle around with it on the client and some information about the locked and user and this token can then be stored by our client and can be used to be attached to future requests so that whenever we in the future try to access something on the server which we want to protect we attach that token which we received from the server we can then verify this token on the server because of the signature which is attached to the token so that we can see that it still is - token we issued and it hasn't been messed around with and once we got that verified we know you got a token the token is valid so you may access this resource and this is how how authentication works here we work with these tokens to not store the information whoever you are allowed to access something or not on the server but on the client but in a way that we can always check if it's valid on the server that's of course important otherwise anyone could send us a token and if we just check if a token is there then this would not be very secure but by being able to verify this token well it is actually pretty secure let's have a closer look at this token though so this token is called a JSON web token typically or typically we use this format to be precise because it simply is just adjacent data object in the end where we can add some information like the idea of the user or the email address of the user who is signed in and some signature so these two pieces are important it also contains data about when the token is going to be expired and the issuer of the token overall all this data which we put together into a token makes up this JSON web token which we return to the client now the important part is what I mentioned earlier we can verify this signature and therefore the validity of the token on the server and if we may add something to the token or try to fake the token we could find out that it is not a valid token on the server because we use a private public key combination and only the server knows the private key so only the server has both keys it needs to in the end validate this token one important note though the token is not encrypted so once we've got it on the client we can actually have a look at it we can extract the data from it but as I said if we try to change it well that doesn't do anything we can still verify it on the backend so this is how this token works and what we do with it or how it is structured now thankfully we don't have to build a token on our own if you want to learn more about the token though you can you can simply dive into the video description where you will find more information about the token but I'd say let's stick to this right now and let's actually implement authentication with JSON web tokens in our restful service so let's add authentication and to add authentication we need users right so I'll first of all create a new model and I'll name it user J s because here I wanted to find how a user should look like in my app I'll then copy the order model let's say just because I'm going to use the general same layout I'll rename order scheme add user schema though and I'll rename my model from order to user now the fields here will also vary of course we got our ID but I don't have product and quantity here instead here I want to have my email let's say and there I'll add an object which is of type strings or which says that it should be of type string and also that it's required so let's set this to true and I want to have a password of course password also will be a string and also is required so these two fields need to be given or need to be there if we create a new user model now we can revisit this later to also add connections to products or orders but for now let's keep it simple and let's focus on the authentication so this is how a user should look like now I also need routes for the user so add my user dot JS file here in the routes folder and I'm going to set up the routes file file in the same way I did for the other routes so I'm going to copy these imports from Express router and Mongoose and put it into my user J's file and then at the very bottom of the file I'm going to export my router with the module exports syntax now in between will create their user related routes and for now I want two routes sign up and sign in you might wonder what about logout well since we don't store information about the user on the server we don't store the information wherever the user is locked in or not we can't lock the user out what would we do we there is nothing to delete there is no session we need to clear or anything like that so we don't need a logout route so let's create our first route then and that should be a post route to create a new user and I'll simply name is slash signup that will be my path overall the path will be user slash signup but I'll load these routes just as I load the other routes from within app chess by importing it here and then using certain prefix and then pointing to the routes file but that will be the next step now for now let's simply create our signup route here of course we create the routes just as we did in the our files so I'll add a second argument where we get the request the response object and this next function we could execute if we were building a normal middle where and then here now the goal is to create a new user now let's see how we can do this first of all I'll import the user model so I'll trade a user constant here and I will require it from my models folder and there from the user file now what we can do is we can create a new user by creating a new constable case user and then this will be a new user now this is just as we for example create a new product to write there we create a new product using our product mongoose model now to the user we can pass a javascript object and now there are a couple of things we needed to create also keep this in mind we created an ID and then we assign the different values so I'll copy the ID value from the products route because we create the ID in exactly the same way with the Mongoose types object ID helper method here but then remember we had two fields here email and password so what I'll do is I'll add email and password here now why of course need to be populated and I will assume that we will get these fields from the incoming request so we can say the email is request body email and then we can also say the password is request body password now this pattern or doing it like this has one major extremely bad security flaw do you see which one which flaw I mean well we store the raw password in the database now let's consider or let's assume that we get the password via HTTP that in the end we host our app why I HTTP still still at that case we would get our password through an encrypted and protected connection but we will store it in plain text form in the database and if anyone ever gets access to our database be that an employee or an attacker of our website then all our user passwords are going to be readable just like that we don't want that so we need to encrypt our password we need to hash it and for that we'll use a package we'll use node be tripped Jas now github link can be found in the video description and yentas is just a package that will hash our password and hash it in a secure way that also can't be unhatched so to say or can't be translated by using dictionary tables I'll come back to how exactly this works in a second so here on this page you see the installation instructions on how to use it I'll copy the install command here and shut down my server and run npm install bcrypt I'll also add - - safe to add an entry to package.json this will now install this hashing library which I will use to do the hashing for me now we'll take a couple of seconds you might see some errors in between us I do here but it should be able to recover from these and fall back and finish without an error in the end then we can restart a server with NPM start now we see how to use it here and I will simply use that hash method here so this is how we do hash our passwords I will import it first of all import decrypt by requiring be tripped like this and then the password should be stored using this be crypt library and there the hash method now the first field here is request body email so that will be the password I want to hash in plain text form and then we have these salt rounds now what the salting mean here well the following is the case if we hash a password theoretically that is safe because you can't reverse a hash you can't translate a hash to the plaintext value it's a one-way operation and if you wonder how we then are able to verify if a password the user enters on sign-in is the same password we store the database I'll come back to this so in general it's non reversible but if you get this hash in the end which is just a random string and you would Google that hash chances are high you would find a translation to your plaintext password why because every plaintext string has a clear unique hashed version of it with the hashing algorithm getting used here and that means that so-called dictionary tables exist these dictionary tables are in the end just what they sound like we have plaintext values and the hash value for it so if your user has a very elaborate password of course no translation might existence actually a dictionary table but if your user uses something like ice cream chances are this translation does exist so if anyone gets access to your database they might still be able to get the plain text password from such a dictionary table the idea behind salting is that we add random strings cue that plaintext password before we hash it and then the strings that were added are also stored in the hash by doing it like this googling the hash won't lead to the plain text version of the password simply because the plain text version contains a random string and we don't have hashing tables dictionary tables for all kinds of random strings and that is what salting does and here you defined a number of salting rounds 10 is considered safe and with that we make sure that our passwords can't be looked up in dictionary tables and then we add a callback here this is a function where we as you can see documentation ebrill get an error or we get the hashed password so we have these two arguments and then we can check if we got an error here then we want to return a response where we send status code 500 and a JSON object where we maybe set an error object which contains our error so then we simply know okay this failed we don't have a password we couldn't store it in yet we couldn't safely hash it otherwise if you got no error then we have a hash password and this can now be stored in the parent in the database so what we need to do actually is change our code we don't assign this to password because it's no synchronous operation instead here this bcrypt operation is what we execute first and only if we make it into the else case only in this case we'll create a new user but then in the Al's case we got a password value and that will be the hash so this is how we now can generate or create a user with a hash password now if we half the user here then we can call users safe to save the user in the database and then we can again chain then here so just like we did for products but we also have then and catch too well do something with errors or with success cases so if we are successful we get back a result and there we probably want to return a response where we will be don't need to return even can just say response status web status 201 because we created a resource and then Jason where we could have a message where we say user create it something like that and we can also catch any errors of course and in such a error case we can do what we always did we can simply maybe log it to the console and return it so like this and let's also log our user in the result in the success case to the console so that we can see what was created here and with that if we save all of that we got our user creation to sign up route now let's test it and for that I'll go to my app J's file and in there I'll first of all imported so I'll import user routes by requiring dot slash API routes user so just like I do it for Diablo routes and then I'll go down there and also forward any requests going to slash user slash something to my user routes with that setup we should be able to reach that route with a post request now let's try it out in postman so here I am in postman I prepared my request post request to slash user slash sign up now I need to attach a body which is now not form data but a raw body of type Jason let's create such a Jason body and if you have a look at our route then you see we try to extract the email here and of course web Stetson error here for the password we should also use body password of course so password and email these are the two fields we'll need so let's add them here let's add an email test at test comm and let's add a password so password like this or maybe tester something like that and let's now try it out that's it's sent and I get an error because I need to set my head or a content type application Jason let's now try again and now we get user created as a message here and if we have a look at our terminal here where we do log something we see a user was created and this is this random hash I was referring to so this is now our password in the way it was stored in our database and this is now not possible to look up with dictionary tables so this is now the user we create it on our server so now we're able to sign users up there's one issue though if I were to send the same request against I hit send again then the user is created again so now we created two users with the same email address and chances are that you don't want that you want to ensure you only have a user with an email address once in your database so what can we do about this well we need to check if the given email address is still a whale in our sign up route so before we hashed a password and try to store the user let's do something totally different let's simply use the user model we import from Mongoose from our Mongoose model and find a certain object where we search the user entries for an email address where email is actually request body email and now we'll exit this to get back a promise and add then and catch now here in the den block I'll get my document so my user in the end and here's the part where we will have issues if user exists so if user is not knowledge or if user is not now I mean so if it's not false so if we make it into this if block we know we have a user and in this case I just want to return a response where a sends status code cheaver now we could use 409 which means conflict we got the request we could handle it but we got a conflict with the resources we already have or 422 which means unprocess about entity which also pretty much means the same we got requests we could theoretically read we understand the request but we can't process it pick the one you enjoy I'll use 409 even though you don't see that this often now this is the error core a code I returned here and I can also attach a message where I say mail exists something like this with that we won't continue in all other cases here we will continue and I don't even need to catch block therefore however of course we should continue inside this then block here so that is where we should then try to hash our password and do all our other stuff so I'll cut this and put it into this else block here just to make sure that we only execute this if we don't have a user for that email address and now if we saved us all and I send the same email and password combination again I get the mail exists error and if I send a different one like test two I also get mail exists why because remember if you use user find like this user here is actually not going to be null if you don't find entries it's going to be an empty array so instead what we should check here is if user length is greater or equal to one that means we already have that email address and for other lengths like zero basically we want to create a new user so now if I save this and set this again we create the user but if I send it a second time we get mail exists so now this is working as it should obviously we now have the issue of having one wrong user entry in our database because we created that first email address twice or maybe you pressed the button more often so we will also need to clean that up and how can we clean it up well we can simply add a delete route here which allows us to all the delete users something we probably want to you have in our application anyways so now I will add delete route here and I'll just have slash user ID and get my request response next function here and in there I'll now use my user remove method to find users where the ID is equal to require to our request parents IDs of what we encoded in the URL and then I'll execute so basically the same what we also do for products and so on here with our delete route and then I'll add up then and a catch block to do something in both cases so then and catch here and if you are successful well that's great umm I don't really care I will just return a response where I set the status code of 200 and then adjacent method where I say message user deleted you really see that it worked and if we got an error I'll use the same error code I have in all my our catch blocks here too so I'll simply put dad into here too now we got a method to delete users now we just need to find out that user IDs and this year was the user of the second test the test outcome user we created so this is the idea I want to delete so let's grab this and let's switch this to a delete request and add instead of sign up this ID now if I sent this I get an error because here I should of course access user ID not ID because we named it user ID here the path tiny mistake now if I sent this I get an error because I copied - comma - so if I remove the comma I get another error would see rest status is not a function oh yeah I should have named this result otherwise we have to rest objects and of course I want to refer to this one so now if you save this it still won't work because we actually did delete it just sending the response didn't work but I will get that message over and over again because we still make it into here because remember if we don't find an entry it won't fail doesn't throw an error so we don't make it into the catch block we just also didn't really delete anything though but this is fine here I now got a functionality to get rid off that user which I don't need so with that we also got to delete route we check if a user email exists before we try to create a new user one more thing we should do is we should go back to the user model and for the email I'll add another configuration which is unique which are also set to true now this can be really deceiving and and strange because you could expect that by setting unique you can basically save this code here you don't need to check whether an email address exists or not right because it's some form of validation just as required ensures that we have to pass this value now for a unique it's actually not the same unique doesn't add any validation on purpose instead unique simply optimizes this field you could say to be searched and to be indexed it can do some performance optimizations by knowing that there will be only one of these values in this field and that of course is helpful to us but it will not validate the values speaking of validation one more thing we can do though is we can add another conflict here to email the match config if type is string as it is here you can add some other built-in validation shipping with Mongoose and you can match that incoming string to a given pattern to ensure that what we're storing really is an email address so first of all distribute is over multiple lines to make it a bit easier to read and then we need a regular expression for validating email addresses now as all pro developers we can simply Google for email regex to find this great regular expression email regular expression discussion thread on Stack Overflow and there if you scroll through you'll find this creating an answer here where we got a couple of demo validation patterns and I'll use this one which should match most cases email address validation with regular expressions is pretty hard as it turns out so let's copy this and now match we'll take a regular expression created with two forward slashes and then simply put that expression in between if we do that we should get an error if we pass something that is not an email address so let's simply save this and let's try it out all first of all stick to my test email address with test free which doesn't exist yet I'll go back to a post request and target user sign up here and I'll hit Send and I get user created now let me remove let me remove the @ sign and now I get an email error validation error and that is actually what I wanted their email address is invalid and we could use that information in our client app and as soon as I riad the @ sign here like this I just get mail exists because it only does exist but it matches our pattern atleast so this is one on our addition I wanted to make and with that we added user signup and the ability to delete users in our routes here now the next step of course is to sign users in and create such a token
Info
Channel: Academind
Views: 168,730
Rating: undefined out of 5
Keywords: node, node.js, rest, restful, rest api, auth, signup, jwt
Id: _EP2qCmLzSE
Channel Id: undefined
Length: 28min 54sec (1734 seconds)
Published: Tue Dec 26 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.