NestJS MongoDB Authentication

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome back to the amazon clone in this video we'll work on authentication in our nest js api with so let's just explain what we'll do in this video so what we're going to do is we're going to implement registration and logging in and the way it's going to work is we're going to have a user send their email and password that they register with the we're going to use the b crypt library and hash their password we'll store that in the database and then when they log in we'll compare their hash password to the password that they enter and if it is correct we'll assign them a jwt we'll send back a json web token so that they can attach that with further requests and we can protect some of our endpoints so the first thing i'm going to do is i'm just going to open up the command line here and i'm just going to cd into the api folder i'm going to cd into the api folder in powershell and i'm just going to install a few of the libraries that we need so npm install be crypt passport jwt at nest js slash jwt at nest gis slash passport so we can see there we've got passport for our authentication staff passport jwt for the json web token stuff bcrypt for the hashing and then we have the nest js stuff for the wrapper over the top of those packages so i'm also just going to run an npm install d for development mode to get some of the types so i can get the passport dash jwt type so we just get a little bit of better intellisense in there so what i want to do is just before we get started i want to open up the main file and just above the app that we're listening to we're listening to the port and we can actually just go app dot enable calls and that's built in on this nest factory object and that just allows us because we'll be making requests from react in a future video probably the next video actually and we just don't want any uh cause issues between the two servers so i'm also going to set a app prefix so i can just run set global prefix here api and this is what this will do is uh it will just add api to the end of our domain so we've got localhost 3000 slash api slash whatever the route is going to be so just a couple of simple tweaks there i'll just go ahead and just save that so what i want to do is i just want to create a few different modules and controllers just a couple so the first thing i want to do is i want to have a user module so i'll run nest g mo user and if we look in the app module it should add that there so we can see that we got the user module and i'm just going to press up because we're also going to have a second module for auth and we're separating the modules out because there's going to be some authentication specific stuff such as generating the tokens and checking the tokens and stuff like that and then there's going to be user specific stuff such as you know getting the user or anything like that validating the user stuff like that and as the application grows it's nice to separate those two out from one another because eventually we'll be wanting more and more user endpoints um so yeah it just separates the logic out into two different modules so we can see that here it is in the app module they've both been referenced here so let's just open those up let's start with the user module so what we'll do is we'll start with the user schema so i'm just going to add a schema here in user and i'm just going to call it user dot schema dot ts and we can just use the schema annotation from this js mongoose so we'll auto import that and then we can just go ahead and we can just export a class here i'll call it user and then we can use the prop annotation to let the class know that it's or the schema know that it's a property and we'll have a name here and a name is nothing more than a string and inside prop here i'm just going to have some additional uh options here so i'm just going to say required is true because we're going to require the name along with the email and password to always be there so let's just change the password which is also a string and well let's say email here and password here both strings everything's required however the email needs to be unique so let's just specify that to true there so what we'll do is we'll export the type as a user document and that's the user class along with the document class and if this is too fast i've actually covered all this in great detail in the previous video um so you know we're not boring you to death with all the details here we'll we'll explain the new stuff but the schemas and documents and all that sort of stuff is covered in the previous video so what we want to do now is we just want to export the schema so we're going to have a constant variable here that we're exporting and we'll call it user schema and we're able to use the schema factory from you know sjs mongoose and then we can just say create for class and we'll go ahead and we'll create it for this class that we just made here and note as discussed in the previous video we're making a document which also has the id version and a bunch of other properties associated with it so we'll get all that so that's the user schema let's take a look at the user controller sorry the user module actually let's just go to the user service first so what i'm going to do is i'm just going to generate a couple of things here so i'm just going to run nest g to generate a controller for the user i don't want a spec file and since we're there already is a user folder here it's just going to put the controller in that root folder there or the user as the root folder there and i'm going to do the same thing in the auth so i have nest g controller in auth and then i want to have a service for both so i'll just say nest generate service auth and then i'll do the same thing for user and we can see that we've got those in there if we just look at the auth module we can see that that's reference there and then if we look in the user module we can see that they're referenced there like that too so let's start by looking at the user service and in the user service this is where we're going to inject our model so in the service here let's just make a constructor so we're able to use that and then of course we're going to need to go to the module to declare that so let me just open up the user module here so i'm going to have some imports here and what i'm going to have going on here's an array i'm going to import the mongoose module so i'm able to say that for a particular feature that we're going to have here which is going to be an array of objects and the object that we've defined here is going to be we're going to call it user and it's going to refer to that schema we just created as the user schema so i'll just go ahead and get that and i'll just put the comma here so with that we have now connected the uh you know the database representation [Music] to the object so now we just need to be able to reference that in the user service here so i'm going to in the constructor params have a inject model here and we just called that user and this is going to be a private it's going to be a read-only user model which is a model which is coming from mongoose i was getting intelligence and then it disappeared and it's going to be based on the user document so we just created this type here which is based on the user class and the document let's go ahead and grab that and then we'll go ahead and we'll import that and then we'll import the model it's not giving me an intellisense so i'm going to import it manually and that's coming from mongoose so go ahead and save that now access to the user model i should be able to use it so i'm also going to just create a quick interface so we don't just return the user document the user document it has the password on it and it also has the version and um yeah the other stuff on it so i'm just going to in user here i'm just going to create an interface user interface dot ts and i'm just going to go ahead and export an interface and i'm just going to call it user here and i actually might just call it user details just to make it a little more specific so user dash details because i feel like user is going to be overloaded pretty quickly so let's just call this user details uh dot interface dot ts and then we can have an id here notice in mongoose underscore id so we want to just use just id like that we'll have a name which is a string and then we'll have an email which is also a string so now that we've got that we can return to our user service that we're working on and the first thing i want to do is i just want to have a helper method um so i'm going to have like a partial sort of function here so i have an underscore in front of it and that just denotes that i want to use it in conjunction with other methods uh it also can be used to signify to javascript that it's a private method because you don't have any real private methods um but in this case it's you know used in conjunction with methods um and that just helps me identify that it should be used in conjunction with other methods so we'll have this helper here so we're just going to take a user document and in return we'll get the user details that we just created and we can just return the id which is going to be the user dot underscore id that we're getting here we're going to get the name which is the user name and we're going to get the email which is the user.email and we'll just go ahead and we'll just save that there so we're just getting that underscore id as an error because we need to rather than using the regular document we need to import the document and we import that from mongoose so let's go ahead and get that and now when we save that we can see that this error has gone away so let's go ahead and continue working on our service here so i think before we create the find users we need to actually register a user so to create a user let's have a async function here so we'll have an async function we'll call it create and let's take the name which is a string an email which is a string and it's going to take the hashed password um so we'll get into that in a minute which is a string and it's just going to return a promise for us for the user document of the user document type and what we'll have is we'll say we'll have a new user is going to be equal to new this dot user model and then we'll just pass in the name email and password which is going to be the hash password and we'll talk about what the hash password is in just a second we'll save that and then we'll go ahead and we'll just return the new user and then we'll just go ahead and we'll click um well we'll type in save there so let's just go over to our auth um service so let's open that up and this is where we're going to begin to work on some of our auth related stuff and we're actually going to need that user service so since we need the user service we're going to need to import the user module into our auth module so if i just go ahead and open up that auth module we can have some imports here we can go ahead and we can import the user module so we got that so let's go back to and we can close some of these up now use a schema we can close user module close maintes will close so we've got this auth module here we've got the auth service now in the user module even though that we're importing the user module in and you'd think that would contain everything in the user module we're going to use the user service in the auth service and we just need to explicitly say that we're going to use that user service in there otherwise it won't work slightly counterintuitive it's just something to remember so we've got that there so let's just close the user module up we'll go back to our auth service and now we'll create a constructor here so we can go ahead and we can create our user service and it's going to be of the type user service so what i'll also do here is i'm going to import bcrypt so i mentioned at the beginning of the video and we need to import or as b crypt from b crit because it doesn't support the named or default [Music] you know imports syntax so and the reason i want be crypt and what bcrypt does is when you save something into a database you save an email and a password usually along with some other user details if someone became aware of our database or somehow hacked into it or got access to it it would be a security breach if they had all of every single user's password so what hashing does is it takes like a password like a string or something like that and then it goes ahead and it converts it into some sort of you know hexadecimal value or whatever it's going to convert it into um just you know a very very long string that no one would ever guess to be the password and it's a representation of the characters that you enter um and only the server really knows how to sort of decrypt that so you're hashing it hashing sort of like a one-way sort of thing unless you have like the details on how to unhash it sort of thing like the algorithm behind it which is uh sort of in the library there's lots of clever things going on there that sort of help prevent that um so but what we can do is when we you know register an account we hash the password but we can also use the same algorithm that we use to hash the password with the bcrypt to when we log in and check the entered password by hashing that and comparing that to the hashed password so that's like a security layer there so i want to have a asynchronous function here called hash password and it's just going to take the password as a string because the user is going to you know just type in their password into a text field and then that's going to be sent an api request that's going to be sent over https so there's should be no bad actors intercepting that and if they do they should get some jargon or jumbled up stuff um so it's only when it hits our server that the server recognizes as a string and then we're going to take that string and we want to return another string and the string with we're returning is you know the hashed uh password so we can just go ahead and we can just use the bcrypt library for it we don't have to you know make it by scratch or anything like that and there's a hash function here if you just hover over it here uh well we're not getting much help there but you just type in the password here and um it's probably a typescript uh type library for that i'm not gonna do it just all's it's doing here is it's got this 12 that's like the salt rounds i believe it's called and it just you know it takes your password and then after one iteration you know you might get something like this or something like that it's gonna be a lot more longer than that this is just to at a high level explain but then the next round is going to take that string and then it's going to convert each of it like this and as you can see as you do that multiple times 12 tends to be like a standard sort of thing there um you know obviously the more rounds you do the longer it takes um but also the more secure it is so 12 sort of like an optimized number there uh there's no way anyone's gonna you know be able to hack through that um at least not to my knowledge um so yeah that's the hashing of the password so the next thing we probably want to do is have the ability to register so let's have a function here and i'll just take cap caps lock off and i'm going to call this register so this is going to take a user and i'm actually going to create a dto for this so in the auth section here actually in the user section i'm going to have a new folder so where is that new folder and i'm going to call these dtos so i don't think we touched on dtos in the previous video but basically it's the data transfer object and if i just create one it will probably become clear what's going on so i'm going to have a new user dot dto dot ts and i'm just going to export a class here i'm going to call it new user dto and when you create a new user it asks you for your name on amazon it asks you for an email which is a string and it also asks you for a password which is a string so basically basically what this if you look at our other user in the user schema you see that we've got the name the email the password so it might look the similar but it also is a user document so it has all the other properties and stuff associated with it and the other thing to note is when you log in for example you only need the email and password so you want to send a different object or data transfer object so in that case would have something like existing user so we'll just go ahead and copy that and it's just going to be the exact same thing but instead of new here we'll have existing and instead of name we can just go ahead and delete that so in different circumstances you can send different data across um so you don't have to use it in show it's just a nice way to do things so the reason i brought dto up is because when we come to this user service here or this auth service we want to use the new user dto and we'll actually use typescript typescript has a read-only um pipe here i believe it might be lower case read only so that's a typescript type and that just makes it so that we can't change the properties because we don't want to change what the user sent to us this just sort of enforces that so um yeah so we got that so when i user user does register you know it's going to be an asynchronous operation so they'll get a promise back and i want to give back the user details and remember the user details was a subset where the [Music] password was removed because in this user service here we had this um well based on user document you can get the user details which is just the id name and email which is what the interface represents so and it'll probably make more sense what this create method's doing as well um but we'll come back to that in just a moment so when you register you get back the user details but that's only true if they register successfully otherwise what i'm going to do here is say you get back null now i'm using null and i'm going to use null for a few of these methods i'm doing in this particular video because i haven't set up error handling yet and we'll do that in another video but just so the server doesn't completely crash on us i'm just going to return null so what we can do is we can just use some object destructuring here and we can just say we want to get the name the email the password and we can just get all those from our new user dto here and i can also go ahead and create a variable called existing user and what i'm going to do here is i'm going to actually when we register a user we need to see if there is a user already existing with that email so i'm going to come back to the user service so remember the user service is where all the user stuff's happening everything related to the user document model and then auth is where all the authentication stuff is happening so you know logging in registering hashing the password json web token stuff and the user service is where all the user stuff is happening so getting the user details creating a new user i'm also going to have the ability to find users so i want to be able to find them in two different ways the first way i want to be able to find a user is going to be by email because that's what i want to check from that method i'm creating an auth so they're going to pass in their email and password and then based on their email what we want to do is we just want to return the user document so we want to return and use the document because we'll need to look at their hash password and then null for bespoke reasons and then i'm just going to go ahead and return and we got the user model set up so i'm just going to say find one which is a mongoose method which takes options and i can pass in email and i can just go ahead and i can run the exact command here so while i'm here i may as well create the method to find by id because we're going to need to use that shortly anyway so we'll just come here we'll say id now id is a string as well now in this case we can just return the user details because or no because we won't need the the password so in that case so i'll just go ahead and i'll just say we'll have a variable here where we'll just await and we can actually just use our method that we created um oh sorry we're going to use the user model and then we're going to just find my id here and then we'll just run exec on that and basically what we'll do here just for now until we do better error handling is if there's no user we can just go ahead and return null and otherwise it will make it past that check and then we can just convert it to get the user details and they'll remove the password for us and then also the id and version and of course we'll just need to pass in the user into there and save that and now we can just go ahead and we can return to our auth service and so we're registering an account we passed in the name the email and the password we want to check if there's an existing user so we can go ahead and we can just await and we can use this user service and we can just go ahead and we can just find by email and just pass in the email because we don't have the id so we need to find it by email and then we can just have an if condition here and if there is an existing user what i'll do just for now until we get better error handling is we'll just say uh email taken so that's cool um i guess technically we need a string here as well um so actually i might just change this to any just for now so all right let's say we get past there's an existing user that means the email is not taken and that means we should be able to register our user so what we can have is we can say we can start to hash our password so they pass in the password as a string we can just say we want to get the hash password and we can just go ahead and we can just await this hash password which is just this method here which cause b crit with the 12 salting rounds it changes it to a bunch of scribbled up text that we can't go backwards on and that's what we're going to and we do that because that's what we're going to store in the database so what we need to do here is we just need to create a new user and we can just await and we have that create method in the user service there so i can go ahead and just pass the name email and it's important that you type in the hashed password here and that's why it's slightly different to the new user dto because this is a hash password rather than a password you could create an object in the interface for it if you want i don't find it necessary here so just looking at the create method you get the name email and hash password and it's going to use the user model that we have access to and it's just going to create the [Music] you know the new user and it's going to save that to the database and that new user that we wait for we can just go ahead and we can just return that but we don't want to return the password back to the user so let's just go ahead and use our helper method here to get the user details based on the new user here so with that we should be in a good position to be able to register well we have the server set up to do so at least so perhaps we should have a look at the controller and if we open up the controller we can go ahead and we can just create a method in here so we're going to need that service so let's just go ahead and say for the auth service auth service and we'll just go ahead and we'll import that in if we'll let me so i'm going to use the post request to register and i'm just going to have a method called register where in the body what i'm expecting is a user which is going to be of that new user dto that we defined and in response what we'll get is we'll get a promise here and it's going to give back the user details or no until we get some better handling going and we can just go ahead and we can just return this all service and we can just go ahead and register that particular user that got passed in here so i just need to remove the method outside of the control constructor some reason i didn't pick that up before and then we can just go ahead and we can get the user details type in so let's just grab that interface there let's just separate out our stuff our imports so yeah we can hit the controller where it's expecting the new user dto which is the name email and password we call the auth service register method we look in the method here and yeah i mean it's doing all the stuff we set up so let's just run npm run start dev i've already got my docker container running if i just create a new uh powershell here i can just do a docker ps to confirm that and we can see we've got our express and later so that's still running from before if not from the root pro of the file folder you would just have to run a docker dash compose space up space dash d where the dash d is optional to for the detached mode but let me just close this if i refresh the amazon database we can see that we now have this users table or this user collection so what i'll do is i'll just view that there's nothing in it but if i go to postman here and i go to register and i register something here we can actually see that we got back the id the name and the email so it doesn't give back the password so that means if we look into our let's just refresh the our schema here or our collection we can see that we've now got this document here and we can see that we've got the id we've got this password which is just you know scramble it's not hexadecimal actually looking at it because there's queues and stuff in it letters past f but it's just a big string of characters there um so it doesn't store our password directly in there and then of course has the version and the other details there so let's just go back there so that's awesome now if i was to run that one more time you will get email taken so obviously we want to have better you know error handling there um but it does the job and it doesn't crash the server so that's a plus all right so now that we've got the register method going let's go ahead and get the login method going so for the login method i'm just going to come to auth modules because we're going to need the json web token module so what we'll have here is we'll just take the json web token module from nest js json web token here and then it has a method on it called register a sync and then from there we can just go ahead and we can use the factory method and with that we can just go ahead and we can just specify what we want to return here so we want to return objects so we can just say in parentheses the object that we wish to return now i'm going to type in the secret here and i'm just going to have a secret and the secret if you're not familiar with json web tokens it's just when you create it our json web token in addition to our payload or the contents in the object we want to have some sort of secret and also have a salt associated with it so the algorithm in which the json web token scrambles up um all the letters you know can't necessarily be replicated so if i'm on another machine i couldn't just you know guess the json web token sort of thing uh and back engineer it um so you can also just go to jwt dot io they have like a quick one minute visualization of that means if you're not familiar with that but i'm just sort of assuming that you've used json web tokens in some capacity but if not do go to jwt.io so you also have the sign options here and i should note that this secret here you could reference this from if you had a dot env file you can run process dot env and then whatever the variable is called say jwt secret and have that set up i did do that in my linkedin project i'm not going to do it in this particular project and there isn't really any security issues with this approach because it's on the server anyway but just for that extra layer if you want it you could run that i just thought i'd mention that and i'm just going to have expires in and i'm just going to have 36 100 seconds so it means the json web token will last one hour so 60 seconds times 60 minutes is 3600 seconds or something like that so since we have that jwt we can now use the jwt in our auth service so let's go have a look at our auth service here and we've sort of done the registration and the hashing and the password so let's begin to work on a method here so i'm actually going to create a couple of helpers um so i'm going to have an async function here and i'm just going to say does the password match and i'm just going to have a password and the hashed password which is a string both strings and then there is some asynchronous behavior that's happening for this bcrip library so i'm just going to return bcrypt here and there's a compare method on it and we can just go ahead and we can just type in our password here with our hash password here and that just does take a little bit of time and returns true or false if the passwords match you'll return true otherwise it'll return false so the idea is when the user types in their password and they send it across we can you know if we have access to the hash password which we have access to when we'll validate the user um you know we can compare the two and see if they match and of course if you're on someone else's server or something like that um you know the hash isn't going to be the same on their servers it will be on our server so even if you i don't know know the password somehow um if you're looking at the database and you're looking at the hash passwords it you can't necessarily map one to one because you got that um you know i've got some of this password hashing here it's got the 12 rounds and it's also got the secret associated with it as well so the algorithm takes all those into account and you'll get some sort of hash password so i'm just going to you know before we log in we need to validate if the user you know is a real user and if their credentials match so i'm just going to have a method here which it takes the email which is a string and it also takes the password which is also a string and then it's just going to return back a promise and we'll give back the user details which is the user document with the um you know the version and the password omitted and we can just say return that or null and so what we'll have in as our logic here is we'll create a constant variable we'll call it user and we can just await this user service and since we have that find by email method we can just you know they're trying to log in now so you know we can see if an email exists and in this case if the email well what they'll get back here is um you know they'll get back a user if it exists otherwise they'll get back something like null or a nullish variable a falsie variable so we can have this other variable here we'll say does the user exist does user exist and we can say that's equal to not not bang bang user so the first bang um it tells you like it's if it's a string um you know well actually what we're expecting here is an object so the first thing is is it not defined so then if it's not not defined it means it is defined so it just takes any non-falsie value and returns a boolean so that's just like a little not a hack but just a little trick to tell if this exists otherwise would be null because it was now not now not not now the user uh doesn't exist which is in this case here and then if it doesn't exist we'll just go ahead and we'll just return null um but if it does make it past there what we can do is we can say okay well the email exists now does the password match so we can just go ahead and we can just call we can have the variable here does password match and then we'll just go ahead and we'll just wait for this does password match and then we'll have the password in here and we want to um so the password that they entered is the first variable or the first argument and the second argument is the hash password so when we get this fine by email we can see that on the user service unlike the id where we're changing it we're just going to get back the user document which actually does have the password on it so because it does have the password on it and it's set up like that on purpose we can use that password and remember once they've you know in the database sort of thing it's going to be the hash password so this compare function it essentially hashes this password with the same algorithm it compares it to the existing hash password and if it's matches it will it'll return true otherwise we'll return false so we can just do another check here and actually i can just copy something like this here and if the password doesn't match i'm just going to return null but if it makes it past that it means the passwords do match that means i'm able to use the user service and i'll just go ahead and return the user details here and we'll be able to use that in the next part so the next part is logging in so that's what we've been waiting for so we have an async function here we'll call it login it takes an existing user which is of the type existing user dto which is just an email and a password that we created before and it's going to return a promise here now i'm going to have this type here i'm going to write it in the return type here it's an object which has token here and a string or it's going to be null and what i can do here is i can just use some object destructuring to get the email email and password from the existing user i'll just go ahead and save that pretty will help me out a little bit and if i just get the user and i get that by awaiting this dot validate user for the email and the password so just recall we made that just before just um so you go to login the person sends the email and password then we validate that if it makes it past all the checks we'll get the user details but if it doesn't we can just say we'll just return null and all these returning nulls we want to handle better with error handling but um we'll get to that i do have a video on that as well um but i'll probably get to that later in this course anyway but if we do make it past there this is where we can await our json web token so we can just say this json web token service so actually i think we need to import the json web token service here so we've got this set up here we've got the jwt module set up so what we can do is in the constructor here we can just reference the jwt service which is the jewt service and we imported that earlier so we can come back to our login method so we can use that service and on that service there's a sign a sync function and you just pass in the user so we're getting the user here which has the you know name email password and they're the same properties that we're going to check that we're going to sign so it doesn't have sorry it doesn't have the password on it it has the name and email um and the id and we're creating a json web token which takes that object uh and it changes the form of it um into the json web token such that we can attach that to further requests and then when further requests are made our server will detect the json web token and if it matches and is valid then we can go ahead and make those requests so we'll take a look at guards in just a moment but just to you know end this function here we can just go ahead and just return the json web token as an object there so now we've created all of the logic for that we can go ahead and we can go to the auth controller and we can actually begin to work on the login method and let's just copy this post down there's also going to be a post and let's hit the endpoint slash login or and let's have a method here called login now one thing to note when we made this http request before we're creating this resource and a resource created is a 201 status code um and by default nsjs will put that status code there for you however when we log in we're not actually we nee we need to do a post request because we need to have a body with the details and a get request um shouldn't be used for that so we have a post request but we don't actually necessarily are creating a resource so what we can do here is we can overwrite the default status code with this http status code annotation and there's also this http status enum and that has a bunch of the status codes on it so like okay for example which is a 200 if you just f12 into the http stats you can see all the status codes so common ones you're probably familiar with is 404 um and we just want to return a 200. you could also probably do accepted as well um you know it's really up to you how you want to do it um this you know different status codes can be used some are more uh semantic than others but you know it's close enough sort of thing um so you can have a user here now this is going to be the existing user this time so i'll just go ahead and import that and rather than use the details back here we're going to get the token which is a string or null so now we can use this auth service we can go ahead and we can just log in with that user so how cool is that let's go ahead and test that out so i've just created an account with john test.com and the passwords password if i go to api all slash login and i click send here we can see that we've got this json web token here so just to you know i'm going to go to jwt.io just to sort of bring the point home here if you haven't seen json web tokens before but if you have it's a good reminder anyway we can see that this is the default json web token here there's a payload um which is the data it also has the algorithm type it uses and it indicates it's a json web token and then you know has this verify uh signature here so you can put your secret in here um so yeah let me just type in my json web token here so you can see that i've got this user here which is the user id the name the john so that's the payload there it also has this um i a t and exp and i believe this is initialized at an expiry date so if you add 3 600 seconds or it might be milliseconds i'm not sure oh yes it says uh seconds second since unix a poc so you add 3600 to that number and you should be able to get this number here uh often epoch time or whatever is in milliseconds after 1970 or something like that but in this case it's seconds so you can see that the um you know the configuration for the json web token seems to be matched there um and if i just type in i don't know if this will work if i type in secret here notice when you type in something like any other characters it changes this part of the token so only this token uh this entire token but with this bit here there as well will be accepted by our server so even if you had all the other details right but the secret wasn't the same uh it won't work and a secret's on our server so they actually have to send the body the payload to our server you know there's this header algorithm which just says what type it is and stuff like that as a jwt um but really it's this combination of the three that allow for the security to be so great uh i mean obviously if you dive deeper and deeper into it there's arguments on both sides json web tokens versus sessions and what's more secure and all that but really the end of the day they're both pretty good um you know no one's gonna hack you with them uh most likely so you can you know feel secure so now that i've created the ability to register and log in i mean that's already a huge step that's the main goal here but when we log in what we want to do is we also want to protect a resource so for example the product let's say you log into amazon.com you log in you have to log in to be able to like i don't know if you want to post something like sell or product or something like that um you know you should be logged in to be able to do that i think i don't know if you can buy stuff if you're not logged in or maybe you need to be logged in because you need to have all your details and stuff like that um i'll get into the front end after this video actually so i'll start to look at the site a bit more and you know tee it all up but um essentially what i want to do is just protect an api endpoint in general so to be able to do that i just want to add a couple of things so in auth here i want to add a folder here i'm going to call this guards and i'm going to have a jwt guard dot ts and what this is going to be is this is actually going to be a service um so i'm just going to copy this bit here um it's a service but you know it's a special type where we're using as a guard but it is just a service so i'm just going to get the injectable in that's what i really wanted um the other thing i want to do is just rename it to jwt guard so the class is jwt guard so it's a very very small service here and the reason it can just be like this is because you know with object-oriented programming you can extend classes so i just want to extend it so then we have access to this guard here that we can apply elsewhere so we can just extend or use extends auth guard and that's coming from this js passport and there's various implementations you can have here so i'm going to have the jwt here the jwc strategy i believe um so that's all we need to do to have the jwt guard so it's quite simple it's all set up for us basically but we will need to have another file called jwt dot strategy dot ts now i'm also just going to copy this because it's a good starting point here and i'm just going to close this up so i'll get rid of the auth guard here we no longer need to extend it but we just need a service here i mean it's slightly easier than generating it and i've already got the server running um but this is going to be the jwt strategy in this case uh we don't want it from there actually we do but not no no no we don't want it from the test section we want jwt strategy by which extends passport strategy and that takes a strategy from passport jwt here so we've installed that so okay i should probably go to the auth module and in the auth module i just need to say that in addition to the auth service providers because these guards and strategies are services we can use them here in the providers so we've got the ge jwt guard import that and the jwt strategy and the good thing is when we import this because we've got this jwt module uh hold on use the module so the good thing is since we've got this jwt mod module and then we're importing the jwt guard and jwt strategy there's lots that's set up for us so based on the jwt guard here it employs a particular strategy uh and then through the module and these files here it just seems to join it all together for us so it makes it really easy for us to create the guards because the guards are already created we're just sort of using them let's say but we do need to just do a couple of things in here so the first thing we want to do is we need a constructor and the reason we need a constructor is because we need a constructor for the base class so we need to actually call that constructor so to be able to do that we need to call the super method inside the constructor and then we just pass an object full of properties so essentially that's just saying for our jwt strategy that we're using in combination with our jwt guard and module um the base class that we're extending needs a couple of properties and then all of the configuration stuff sort of done for us but we need some sort of well there's multiple ways to do this and we need some sort of a couple of things we just need to put here so the first one is the jwt from request so what this is here is we just want to um basically what we want to do is whenever we have a protected route that route that we're calling as the end point we're expecting the token the json web token to be part of the headers so when the user signs in on the front end the token that got sent back to them is attached to all of the future requests that they send so we can actually call this method here extract jwt from passport and then we can just run from auth header as bearer token and that will do that for us so when it comes back to our server it's expecting it on the bearer token or from the header and you know if it's valid and then it will just work sort of thing so we can also have this other one uh ignore expiration and we can set this to false because i think by default it's true uh and if it isn't you know it's just you know an extra line here but i believe that even if you create a json token and it expires in 3600 seconds or an hour uh it might still work unless you have this extra option here um so the other thing we need here is the secret or key and we in our uh app module i believe no not app module or the auth module our auth module where we set the jwt up we had this secret here um and you could have that in an environment file as discussed before but you know we won't do that i've done in that other video as mentioned um and i might have another series where i go through some sjs techniques and stuff like that so rather than doing a big project i'll color all the details but i don't know that's just something i'm thinking on the side uh for now uh and it's all secure anyway so it doesn't really matter but um you could have process dot env dot the jwt secret here it's just i got docker set up as well so there's a couple of extra steps um it's not too hard but i just want to focus on development um so it has the secret as well so basically we're just saying where we're expecting it from so we're expecting it from the header um what is the secret so that secret needs to match um what we're doing so the secret's called when we create the json web token but then when we also verify it or we have a guard that needs to verify it we need to make sure the secrets match um so you need those properties and then this is sort of an optional one where we want to ignore expiration or we don't want to ignore the expiration so it's pretty simple really it's just um you know calling a super or constructor of a constructor basically uh of the base class um but there's just one more method it's gonna be super easy because the whole thing is that this class that we're extending it has a uh method that we need to enforce and consume from our this extended class here and that's validate so basically what's going to happen is somebody's going to send a request um and it could be any request because it could be hidden any other endpoints so we have a payload here and it's okay to call it the any type um because we're really expecting anything any type of object or you could have a generic i suppose um but we'll just it doesn't really matter because we're not really using it anywhere and what we'll do is we'll just return the user from the payload so what's happening is a user sends a request and a user sends a request um and they're going to have a like on the payload the the user object will be there and when we validate that the json web tone token is correct we're only really interested in the user details so we'll just go ahead and get the payload and get the user on there and return that object there so yeah that's the setting up of the guard so let's all we really need to do now is just consume the guard somewhere so we've got this um when is a good spot to put it we've got this um product controller here so let's just go ahead and um and we've got this token here as well um i want to when we created um i'll create a new user here when we created that we got the id so i think what i want to do is i want to have a user controller to be able to get the user so let's just start on that so we've got it's going to be really simple um i just want to get that so then i can get some information there so we'll just have the constructor and we'll just go ahead and we'll inject the user service which is the user service and then we'll just close up the close code block there now we're going to have a get method and we want to be able to get the user based on the id so we can have this async function here and i don't think actually we don't actually need the async function on the controller um so we can go ahead and we can get that as a dynamic variable so slash user slash whatever the id is so you create an account um then you get the id back and then um we can have a param here and then we have an id which is just matching the dynamic part there which is a string and i'm just going to return a promise which is going to have the user details or null so i'm just going to return this user service and we created this earlier the find by id and then we'll just pass in the id here and i'll just go ahead and import this so now for this particular user that we created we'll get that id there uh and then we should be able to get that id so that's cool that's just like a helper sort of function just so we got one function on our user controller we'll end up building that up but you know we've got that separation between the user and the auth stuff there so uh what i want to do is just protect a route and i'm just going to protect the product route that we created in the previous video here so if i just go to product and i open up the product controller and i navigate to yeah this one here i'm just going i'm not going to protect all the routes just yet i'll fix up the protection of the routes as needed um but i'm going to have this annotation here use guards that's built into sjs and then we can just use the jwt guard here so that's all we have to do and now if i make this request so it says that we're not authorized and this is better error handling and that's done for us so that's cool we're not authorized because we haven't attached our token but if we get our token from our login here we can go ahead and we can just go to bearer token here in the authorization tab and then we can just click in and copy and paste our token here and now you can see that we actually do have that so that's how guards work so i'll just recap everything that we've done here today and then i'll just talk about what we're going to be doing next in the next video here so basically what we've done here is we've created two modules a user module and an auth module so in the auth module there's two methods in our controllers we have register and login so registering if we just drill into the method here by clicking f12 we can see that we check if there's an existing user we hash the password if there is an existing user and then we go ahead and we create a new user and the login method here what this is doing for us is it's going to validate that the user uh you know the email and password match and then if they do they'll create a json web token now json web tokens when they're you know assigned and they're going to be assigned to the front end and they're going to be attached to the headers and for further for protected routes we can just go ahead and use the jwt guard there so and protect the route as needed so yeah that's everything i really wanted to cover in this video now if you're interested in role based access control or rbac which is essentially like let's say you log in as an administrator or you log in as a super user or you log in as you know there's different roles and there's different access levels for the different roles there like an admin might be able to do everything let's say but a premium user might only be able to you know get and post products for example but anatomy might be able to edit them or something like that um you need to start looking to roll rbac now i've actually done a video on this already in my linkedin series so if you've watched this one and you want to do that i believe it's the ninth video in the linkedin uh video series um so even though in that series we're using postgres um you only really need the most basic mongoose methods that we've used in this video so like save and find and stuff like that um so it should be quite trivial if you watch that other video to implement it into mongoose based on what we've done here um so i'd highly suggest checking out that video if you're interested in that now we're not going to do that in this particular video series because i've already done that um and i also want to focus more on the e-commerce side of things so you know payment gateways perhaps with stripe and i also want to set up the front end so we'll in the next video we'll probably set up the front end for the authentication pages in react and i want to do it with modern react with functional components and i also want to use the redux architecture so set it up like i'm set up like a big project an enterprise grade project uh and you have the async thunk stuff going on in that redux there in that architecture there with the flux design pattern um so that's what we'll work on in the next video then we'll end up looking at some error handling a little later on and stuff like that um obviously the payment gateway that's the exciting stuff um but yeah i think we'll jump into react for a couple of videos then jump back over to nest uh and just continue that sort of process so i really hope you enjoyed the video if you did please subscribe to my youtube channel and i'll see you in the next video cheers
Info
Channel: Jon Peppinck
Views: 8,930
Rating: undefined out of 5
Keywords: nestjs, nestjs mongodb, authentication, mongodb, jwt authentication, nestjs tutorial, nestjs authentication, nestjs and mongodb, mongodb authentication nodejs, jwt authentication node js mongodb, user authentication, node js authentication jwt, nest.js, node js authentication and authorization, use mongo with nestjs, crud mongodb nestjs, mongodb insert data in nestjs, node nestjs, how to user nestjs with mongodb, bcrypt, jwt
Id: ziyNZjjqbsE
Channel Id: undefined
Length: 82min 49sec (4969 seconds)
Published: Fri Feb 25 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.