Learn The MERN Stack - JWT Authentication

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hey what's going on guys in this video we're going to add authentication to a rest api using json web tokens now this is actually part two of a mirnstack series but i do just want to quickly explain the the current code that we have just in case you didn't watch the first video where we created the rest api so basically we have a crud api we can create read update and delete goals so we can make a get request to our you know api slash goals and we can fetch them right now i don't have any i actually deleted all them but we can also make a post request to add a goal we can make a put request to update and we can make a delete request to delete a goal so that's the extent of the functionality and then this is the folder structure here so in the backend folder we have our server.js we have api goals going to our goal routes which is this folder here or this file here and then we have some functions from the controller that we're bringing in and setting to certain endpoints so slash and then slash id and we have our functions in our controller so here you can see we have get goals which just fetches them from mongodb using mongoose set goal we have update goal and we have delete goal and then we just created a custom error handler as well so that's pretty much what we did in the first video so now like i said i want to add authentication so that not just anybody can come to these endpoints and get get and set and update and delete goals all right now just to talk a little bit about json web tokens and and what they are this this is jwt dot io this is the official site for jason webb tokens and if we scroll down to us this is what the token actually looks like which kind of just looks like a mess but that's because it's encoded but there's actually three different parts and you can see they've color coded them and the first part is the header which includes the algorithm and the token type which is jsonwebtoken is the type and then it includes some data in json in the json format and you can have whatever you want in your in your token in our case we're going to have the user id so it also has an issued at which is the timestamp that the the token was issued at and then it also has a signature which will ensure that the jwt hasn't been altered with or tampered with in any way and the party that creates the token signs the header and payload with a secret that's known to the issuer and the receiver or private key that's known only to the issuer so basically when we have a route we want to be able to protect it and we'll have to log in get the token and send the token and the headers to access that protected route okay so that's what we're going to do in this particular video and then in the next video we should be able to start on the front end so let's first let's first create in models here since users is going to be a new resource we're going to create a new file in models called user model.js and if you watch the first video you know that in here we put our schema and all the fields that we want to a user to have we have to bring in mongoose which is our um our odm to interact with with mongodb and we can also use it to create our schemas and models so let's bring in mongoose and then let's create a user schema basically the fields that we want a user to have so we set this to mongoose.schema we want to pass in an object here and then add our fields so as far as the fields go we're going to have a name and we're going to give that a type of string and we do want this to be required so we're going to say required and we can do true and then add a message here like please add a name okay so that's the name and then what i'll do is just copy this down i will do four times and then the second field that we want is an email all right so we'll say email the type is going to be string required true and then we'll just change the message to please add and email and we do uh want this to be unique as well so i'm going to add in unique and we're going to set that to true okay because we don't want two of the same email addresses and then the password say password that's going to be type of a string and we'll say please add a password and then uh yeah i think that that should do it if you want to have other things of course you could if you wanted to add like phone number or or anything like that if you have different you know you could have admin different roles things like that but this is going to be pretty simple so that's all we're going to have actually now i do want timestamp fields so after this after the schema we can put in a set of curly braces and we can just say timestamp or timestamps and set that to true and that will automatically create give us a created at and updated at field all right so now we just need to export so we'll say module exports our mongoose model and the model name is going to be user and then the schema is the user schema that we just created so we can go ahead and close that up now i'm going to open up the goal model because with every goal we have to know which user created that goal okay every goal is going to be associated with a specific user so we're actually going to add a field here so i'm going to go above text and we're going to call this user and just make sure you put a comma after that so as far as the type goes the type is actually going to be mongoose dot schema dot types and then dot object id okay so when we have our you know underscore id field and we create a new resource that's an object id so what we're saying is we want this type to be an object id and we also want it to be required so let's say required set that to true and then we need to add a reference because we need to know which which which model does this object id pertain to and it's going to be the user so we add a ref field so we say ref and then the name of the the model which in this case is going to be user all right so that will allow us to have a user associated with a goal okay so we're gonna just do that save that close that up so next thing let's uh let's see let's create a new routes folder so our file so file called userroutes.js and in our server.js since we added a new route file we need to add it here so i'm just going to copy this line down and let's set this to routes and then user routes and it's going to be api slash users okay so now that will pertain to that file we're going to get an error for now just because we have nothing in this this user routes so now let's start adding our routes and we're only going to have we're going to have three actually three routes one is going to be to register or create a user one is going to be to log in and one is going to be to get the the user's information so first of all we need to bring in express just like we did in the goal routes so we want to require express and then we're gonna create our router so let's say express dot and then router and let's make sure that we export that so we want to module exports equals router all right so let's see we're gonna say router dot post so basically when we make a post request to slash which in this case is is gonna be slash api slash users remember when we post that's that's to add a resource right so we're going to be adding a user with a post request and that's basically a registration so when when we hit that route we're going to want to call a controller function called register register user all right now we don't have that yet we haven't even created our controller so we'll do that in a second but let's bring it in so we'll say const register user and that's going to come from require and let's say we want to go outside of the routes into controllers and then it's going to be user controller all alright so we'll create that now so let's go into controllers create a new file here called user controller.js and let's create the register register user function it's going to take in request response and uh i need an arrow here and then for now let's just do a res.json and we'll just say actually let's say message register user and then we need to export so let's say module dot exports and register user okay so now we shouldn't see any errors down here and if we go to a new tab and instead of goals we're going to make a post request to api slash users and let's send that and we should see a message register user now we're also going to have actually let's add our little header here that i like to add so just the description and stuff like that so this is going to register a new user and the method is post and it's going to be api slash users and it's going to be public obviously because you can't lock you can't access a protected route without being logged in and you can't log in without being registered so let's take this and let's copy that down so this one here description let's say login or we'll say authenticate a user and this one is going to be a this is going to be a post request as well but instead of api users it's going to be api login and that's going to be public as well and let's say login user and then we'll just respond with login user and then this one here we'll just say get say get user data and i want this to go to api users me and this is going to be a get request and basically it'll be able to get the current logged in user because we'll be sending the token and you get the id from that token okay so we'll just call this get we'll say get me and we'll just say user data display or whatever it doesn't really matter and then down here let's export login user and let's export get me and then bring those into our routes so let's see these are all going to be different endpoints so i guess we can just copy this down so this will be post to slash login and function will be login user and then this one here will be me and it'll be slash me and we just want to bring it up here login user and get me alright so let's try those routes out i'll go ahead and make a post request to slash login and we get login user and if i make a get request we'll do this we'll open up another tab for this and this one will be user slash me get requests send and 404 not found oh i need to change this this needs to be get all right so now we get user data display good so now we at least we have the route set up so first thing i want to do or i should say next thing i want to do is the register user functionality okay now we do need to encrypt our passwords obviously we're not going to store plain text passwords in the database so we're going to use something called bcrypt js for that so i'm going to open up a new terminal down here and say npm install and we want bcrypt js all right now we're also going to be dealing with json web tokens so i'm going to npm install jason web token so it's just all one word like that and then i think that's pretty much yeah i think that's all we need as far as dependencies okay so just get those installed and then let's see let's go to we shouldn't need our this routes folder anymore so let's go to our user controller and this register user function is what i want to work on first but we do have some stuff to bring in so it's wrong syntax so let's bring in json web token so we'll say jwt and we're going to require json web token we also want to bring in bcrypt to hash our passwords so the variable here is bcrypt but when you require it just make sure you add js so we want to require bcrypt.js and then what else we also want our our express async handler so we'll call this async handler and set that to require and then express async handler and we also want to bring in our user model so const user and set that to require and that's going to be up one level in models and then user model now let's just make these asynchronous because again we're working with mongoose we're also working with bcrypt which uh is also we also deal with asynchronous methods there too as well so we're gonna make these async and then remember we have to wrap these in async handler to handle exceptions so let's say async handler and just wrap the entire thing so i'm just going to copy that and here wrap it and same thing with this wrap that one as well good so let's see now we're going to start to work in the register now when we send a request to to this this endpoint api users post requests ready to register a user we're going to have some body data so i'm going to destructure that it's going to be name email and password we're going to get that from request.body and then i'm just going to do a little bit of validation here so i'm going to say if not name or if not email or if not password if none of those are included then let's do a res dot status it's going to be a 400 which is a bad request and then we're going to throw a new error and we'll say please add all fields and let's check that out for now so if we come back over here we hit api users with post we're going to get this please fill in all fields so now in the body here we can add in our name and email and our password i'll just do a one two three four five six so if i send with those fields then that works i get back register user which is what i want so let's see next thing is to check to see if the user exists so let's say check if user exists so we're going to first create a variable called user exists and we're going to await and then use the user model and there's a method called find one and we want to find the user by the email that's passed in so if that includes something say if if user exists then we're going to want to send an error because obviously we don't want to register the user if they already exist so let's say res.status and we're going to do a 400 and then throw throw an error and we'll say user already exists oops exists okay and then we'll keep going here and the next thing we want to do is hash the password so to do that we use bcrypt let's put a comment here we'll just say hash password and we can do that by first creating what's called a salt we need a salt to or do we need to generate a salt to hash the password and we do that by calling uh a bcrypt method called gensalts let's say bcrypt our bcrypt.gensalt and that takes in a number of rounds here 10 is the default so i'm just going to use 10 and now that we have the salt we can hash the password so let's say const hashed we'll say hash password and we'll set that to a weight on bcrypt and we have a method called hash and then that's going to take in two things one is the plain text password that comes from the form or com or in our case postman and then next is the salt and that will give us the hashed password next we want to then create the user so we can do that let's say const user and set that to a weight and from the user model we want to call create just like we did with the goals pass in an object and then the fields that we want such as name email and then we want to make sure that we set password to the hash password so that will actually create the user then we want to just make sure we want to check that so let's say if user okay so if the user was created then we're going to res dot status 201 which is an ok and also something was created and then for the json you could just do the token which we're going to get to in a few minutes but i'm also going to send some user data back like the id we'll say underscore id user dot id let's do name user user.name and then let's do email so user.email and then we want to have an else here so else then we're gonna set an error so status 400 and then throw new error and i'll say or we'll say invalid user data and then just get rid of this last line here all right so let's try this out i'm going to come back over here and i'm going to keep these name email and password fields and send and now i get back a 201 created i get back the id the name and the email no token yet we haven't done that yet but we can now register a user and if you want to open up compass if you did install it and you check the the database and you look in the users collection you should see you should see this or whatever you know whatever name and stuff you used so now we can register user next i want to what do we want to do next let's just do the login functionality so basically you know matching the name the email and password and then after that we'll do the token generation and will respond from because i want the token to be sent whether the user registers or logs in but let's just do the login functionality first which is going to be really simple we're just going to get the email and password that's sent in the body so we want that from request.body and then we can just say const user set that to a weight we want the user model and yeah let's do dot find one and we're going to find by the email once we do that we have to match the password so this will let's say check for user email all right and then let's check the password so i'm going to say if so if user and we want to compare the passwords now remember that the password in the database right if we look here well actually we can't see it there if we look in here the password is hashed right and the password we're going to send to login is not going to be hash so we need to use a bcrypt method called compare to do that so i'm just going to open up another set of parentheses and we're going to await on bcrypt dot compare and that's what it'll do it'll compare the the plain text password which is this password that's sent in from the form or from postman and then second secondly we want to pass in the user which we just fetched and the password which is hashed so we're going to pass those two things in all right now if that all turns out then we're going to respond with jason and we're going to pat we're going to send the same the same data back that we send if they registered so this stuff here so pass that in and then we'll just have an else so this if statement right here let's say else and then we'll just do the same thing we did up here which is an error and invalid user data or let's say invalid email or invalid credentials because that's we'll actually see this message in our front end when we try to log in and now let's get rid of that okay so let's at least try to authenticate so i'm going to go to a new tab um yeah we'll just actually open up another one so let's copy this and it's going to be a post request to user slash login so if i just send with nothing i get invalid credentials if i go to my body and set email to brad gmail.com and then we also do password and my password was just one through six if i send that now i get back the user data all right so i'm able to match my user my email and password against the database so now we want to get into our json web token and basically we're going to we're going to have to sign the token and we're going to send that back in both register and login so we do have to have a secret and we're going to put that into our dot env because it needs to be signed with a specific secret so let's say jwt underscore secret and i'm just going to set it it can be anything i'm just going to set it to abc123 okay and then let's just restart the server because whenever you add a new environment variable you should restart the server and then in the user controller i'm actually going to create a separate function because we're do it we're going to put this in two places both in login and register so i'm just going to create another function down here to generate a token we'll say generate jwt so let's say const and generate token it's going to take in the id that's going to be the user id because that's what we want to put as the payload and then we want to return from this function we're going to use jwt which we brought in up at the top this is using the json web token package and we're using a method called sign oops sign and that's going to take in a couple things first is going to be the payload the data that we actually want to put in there which is going to be the id that is passed into this function second is going to be the secret so process dot env dot and then jwt underscore secret and then third so we can put a third argument in here of options and there's an expires in and you can set this to whatever you want i'm going to say 30d which is going to be 30 days all right so this will sign a new token with the id that's passed in with this secret used and it'll expire in 30 days so now we can just simply go back up to let's go to register first and along with the user data that we passed back i'm also going to pass back a token which is we're going to call our generate token and then we're going to pass in user dot underscore id okay so the user that we register remember we get the user back and we're just passing the id into the generate token function and then it's going to get put into the the actual token so we'll do the same thing for login so i'll just copy this and then once we log in in addition to that we'll get the token so let's go ahead and try that out i'm going to uh we'll just log in again so i have the correct information here i'm going to go ahead and send and now you'll see in addition to my user data i have a token and if i take that token and copy it and then i go to jwt dot io you can actually put that in here and it'll show you what what it is so pass that in and now you can see in the payload i have an id and that's my user's id i also have an issued at and an expiration which is 30 days from now all right so this user id we should be able to get when some when we send a specific route we send that token and that's how we can validate so the next step now we can do let's actually check the register as well so i'm going to go to this post api users we'll register a different user here let's say john doe and just set this to john okay and we'll send so that registers a new user and it gives us the token for john now i just want to send this again and make sure yeah so we get user already exists so all of our functionality up to this point is working now we want to be able to protect routes and i'm going to use this this this get me right here this is actually going to be private so let's say private and we'll use this as an example of how to protect a route now we need to the way we do it was with middleware we create a custom piece of middleware and remember middlewares is a function that runs during the request response cycle so when we send a route or send a request to a route or an endpoint this function that we create is going to run and check the token so let's create a file here called off middleware.js and let's see we want to bring in a couple things here so jsonwebtoken so jwt we want to bring that in from web token we want to bring in our async handler so const async handler equals require express async handler we want to bring in the user model so const user and set that to require and we're in middleware so we want to go up one level into models and user model so we're going to create a function here called protect so let's say const protect we're going to use async handler so make sure you add that and then async will have an async function and this is going to take in here request res and next since this is middleware and let's just export this so i don't forget so down here module exports and we're going to export protect so as far as what we want to do in here first thing i'm going to do is just initialize a variable called token and then we want to check and the way excuse me the way that this is going to be sent is with is in the headers in the http headers you have an authorization object so that's what we want to check so let's say if request dot headers so with expressato we can access the headers and we want to look in authorization so we want to just check make sure that that's there and we want to check to see if it starts with bearer so the reason for that is when the token is sent in the authorization header it's you don't have to type this but it's formatted like this so bearer space and then whatever the token is all right because it's it we're bearing the token it's a bearer token so we want to make sure that it starts with bearer so we can do that by just taking this and we'll paste that in and we can say dot and we'll use the javascript method starts with and we want to make sure it starts with bearer all right let's close that up so let's see if that is true so let's say if then we're gonna add a try catch here and in the try the first thing we want to do is get the token from the bearer header because remember how it's formatted it's bearer space and then the token so i'm going to actually put a comment here and say get token from header so token which is the the variable we initialized above we're going to set to request dot header headers dot authorization oops authorization and we're going to use dot split because what i'm doing is getting the token from that bearer space token so what split does it'll turn this into an array and if we split by the space so remember we have bearer space token and what this split will do is it'll turn this into an array where bear the the text bearer is the first item or the zero index and the token is the second item or the one index so we're just going to put here we want the one index so that'll give us just the token then we want to verify the token so i'm going to say const we're going to have a variable called decoded and we're going to set that to jwt which is our json web token package and then there's a verify method so this takes in the token itself and then the secret so remember that's in process dot env dot and then jwt underscore secret okay next we want to get say get user from the token because the token has the user id as a payload we also want to assign it to request.user so that we can access request.user in any route that's protected so let's say await and then user so from the user model we're going to use find by d and the id is going to be in the decoded object okay because this right here when we do verify that will allow us to get the payload or that will decode it so that we can get the payload which is the id and remember we we set the id in the token if we go let's see right here when we signed it we set the id so we could put anything in here you know we could put the the user name or whatever we want inside of the the token payload and then we could get it here so what we're doing is finding the user by the id that's in the token but i don't want the password hash okay even though the password is hashed i don't want that here so we can use dot select and if we put a string in here of minus password then it won't include the password okay so we won't have request.user.password or whatever and then we just want to call next because at the end of our middleware we want to be able to call the next piece of middleware now if there's an error then we're going to first of all just console.log the error and then we'll just do a res.status of 401 because 401 means not authorized and we'll throw new error and we'll pass in here we'll just say not not authorized okay and then let's see right after this second curly brace we just want to say if not token so if if there's no token at all then we'll say res.status and that's going to be a 401 and throw new error and we'll say say not authorized no token and then that should do it so again just kind of go through we're checking for the the authorization header making sure it's a bearer token then we're assigning the token to this variable we're decoding and verifying the token we're getting the user from the token calling the next piece of middleware if this doesn't if none of this you know if something goes wrong then we're going to send a 401 and say not authorized if there's no token at all not authorized so wherever we want to use this we can simply go into the route file so for instance user routes this slash me right now i can go to it right if we go to where is it user slash me i can hit it right and it's just sending this message but i want to protect that so what i'm going to do is bring in the protect function from our middleware so protect and set that or get that from dot dot slash middleware slash off middleware and all we have to do is add it as a second argument so we can just say protect like that and then let's try to hit that route again and you can see we get not authorized no token so now let's um let's log in so right here i already did i'll just hit this again so i logged in with the correct email and password and now i'm going to grab this token and go to my protected route which is user slash me and you could do this a couple ways you could add here in the not here as a param but as a header you could add authorization and then put the token or with postman you can just click on authorization you can choose bearer token and just simply paste that in i don't think that's the right one so if we paste that in and now we send now we can hit that row now if this token is is changed in any way like that 4 on the end if i just take that off and i put a 5 and i send we're going to get not authorized it doesn't say no token because we have a token it just failed it's not the right one all right now i'm going to put the right one in and remember we get the user id is is inside of this token and when it goes through our middleware we set the user to this request.user so any route that i use the token in such as this getme which is right here i have access to request dot user so i i can use that id to whatever i want to validate certain goals or whatever so let's um let's add to this because all i want this to do is return whatever the logged in user data is so i'm going to get rid of this and let's say const and then i'm going to just destructure let's say underscore id name and email i'm going to destructure that from the user so let's say a weight and then the user model and then we'll do find by id and we should now have access to request.user.id because we set that in the middleware and then we'll say res.status 200 and then dot json and we'll send an object with we'll say id and set that to our underscore id name set actually just say name and email so now whatever users logged in when they hit this route they should get their own info so if i go ahead and send with that token i get back brad traversy so email and my id now if i log in as another user such as john so let's go to the login route and let's do john at gmail and send and then i get this token i'm going to take that one and this one should have john's id so if i go ahead and i add this here and i hit the get me route now it's just going to show john so this request.user is going to be whatever user is has authenticated all right so now what we can do is protect all of our goal routes because right now we can probably just let's just leave the login open we can close that up we can close up but that one so we have api slash goals which right now just will get all of the goals but what i would like to do is protect that route for one thing and then have it return only the user's goals so let's close up user routes close up auth middleware and i think we're all set with our user controller as well so now we're going to open up goal controller and go routes because we want to protect these routes so in our goal routes let's bring in the protect middleware function so we'll say protect want to require dot dot slash middleware slash off middleware and then right here we do debt debt dot get and then get goals i'm just going to put protect before that so that's all you have to do to protect a route so now if i come back to api goals and send i'm not authorized because i didn't send a token so i actually want to protect all of these so set goal let's say protect for delete goal we're going to protect that and for update goal all right now let's go back to our goal controller now that all those are protected and private and um like i said right now we're just we're getting all of the goals in the database but i want to get only the specific users goals so in this find here let's add an object and we're going to say we're the user because remember now we have a user field on the goals which is a relationship to the user model and we can access request.user because of the protect middleware and we just want to match the id all right and that's all we have to add here so now if i send with let's get a token so i'll go to login and let's use john so grab john's token and let's see we want to add that to authorization bear a token and we'll paste that in and send and we get nothing so let's add a goal as john but before we do that let's go to our set goal and make it so that the user is uh so that the user is actually included because right now what we're doing is just saying create and just using the text in the body so all we have to do is also set a user to request.user.id all right so we'll save that now let's open up a new tab and let's hit this same endpoint api goals make a post request and remember we have to add text oops this is params we want to go to body so body we want to go here and let's add text and we'll say this is john's goal one and if i just send that now you'll see i get not authorized but if i put in john's token in authorization bearer token oops that's not right i want to get john's token and let's send and then we get back john's goal one all right let's actually do another one we'll say john's goal two send that john's goal two now if i come back over to make a get request and i have john's token and i send we're going to see john's goal 1 and john's goal 2. so now let's log in with a different user so i'm going to go to the login endpoint and we're going to do brad at gmail send that i'm going to get brad's token and then i'm going to go to the get where we get make a get request and i shouldn't see if i put in brad's token i shouldn't see john's goals so if i send you'll see i get an empty array now if i go to add a goal as brad so let's go back to post api goals i don't know why that's there and then let's change the token so authorization bearer token and change that to brad's token and in the body we'll say this is brad's goal one and we'll send that and now i see this is brad's goal 1 and if i go back to get my goals and send and i have brad's token in that's the only one i'm going to see all right now for the update and delete we want to make sure that brad can't delete john's goal and vice versa or update each other's goals you should only be able to delete and update your own goals so we're first going to bring in the user model up top in addition to in addition to the goal model so here let's say user okay so we're going to go down to update now okay so in our update we're getting the goal by the id and the in the uri and the url and then we're checking for the goal and then we're updating it with find by update now before right before we call that find by update we first want to get the user so let's say const user equals a weight user model and we're going to use find by id and the id is going to be in request.user.id okay so that's the logged in user's id and then we're going to say if not user so if the user doesn't exist i'm just going to put a comment here we'll say check for user then let's do a res dot status and do a 401 with his which is not authorized and let's throw a new error and here we'll just say user not found and then we want to make sure that like i said we can't update each other's goals so we're going to check for the let's say goal and then the goal goal has a user field on it which is an object id and we want to turn that to a string before we check it so we're going to say to string and then say if that is not equal to the user dot id okay and the user is the one that we just got up here from the logged in user so if that if those don't match actually let's put a comment here we'll say make sure um only or say make sure the logged in user matches matches the uh goal user okay so if that's not true then we're just going to res res.status 401 whoops 401 and then throw new error and we'll say user not authorized okay so again we're just checking for the user making sure that's there and then we're matching the user logged in user to the goals user make sure they match and we're going to do the same thing with delete so i'm going to just copy these parts here and then in delete right after we check for the goal paste that in all right so now if we let's see i'm going to open up a new tab and i want to do a delete so i want to say delete request remember that has to have an id so i'm going to take brad's goal id right here and right now i don't have any token selected in my authorization so i should just get not authorized no token however if i log in as john so i'm going to change in the login route here i'm going to change that to john and then i'm going to take john's token and i'm going to use that to try to delete brad's goal so let's go to authorization and then bear a token and let's paste in john's token okay so again i'm trying to delete brad's goal that's this id is is brad's goal and this token is john's and you'll see if i send i get user not authorized so like there's no way i can do that if i log in as brad though i should be able to delete it so let's change that to brad correct password send and now i'm going to take brad's token feels weird calling to myself in the first third person so here i'm gonna put in brad's token and send and that deletes it so if i go back to the get request and send now there's no goal brad has no goals brad's a loser um but yeah so now we have complete crud functionality with author um authentication and authorization okay we authenticate by you know going against the database and make making sure we have the correct email and password and then we authorize by sending the right token to uh to the route to the correct route so that's it now we have an authentication an api that has authentication so obviously you can use this for other projects other apis um i think yeah i think we're pretty much done with the back end so in the next video we'll be doing uh we'll be doing the front end and i want to use react along with redux and redux toolkit but of course you could use this api and create any front end views felt angular whatever you want to use alright so that's it guys thanks for watching if you stuck through the whole thing thanks i appreciate it and i will see you next time
Info
Channel: Traversy Media
Views: 143,197
Rating: undefined out of 5
Keywords: mern, mern stack, jwt, jsonwebtokens, json web tokens, api authentication, authentication
Id: enopDSs3DRw
Channel Id: undefined
Length: 52min 29sec (3149 seconds)
Published: Thu Feb 10 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.