In this tutorial, we'll compare *authorization* to authentication. Once we understand both concepts, we'll expand the authorization given to our JWT tokens by including user role and permissions info in the process. If you're just starting with Node.js & Express, I suggest going to the beginning of this *Node.js for Beginners* playlist here: ru-vid.com/group/PL0Zuz27SZ-6PFkIxaJ6Xx_X46avTM1aYw
@@shocchosolutions6275 here's a React series where I use the permissions created with this Node tutorial: ru-vid.com/video/%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE-oUZjO00NkhY.html
Great tutorial and a seriously underrated channel! I'm learning on my own and have been having a really hard time piecing these backend concepts together - this helped a lot. There's a lot of frontend tutorials out there, but not as many backends. Keep up the great work! subbed and liked
Wowwwww!!! this series of node and express tutorials is amazinggggg!!!!! I went through the whole series and really learned a lot even though I have used express for a long time. Thanks Dave, pls keep going for the excellent content, this is the best node &express tutorial on RU-vid.
Awesome video series!! I've tried many times to understand node in more detail together with JWT Authorization and Authentication and this is the best resource available by far! Looking forward to taking more of your courses once you have your platform up and running!!
Thank you for another fascinating lesson. A couple of notes: (1) 26:44 - It is not shown on screen but maybe you should consider to make it clear with hard-subs (because it might be confused) That in, the content of the Body tab is: {"id": 3, "firstname":"john", "lastname": "Doe"} (...took me awhile to figure it up, and it might ease others, so..) (2) 27:25 - Thank you for the clarification, but in this point people (such as myself) - Might already got confused and spent some time to figure it out on their own, So you might want to consider, again, to clear it up in the relevant (previous) video, with hard subs. * If those are too difficult to produce now, Then these clarifications might be helpful as notifications at the description (..which is quite busy already as is, but.. ..yeah).
Thanks - your comments may help others. RU-vid does not let me edit / change videos that have already been posted. I could continue to add to the description but as you mentioned, it already has a lot. Many provide suggestions and I may use these when I cover the topic again. 🚀
This is a very nice concept to apply access roles, I used to use similar concept before (saving user roles upon login process), everything worked nice until I encountered a case where a user was misbehaving and I needed to remove some roles, unfortunately there was no way to invalidate his access token and I had to wait for him to logout or for his session to get expired 🤦♂️😥 I really appreciate explaining the concept, this will make coding easier, Thanks Dave,
Awesome info. This tutorial and other ones you created provided all the answers I needed on how to integrate JWT into my project along with roles. I was cornfused before and now I'm less cornfused.
How do u automatically generate new access token from the server side with hit endpoint refresh token.. cos on d client once user is active d refresh token to generate new without re login.. pls
good idea with role codes! when it comes to verifying auth header, I prefer to destructure: const [bearer, token] = req.headers.authorization?.split(' '). Results in much cleaner code down the pipe.
@@DaveGrayTeachesCode I wonder how you configure a special role in this mix, which is owner - so a document can only be mutated/deleted by admin or owner
@@aram5642 on a per-document basis you would have to track the document owner and match it up, too. Otherwise, adding permissions for an admin only route to a delete endpoint should be much like the other restricted routes.
Hi Dave! Great work, really enjoy your method of teaching and way of explaining everything. I consider myself more than a beginner but not advanced for sure, and I have found a lot of new information and new tips and tricks to take away from your lessons. I do have one question. I understand the process of passing the roles inside the JWT and validating them during the request process. However, what I don't quite understand, is why you use numbers associated to each role and not just level names (i.e. "admin" for Admin), I know you said that there are many constructs to role permissions, so maybe this is just one variation and there is no meaning behind it, but I was curious what your thoughts on it.
Thanks Robert! And great question - I think I only briefly mentioned it at best. And you are right that roles and permissions can be structured in many different ways. I've found they are often associated with codes or IDs. In this specific tutorial example, I briefly mentioned that a backend dev will not have control over how a frontend dev chooses to store the access token. While I believe an access token should only be kept in memory, others do put them in local storage or cookies that are not httpOnly. If someone got a JWT and decoded it (like you can at JWT.io), they can easily read the payload. I'd rather have a code or two in there instead of clearly stating this is an admin token for example. Just a bit of security through obscurity if the JWT is mishandled.
@@DaveGrayTeachesCode Thanks again! I had a feeling it was going to involve some bit of obscurity, but I wanted to make sure I didn't miss anything. This also allows you to know the roles without a database lookup for every API call. Nice! Again, great work, keep it up! I'm always looking for great content and something to learn, I'll be watching more and more of your channel.
i think that you should prepare some slides about theory of each lecture, for example authentication , but anyway your nodejs express course is awesome and amazing , i hope that in the future you can make advanced course about nodejs .Tks very much !!!
Hi Dave , your explanations are just Perfect , Please, any chance to ses PHP and symfony series in a near futur please ? Thank you for your JS long video , definitly super great !
In verifyRoles.js "Some" array method could have been used in place of chaining "map" and "find" when checking if rolesArray and req.roles contains the same elements.
Hi Dave it is a good idea with role codes! when it comes to verifying auth header, I prefer to destructure: const [bearer, token] = req.headers.authorization?.split(' '). Results in much cleaner code down the pipe.
Very rich playlist. However, I don't see the usecase for the accesstoken as response to the /login endpoint. First, because you advised that we should only store in memory, so we can't store in a state or context in the frontend that we can use to say access /employees endpoint later on. So maybe everytime we need to access the /employees endpoint, we first call /refresh and get an access token then call the /employees endpoint. I'd like anyone to point out a usecase for the accesstoken as response to the /login endpoint.
If I were to need to update the user for an API post request -- for example, the user clicks a button, and something is changed on their user account -- would it make sense to just use the refresh token to lookup the user in the database like you demonstrate with the login and refresh routes? I'd prefer to use the user ID directly, but I imagine passing it through one of the tokens would be a security risk. Thanks!
If a bad user tried to hack our app by decoding his jwt and changing his userId and encoding it again and storing it in localstorage again, can he do it? Can't we detect that in the node server?
If I remember correctly, we are using jwt-decode middleware in this tutorial. (Reference: www.npmjs.com/package/jwt-decode) If a token is changed, it will be detected because they will not know the embedded secret key. You can also decode tokens at the following site and see how each part works: jwt.io/
In the timeframe 09:48 you are obtaining the userroles from the founduser. But the userroles is also present in the decoded variable. can we assign the jwt userroles from founduser or decoded.userroles. both are fine?
it's perfect content. I sent you message from twitter. I'm one of flutter and nodejs developer and I want to introduce you in my country (turkey) if we can make video together for 10 minutes for beginners I will be happy to translate for turkish franch and arabic! it's pleasure discovering your channel
Hey nice tutorials. I have a question. Why at 12:50 why need to modify request object and set user and user roles to it, when all this middleware does is check whether we have auth token?
Hi Dave, Thank you for providing very conceptual tutorial, please tell me one thing I will be greatly thankful to you because I am learning react and node just on a self-study basis. I created the schema with my cars inventory with status purchased When I sold the car how can we change the status of the car from purchased to sold, please guide me or any tutorial or study ref available then please provide me how to change the status of the product after sold our product from purchased to sold?
You are asking about updating data. Updates are part of a CRUD application. Create, Read, Update and Delete is what the CRUD acronym stands for. Follow the full playlist for this course to learn how to do all of these CRUD operations.
@@DaveGrayTeachesCode Thank you for your response, I am not asking updating data , I am asking to change the status of the product. Suppose I and doi g business of a car dealership, I purchased one car to sell. I insert data from my car with the status purchased .But when I sell that car then the status will be sold instead of purchased in my dashboard.
@@iramimran3117 Have a stauts property in your schema. The default could be purchased for example. Then created an updateCarDetails function in your backend that modifies any stored cars with whats provided by the frontend. Much like an update employee function in this course. In your dashboard have a toggle or a button that once pressed makes a call to your updateCarDetails function and sets the status to sold.
Thanks, Dave, great video. Quick question... Is there any available service to which we can delegate the RBAC management to? For instance, if Cognito is taking care of the Authentication, do you know if there is any service for the Authorization part? Also what solution do you recommend for partial access levels? For instance, a user has Read access but only on his own posts? do these need to handle at the controller level or can we come up with a middleware that can filter response?
Thanks - You seem to be asking about Amazon services. It seems Amazon Cognito can handle RBAC: docs.aws.amazon.com/cognito/latest/developerguide/role-based-access-control.html Many different solutions are possible for partial access. I would consider different levels of roles for this.
Should i create different controllers for different roles?, eg: in some cases i need to use populate to get certain references within the document based on the role
No. Controllers are not based on roles. You usually route to a specific controller. You can control access to the route with roles, and I suggest using middleware for that.
Hi Dave, thank you very much for this video, cool as always. I'm an intermediate developer and I've always struggled with scaling the backend. You seem to be a very experienced developer so I wanted to ask you here to create a series on scaling techniques. And to be clear, I mean for example when an app is supposed to have millions of users. Just as an instance, somewhere in this video, you mentioned that we might want to store the roles (and their codes) in the database, however, wouldn't that mean checking the database on every request only for the purpose of the authorization part? (I know this is just "one way"). Also keeping them in code has this downside that "DATA DOES NOT BELONG TO CODE, IT BELONGS TO DATABASE", but which way should a developer prefer if they know their application will gain a big number of users in a short period of time? What are the common methods that highly scaled applications use in order to increase their performance in case of such repetitious requests? I know these things are usually either very advanced or proprietary, but I'm sure there are at least some best practices and known methods in the world of scalability (say Redis, Sharding, HA clusters, Kubernetes, etc.), and I believe the world needs more great teachers like you on them 😎 Yes, no one knows everything, but please do share with us whatever experience you have in that regard too, it's greatly missing.
Thank you for the kind words 🙏 Much of my teaching focuses on beginners to intermediate, but for your questions, I suggest checking out @JackHerrington - Jack Herrington's channel. It is excellent and he has decades of experience: ru-vid.com
@@DaveGrayTeachesCode Yes, I've subscribed to Jack Herrington and I have learned loads from him especially about Typescript and State Management. However, I only recently discovered your channel and I've found that you cover some vary useful and often overlooked skills that hardly anyone else bothers with such as best practise implementation of refresh tokens and accessibility friendly forms. Thank you for being here to cover the gaps in my knowledge 👍🏾
this is awesome, answered so many questions i had before watching this, just one question i have tho, assuming i have a user with role of admin, and i want to secure it in the "app.use" area, but i also want to verify if user already logged in, and has the role as well, meaning i need to create 2 middlewares, is it a good approach if i create 2 functions for that in my auth controller, then in main.js file (main file in project), i'll import it at the top, then use something like app.use("/secured", verifyJWT, verifyAdmin) ? so even if user is indeed verified logged in, they also have to have the role admin
Applying app.use() will apply it to all routes that come after. Your middleware should not be created in your controller. I apply middleware to specific routes like you can see here: github.com/gitdagray/mongo_async_crud/blob/main/routes/api/employees.js ..this all comes before the controller. You can apply more than one middleware to a route.
I have an idea por a serie you can do. Why don't you build a social network nodejs api? maybe store photos with cloudinary. Teach us how you would set the role for the users, if you'd store comments nested in arrays or used by references... and so on. That could be fun. I haven't seen a serie like that here on youtube
I have a Node.js upload video here: ru-vid.com/video/%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE-4pmkQjsKJ-U.html Notifications can be handled in any stack you choose. I would likely use MERN.
hey dave may i know why have you used refreshTokenController in jwt authentication, i could not get the idea of creating another refresh route and generation the new access token
Good thoughtful question, Abiodun. verifyJWT is in use at line 42 of the server.js in my example so it applies to all routes that come afterwards like the employees route. That said, you could remove it and apply it specifically to individual routes like I show with the verifyRoles middleware if you choose to do so. 🚀
Nothing is 100% secure in the frontend, but yes, if sending from the REST API to the client (browser) so the roles can be used, I'd send them inside the token.
Hello Dave. I'm sorry for another question: we check if there is access token in request and that it hasn't expired if access token has expired we need to refresh token and if cookie jwt is stored in database it will be refreshed but how it would work from frontend side? we have access token inside store we send GET request to secure route - it sends back 403 (token has expired) so we need to make one more request to /REFRESH (checkes cookie jwt and gives back new access) then rewrite our store token and then make this get request again? so if we work with redux we need middleware function which will implement at max 3-4 extra requests under the hood of every CRUD requests?
No, 3 or 4 extra requests are not necessary. You can see how it is implemented with Redux here: ru-vid.com/video/%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE--JJFQ9bkUbo.html ...for more on the frontend and using this strategy, I have a full React Auth playlist here: ru-vid.com/group/PL0Zuz27SZ-6PRCpm9clX0WiBEMB70FWwd
@@DaveGrayTeachesCode Thank you Dave. Yeah, have started your MERN course. I try to watch and repeat your every tutorial, they are extra helpful. You are the best!
Hello! I have done this tutorial two times and also tried the testing with thunder client with the finished source code and am receiving the following error: Error: secretOrPrivateKey must have a value at Object.module.exports [as sign] (.../node_modules/jsonwebtoken/sign.js:107:20) The line of code in the /sign.js stated: if (!secretOrPrivateKey && options.algorithm !== 'none') { return failure(new Error('secretOrPrivateKey must have a value')); } I believe from looking online this is due to missing the contents of the .env file. Are you able to share what those would be? I've gone back through all the videos and am having a hard time finding where that was created and the variables inside it. Thank you!
The .env file just contains a secret variable value that you do not want to share in Github or other public resource. Confirm you have installed the dependency and that you have the dotenv required in the server file as shown in my source code. Any time you reference a variable found in the .env file, you reference it with process.env.VARIABLE_NAME (where you replace VARIABLE_NAME with whatever the actual name of your variable is). Otherwise, as you mentioned, going back through the code and tutorial can often uncover a small difference that creates an error when you follow along.
Good question! You can encrypt whatever you wish before storing and then decrypt it when you retrieve it. I *think* I covered bcrypt and storing the encrypted password before this lesson, but maybe not... if not, it will be coming up in this series.
No need to overthink an example like this. Different organizations can organize their roles to their needs. I believe I do show one benefit of using an object lookup for the roles during this tutorial - using dot notation and not needing to type the roles which could lead to typos. All personal preference or organization preference though.
@@DaveGrayTeachesCode ah sorry, I stopped watching half way through because I loved the route structure so much I immediately started implementing it referencing the first half of your video but quickly was met with hours of debugging haha. I'll definitely finish the rest of it now I have everything working
@@DaveGrayTeachesCode Thanks sir ,let me show us how an admin can create his account ,either he should manually create his account in database and put his roles there or in frontend ,we enable an option or checkbox or roles option ,like if you are user/admin then paste your roles etc ,and this registration data will be then store in the mongodb database...i am very confuse about that...
Good request, Usman. An admin panel for this would be a nice addition for user maintenance. Currently, you simply need to manually add an admin to the database as you do any other role besides "user".
i think there is an error, when i try to login i don't get a token when the verifyJWT function excute , i don't have a header that start with Bearer at that point , so i get an Unauthorized response, please help me
@@DaveGrayTeachesCode i think it's because my server send back a 401 unauthorized error instead of 403 like your's at the baseQueryWithReAuth() function, and that prevent the refresh route to execute, what should i do ? should i add 401 at the condition check of errors ?
@@DaveGrayTeachesCode i finally found the issue , it's when i use axios instead of the apiSlice, can't we integrate axios to the apiSlice can you do that please ?