I like how over time your channel covers more and more advanced topics. I feel like I've been growing in my career in a similar pace, so you always have me covered! Thank you
you are wrong. What you are doing is consuming precisely targeted ads. This video is nothing more than an advertisement. He didn't even mention free/open source alternatives. Every second of this video is designed to attract you to the clerk's product.
@@xaweeeed33rt5g43wsd the permission logic is the same regardless of what auth provider you use though. You expect to consume his videos for free then complain when he gets someone else to pay him to continue teaching for free.
@@xaweeeed33rt5g43wsdso what? The auth process stays the same without clerk and also that’s some great learning material and good explanation he’s done.
Great video!!! It's important to note that you have to handle permissions for both the client display AND the database action. For example, if you display the delete button for your own comments and clicking it results in `DELETE /api/comments/123` and someone can find the ID of another comment (maybe by looking at the XHR request for the listing page of comments) and issues their own DELETE fetch request to the other comment, your backend or DB has to also check permissions and not just delete the comment. Postgres can do row-based and column-based policies that makes that a lot easier to do that particular check on the backend.
But why would you move authorization logic to the db layer really. A server app layer can handle this comfortably. Unless you share and touch db outside of the app, or are serving client app straight from db eg firebase, i would not advise for that. Db should be kept as simple as possible.
@warrenarnoldmusic that's why I said either do it on the backend or DB. One over the other and what "should" be done is a preference / philosophical question, making sure a client side request is validated for authorization is not a question, but a requirement.
@@warrenarnoldmusicyou could even consider building a dbase access layer. The server should only use that layer. Any program accessing that dbase should use that access layer. It enables access control to be shared.
I would recommend a layered approach to authorization. Frontend and backend. Frontend - fetch the role of the user from DB. Then use something like RLS in Postgres to support row-level security. Then write RLS policies for each table that leverages the user roles. In supabase you can do this easily.
Amazing 🤩 I have been searching for years for this video. But never find this kind of your where all kind of permission handling discussed in a single video with all advantages and disadvantages. Thankyou for this video 🥳
Thanks! Great tip. I'm still working on a 20 year old application and rewrite it from scratch. I will use this advice. Top tip! Go forward with more of these practical topics.
As someone who works on a permissions team, glad to see some coverage about it. Not talked about much but is crucial to get right. And try not to roll your own authorization unless your companies unique demands call for it.
more in this topic please , people usually skip this part and use ready solution, but building it up from scratch and understanding this topics is what differentiates a good dev from the others
15:42 This is what I've come up with on my own and have used for quite a bit. It's great to have someone show me the limitations and then how to overcome them. Thank you!
I've just written a system using CodeIgniter and implemented security using Shield - which is there Role Based Access Control system. Very good and made like so much easier as things changed during development. Using if statements like "can a use do this" made development and security so much easier.
Lovely vid! First implementation is generally called CRUD, Create Read Update Delete. It's generally better to keep to the standard. The standar for all this called NIST INCITS 359-2012. My personal fav product for ABAC is called Axiomatics. Easy to work with both as dev and admin. The whole point of ABAC from an enterprise view is to place the complexity where it belongs - at the business level. A chief enterprise architect may at any time be responsible for several dev projects. Dealing with different authorization models for every system becomes needlessly complex for every one. From this perspective, devs with ABAC skills become very valuable.
Using Bitmasking makes it even easier. That also solves the problem of permission inheritance from various roles - that way you only end up with one permission set per user, don't have to work with roles directly.
@@milimilutinovic835 A bit difficult to explain in a comment, but let's try. Think of bits as permission flags. For instance, let’s say we have four permissions: Create, Read, Update, and Delete (C, R, U, D). These can be represented in binary as 1111, which equals 15 in decimal. A bit for each permission. If a user has all four permissions, you store the value 15 next to their name. To check if a user has a particular permission, you can use bitwise operations. Assign a unique decimal value to each permission: { create: 1, read: 2, update: 4, delete: 8 } Now, to check if a user has the "update" permission, simply do: userPermissions & systemPerms.update This operation returns a non-zero value if the user has the "update" permission (since bitwise AND compares corresponding bits and returns a match if both are set). To avoid running out of bit values, group permissions into categories: { homepage: { seeBanner: 1, clickButton: 2 }, users: { create: 1, update: 2, read: 4, delete: 8, allocate: 16 } } Now you can store decimal values for each category: { homepage: 1, users: 31 } When a user has multiple roles, you combine their permissions by adding the respective role values together. Bitwise operations allow you to modify permissions: Add permission: userPerms.users |= systemperms.users.delete; // Adds the 'delete' permission Toggle permission: userPerms.users ^= systemperms.users.delete; // Toggles the 'delete' permission Remove permission: userPerms.users &= ~systemperms.users.delete; // Removes the 'delete' permission Summary of operators: |= (OR assignment): Adds the specified bit to userPerms.users. If it’s already set, no change occurs. ^= (XOR assignment): Toggles the specified bit in userPerms.users. &= ~ (AND with negation): Removes the specified bit from userPerms.users. This approach efficiently manages permissions and scales well for larger applications with many roles and permissions.
@@milimilutinovic835 Think of bits as permission flags. For instance, let’s say we have four permissions: Create, Read, Update, and Delete (C, R, U, D). These can be represented in binary as 1111, which equals 15 in decimal. If a user has all four permissions, you store the value 15 next to their name. To check if a user has a particular permission, you can use bitwise operations. Assign a unique decimal value to each permission: { create: 1, read: 2, update: 4, delete: 8 } Now, to check if a user has the "update" permission, simply do: userPermissions & systemPerms.update This operation returns a non-zero value if the user has the "update" permission (since bitwise AND compares corresponding bits and returns a match if both are set). To avoid running out of bit values, group permissions into categories: { homepage: { seeBanner: 1, clickButton: 2 }, users: { create: 1, update: 2, read: 4, delete: 8, allocate: 16 } } Now you can store decimal values for each category: { homepage: 1, users: 31 } When a user has multiple roles, you combine their permissions by adding the respective role values together. Bitwise operations allow you to modify permissions: Add permission: userPerms.users |= systemperms.users.delete; // Adds the 'delete' permission Toggle permission: userPerms.users ^= systemperms.users.delete; // Toggles the 'delete' permission Remove permission: userPerms.users &= ~systemperms.users.delete; // Removes the 'delete' permission Summary of operators: |= (OR assignment): Adds the specified bit to userPerms.users. If it’s already set, no change occurs. ^= (XOR assignment): Toggles the specified bit in userPerms.users. &= ~ (AND with negation): Removes the specified bit from userPerms.users. This approach efficiently manages permissions and scales well for larger applications with many roles and permissions.
@@milimilutinovic835 consider a website with only one page, and the permission system controls who can read that page. We can write the permission data as a bit, if they can read it's 1; if they can't it's 0. Now this page got CRUD, 4 functions. Similar idea, we can have 4 bits to say this user can create but not others (1000); this user can read and update but not create nor delete (0110). By this way, instead of designating what role can do what, we can "stack" the roles easily. If a user has two roles: 1000 and 0110, then depends on your design, either he has privilege of 1110 or 0000, they can both be easily calculated thanks to bit masking. In C# this is abstracted(?) into Flags, in wrongly simplified way it's like enum but supports OR. if (UserRole.Admin | UserRole.Peasant), etc. Much simpler than bunches of booleans, as once frontend and backend promised upon one same chart of flags (i.e. which bit is needed for user to read this page), the value can be passed as simple numbers and then go on with the logics even more easier.
Loving the best practice videos you've been pushing lately. Can u make a video on which architectural design patterns to use for reactive frameworks like vue and react? Like mvc and mvvm?
typescript is such a blessing :) this is pretty nice, but this has one assumption, when you say what roles user has, you are giving positive authorization for a user, this is allow authorization, there is also negative case, deny authorization, that takes precedence over allow, and if you have multiple roles, you can setup in a way that if you have role hierarchy that is not additive, meaning each lower role is not a subset of higher role, then deny will be handy, you can add authorization to a user, for a role this is usually allow, but also for a permission, this can deny something, this way you can do role_level1 role_level2 role_level3, and level2 can do everything that level1 and something else, but level3 can include level2, and level1 and something else, but also exclude something that only level1 and level2 can do. its not my invention, some businesses work this way.
Beware clerk users!! public metadata in clerk is limited to 8KB which isn't enough for even a medium sized production application. We implemented ABAC (attribute based access control) using clerk's public metadata last year and we hit the ceiling a couple of months ago. Clerk is so buggy that instead of not letting you store data which exceeds the limit, it would put the client in an endless refresh loop. A pretty terrible oversight.
I feel like clerk overcomplicates everything here, seems much easier to just create the permission checking function ourselves (btw I just found CASL it seems really simple to use and it's free). I think this channel is great, but this video specifically is WebDevOverEngineered. And clickbait. I clicked expecting to see best practices on Permissions and how to structure them, instead I got baited lol. Didn't really go into depth on how to structure it yourself. Clerk is a third party with data limits. Also this video is clickbait. It's a sponsor. It's a clerk review. Total click bait. It's not a video focused on permissions, it's about Clerk... Also I totally missed where he said it's a sponsor. I know he said it, but I didn't see/notice him saying it.
@abdarker1043 I swear the clerk implementation details he described makes no sense to me. Why the hell would I do all that. Why use a lib that just checks keys inside User/Roles from a database, and has some obscure implementation steps and functions. Simple DB Relations with tables:Users/Companys/Roles/Perms already do all that.
I was sure he was about to raw dog the implementation so I was confused he talked about Clerk. Btw does that UI with the JSON have to do with Clerk? If so, that's a plus
Hi Kyle, Love your content! One minor suggestion: could you make the code editor and browser output colors consistent (both black or white) in your future videos? The current contrast makes it hard to watch.
Incredible work! A few days ago I looked for existing libraries for this type of permissions, but all of them were complicated and not so easy to use. Do you want to make an npm package?
Great Video and imho a really very clean solution regarding permission management. Thanks I have some concerns with Clerk. Maybe you could address them in a future video - it feels weird to store the most personal data with a 3rd party - and there are obvious GDPR concerns. Also what happens if clerk decides to shut down. - I know you have a paid cooperation with them - but could you do a video on those topics from a developer perspective. Maybe there are solutions for those issues. Working in the EU - with larger organisations, that share those concerns - it would be good to have answers from a developers perspective.
You only store username, email (for login, password reset) and, in this case, roles. You rarely need to give a 3rd party auth service more data than that.
You should also support "scope", so that users can delegate part of their permissions to third party (at least if you provide an API or something similar).
Another great vid Kyle. Always tough to see your stuff on phone with small font but usually fine to zoom the device for detail. Please try to minimize size of less relevant visual artifacts, perhaps including your face. 😂
Hi Kyle, thank you for this tutorial. I learn a lot from your tuts and saving to enroll on your course. Just wondering, why you choose to use {actions:resource} but not the other way around? I am thinking {resource:action} would be more readable and we can group them easily. We can have {resource:*} as well to allow all actions on the resource.
When will you start working on a MERN microservice or microfrontend architecture? All your previous projects have been monolithic. Please consider creating an e-commerce application using a microfrontend and microservice architecture
ABAC is pretty nice. I’ve been pondering how gdrive does it lately. However, the final example does not implement the generic resource-user-role table approach, it is the uber copy/paste approach 😢
32:46 why user "3" has update and delete permission even though blocked by user "2" edited: I thought user "3" should be blocked from every access user "2" provides... Nice implementation tho... I was doing some .Net roles and permissions stuff on the backend and this is lit
I don't plan on expanding this to storing in a DB. If you wanted to store this in a DB you would need to not use functions and instead store your data in a form like JSON which you could then use to do checks with. For example you could store something like { authorId: "eq({userId}" } in JSON to signify the authorId must equal the current user's id.
Take a look at CEL expressions. You could store code in the form of these expressions in the database and then evaluate them when the actual permission check happens.
Thanks Great video!! we wanted to use clerk as well but the problem with that is we started our project with manual role based auth. we are using trpc, prisma and zenstack. If you can make a video around these stack with clerk that would be very helpful.
I think it's about 3000 elements where it starts to be faster to get the from a hashmap. Below 3000 elements itsfaater to iterate through an array and check each element. In some contexts it's 3000, in others 10000
I remember before understanding access control I accidentally over engineered my way up to inventing a terrible abac. It wouldn’t surprise me at all if that site is still using most of my newbie code haha
Very interesting video. But I'm not sure whats the best practice to design backend DB queries to take this into consideration. Example has hard-coded data, which is the same as fetching all records from database and filtering it based on roles. But this is not optimal for DB querying. In example, if my users are split into departments, and my user has permissions only to view users from his own department, and he requests the list of users from backend... I need to add to query something like "where departmentId = user.departmentId". Of course, I can hard-code this into API requst (get user's departmentId from auth session data), but is this good practice? It seems I'm just spreading permissions data configuration from a single place (permissions file/db) into code.
In Rails I usually use the cancancan library for exactly this type of stuff. The problem usually comes when I need to expose the permissions for the client when making an SPA. How does Clerk do that? Do they serialize the permissions somehow, or is it just an extra http call everytime you check a permission on the client?
I created a Permission manager class and have added the static methods in it which works perfectly fine for actions I m driving the method which I want to calls and get the value which is way a lot easier without depending on third party packages 😅
Hey, could you make a video which handles server side rendering for react other than the framework such as next, etc. Like to learn how to make use of custom ssr react, maybe with vite initial start up and deploy on ec2
Could you please create a Project by watching and checking it with a Figma file having any design and upload that video to this channel so that we learn & get benefits? We need to learn the strategy to complete a project fast through Figma.
With this approach, if we have multiple front-ends (mobile app, desktop app) we would have to duplicate and maintain the permissions setup in each of them. Shouldn't this be centralized in the server with an api endpoint to which you send the subject, action, resource and any extra data, so it returns whether the user is allowed or not? Regarding security, just as a reminder, this is front-end permissions just to show or not buttons, full sections or whatever which is not secure by definition. The real security controls should always be implemented at server level (or db?)
A common case is that Roles are unknown, as users can create their own and assign permissions to each role. In other words, there is no point in handling roles, besides from a UX perspective?
Cool, but permissions aren't always simply about what action can be done on a resource. They can be much more complicated, like how many of something can be done or for how often or at what times, etc. But the basic ideas is to define a Permissions object in addition to the usual Role.
One thing I don't see with you solution is how does that scale? Let's say you have hundreds of roles, and thousands of permissions, do you define a rule for each action on every resource in your system? I'd say another logical approach is to go with the RBAC approach, but just add scoping to it. Of course it wouldn't be as flexible, but you'd at least be able to dynamically add permissions and assign users to them, even from within your application, but I don't see how you'd do that with the last approach you gave.
This system is specifically meant to scale to incredibly large numbers of permissions and roles. Yes you would need to define specific rules for each role/action, but you can also create helpers that make this easier (for example having an "all" key that gives a user permissions for all actions on a resources, or grouping resources to make assigning actions easier)
Try Clerk: go.clerk.com/b2b-orgs
I like how over time your channel covers more and more advanced topics. I feel like I've been growing in my career in a similar pace, so you always have me covered! Thank you
you are wrong. What you are doing is consuming precisely targeted ads. This video is nothing more than an advertisement. He didn't even mention free/open source alternatives. Every second of this video is designed to attract you to the clerk's product.
@@xaweeeed33rt5g43wsd the permission logic is the same regardless of what auth provider you use though. You expect to consume his videos for free then complain when he gets someone else to pay him to continue teaching for free.
@@xaweeeed33rt5g43wsdso what? The auth process stays the same without clerk and also that’s some great learning material and good explanation he’s done.
@Mac501pl Me too 😅
26:00 , "I am not really that great at typescript", says the guy who is my and many other self taught coders' favourite teacher.
Take a bow man.
Great video!!! It's important to note that you have to handle permissions for both the client display AND the database action. For example, if you display the delete button for your own comments and clicking it results in `DELETE /api/comments/123` and someone can find the ID of another comment (maybe by looking at the XHR request for the listing page of comments) and issues their own DELETE fetch request to the other comment, your backend or DB has to also check permissions and not just delete the comment. Postgres can do row-based and column-based policies that makes that a lot easier to do that particular check on the backend.
But why would you move authorization logic to the db layer really. A server app layer can handle this comfortably. Unless you share and touch db outside of the app, or are serving client app straight from db eg firebase, i would not advise for that. Db should be kept as simple as possible.
@warrenarnoldmusic that's why I said either do it on the backend or DB. One over the other and what "should" be done is a preference / philosophical question, making sure a client side request is validated for authorization is not a question, but a requirement.
@@warrenarnoldmusicyou could even consider building a dbase access layer. The server should only use that layer. Any program accessing that dbase should use that access layer. It enables access control to be shared.
I would recommend a layered approach to authorization. Frontend and backend. Frontend - fetch the role of the user from DB. Then use something like RLS in Postgres to support row-level security. Then write RLS policies for each table that leverages the user roles. In supabase you can do this easily.
let me made it simpler what this guy says is just do not directly update the db, do check is this from the same user or not
IAM professional here. Great job showing devs solid principals that can be applied to most projects, Clerk or not.
Amazing 🤩 I have been searching for years for this video. But never find this kind of your where all kind of permission handling discussed in a single video with all advantages and disadvantages. Thankyou for this video 🥳
This is possibly one of the best resources hands down, on the topic.
You did a great job!
CASL is a great library with many integrations for handling complex decisioning like this
+1 for CASL
+1
Initial it is hard to me to work with it but now I now how powerful and simple
casl team 👊
I wouldn't be surprised if Clerk uses CASL internally
Thanks! Great tip. I'm still working on a 20 year old application and rewrite it from scratch. I will use this advice. Top tip! Go forward with more of these practical topics.
Please do this more often, This is something I would learn everyday.
This guy puts out quality educational content and for free !!!
Thanks man
the problem is free, the solution is a paid service, so...
its been 4 min and I already feel the whole video will be worthwhile
It will be worthwhile if you're a beginner
@@StingSting844 yeah I dont think seniors are watching videos on youtube on how to do auth, thanks for pointing the obvious
As someone who works on a permissions team, glad to see some coverage about it. Not talked about much but is crucial to get right. And try not to roll your own authorization unless your companies unique demands call for it.
more in this topic please , people usually skip this part and use ready solution, but building it up from scratch and understanding this topics is what differentiates a good dev from the others
15:42 This is what I've come up with on my own and have used for quite a bit. It's great to have someone show me the limitations and then how to overcome them. Thank you!
Another great tutorial from one of the best content creators on TH-cam!!! Keep it up man
I've just written a system using CodeIgniter and implemented security using Shield - which is there Role Based Access Control system. Very good and made like so much easier as things changed during development. Using if statements like "can a use do this" made development and security so much easier.
Lovely vid! First implementation is generally called CRUD, Create Read Update Delete. It's generally better to keep to the standard. The standar for all this called NIST INCITS 359-2012. My personal fav product for ABAC is called Axiomatics. Easy to work with both as dev and admin.
The whole point of ABAC from an enterprise view is to place the complexity where it belongs - at the business level. A chief enterprise architect may at any time be responsible for several dev projects. Dealing with different authorization models for every system becomes needlessly complex for every one. From this perspective, devs with ABAC skills become very valuable.
Using Bitmasking makes it even easier. That also solves the problem of permission inheritance from various roles - that way you only end up with one permission set per user, don't have to work with roles directly.
Could you please elaborate on this interesting suggestion
@@milimilutinovic835 A bit difficult to explain in a comment, but let's try.
Think of bits as permission flags. For instance, let’s say we have four permissions: Create, Read, Update, and Delete (C, R, U, D). These can be represented in binary as 1111, which equals 15 in decimal. A bit for each permission.
If a user has all four permissions, you store the value 15 next to their name.
To check if a user has a particular permission, you can use bitwise operations. Assign a unique decimal value to each permission:
{
create: 1,
read: 2,
update: 4,
delete: 8
}
Now, to check if a user has the "update" permission, simply do:
userPermissions & systemPerms.update
This operation returns a non-zero value if the user has the "update" permission (since bitwise AND compares corresponding bits and returns a match if both are set).
To avoid running out of bit values, group permissions into categories:
{
homepage: { seeBanner: 1, clickButton: 2 },
users: { create: 1, update: 2, read: 4, delete: 8, allocate: 16 }
}
Now you can store decimal values for each category:
{
homepage: 1,
users: 31
}
When a user has multiple roles, you combine their permissions by adding the respective role values together.
Bitwise operations allow you to modify permissions:
Add permission:
userPerms.users |= systemperms.users.delete; // Adds the 'delete' permission
Toggle permission:
userPerms.users ^= systemperms.users.delete; // Toggles the 'delete' permission
Remove permission:
userPerms.users &= ~systemperms.users.delete; // Removes the 'delete' permission
Summary of operators:
|= (OR assignment): Adds the specified bit to userPerms.users. If it’s already set, no change occurs.
^= (XOR assignment): Toggles the specified bit in userPerms.users.
&= ~ (AND with negation): Removes the specified bit from userPerms.users.
This approach efficiently manages permissions and scales well for larger applications with many roles and permissions.
@@milimilutinovic835 Think of bits as permission flags. For instance, let’s say we have four permissions: Create, Read, Update, and Delete (C, R, U, D). These can be represented in binary as 1111, which equals 15 in decimal.
If a user has all four permissions, you store the value 15 next to their name.
To check if a user has a particular permission, you can use bitwise operations. Assign a unique decimal value to each permission:
{
create: 1,
read: 2,
update: 4,
delete: 8
}
Now, to check if a user has the "update" permission, simply do:
userPermissions & systemPerms.update
This operation returns a non-zero value if the user has the "update" permission (since bitwise AND compares corresponding bits and returns a match if both are set).
To avoid running out of bit values, group permissions into categories:
{
homepage: { seeBanner: 1, clickButton: 2 },
users: { create: 1, update: 2, read: 4, delete: 8, allocate: 16 }
}
Now you can store decimal values for each category:
{
homepage: 1,
users: 31
}
When a user has multiple roles, you combine their permissions by adding the respective role values together.
Bitwise operations allow you to modify permissions:
Add permission:
userPerms.users |= systemperms.users.delete; // Adds the 'delete' permission
Toggle permission:
userPerms.users ^= systemperms.users.delete; // Toggles the 'delete' permission
Remove permission:
userPerms.users &= ~systemperms.users.delete; // Removes the 'delete' permission
Summary of operators:
|= (OR assignment): Adds the specified bit to userPerms.users. If it’s already set, no change occurs.
^= (XOR assignment): Toggles the specified bit in userPerms.users.
&= ~ (AND with negation): Removes the specified bit from userPerms.users.
This approach efficiently manages permissions and scales well for larger applications with many roles and permissions.
@@milimilutinovic835 consider a website with only one page, and the permission system controls who can read that page. We can write the permission data as a bit, if they can read it's 1; if they can't it's 0.
Now this page got CRUD, 4 functions. Similar idea, we can have 4 bits to say this user can create but not others (1000); this user can read and update but not create nor delete (0110).
By this way, instead of designating what role can do what, we can "stack" the roles easily. If a user has two roles: 1000 and 0110, then depends on your design, either he has privilege of 1110 or 0000, they can both be easily calculated thanks to bit masking.
In C# this is abstracted(?) into Flags, in wrongly simplified way it's like enum but supports OR. if (UserRole.Admin | UserRole.Peasant), etc.
Much simpler than bunches of booleans, as once frontend and backend promised upon one same chart of flags (i.e. which bit is needed for user to read this page), the value can be passed as simple numbers and then go on with the logics even more easier.
Thank you so much! I was just implementing RBAC on a huge project today, but Im going to change it to ABAC!
This is awesome because you helped me get a job, and now you're helping me keep it!
User -> Action -> Resource
User = Id
Action = CRUD
Resource = Type, Id
Role = Action + Resource
Roles are a simplification.
Loving the best practice videos you've been pushing lately. Can u make a video on which architectural design patterns to use for reactive frameworks like vue and react? Like mvc and mvvm?
What perfect timing for me that you put this video out. Thanks!
I like Bouncer authorization system from Adonis. It's the most straightforward one I have ever seen
Wow, Thanks Web Dev Simplified Very Helpful please Continue Making Videos For advanced Topics
This came just in time!
I was going to implement security on my api today, this was a god sent
Great video and I love the last approach. Thanks for the tutorial and for all the quality knowledge you share on the channel.
This is a good example of using exhaustive type systems to remove stringly-typed APIs. Very useful.
Imagine how much better it would be in Rust! 😉
typescript is such a blessing :) this is pretty nice, but this has one assumption, when you say what roles user has, you are giving positive authorization for a user, this is allow authorization, there is also negative case, deny authorization, that takes precedence over allow, and if you have multiple roles, you can setup in a way that if you have role hierarchy that is not additive, meaning each lower role is not a subset of higher role, then deny will be handy, you can add authorization to a user, for a role this is usually allow, but also for a permission, this can deny something, this way you can do role_level1 role_level2 role_level3, and level2 can do everything that level1 and something else, but level3 can include level2, and level1 and something else, but also exclude something that only level1 and level2 can do. its not my invention, some businesses work this way.
Beware clerk users!! public metadata in clerk is limited to 8KB which isn't enough for even a medium sized production application. We implemented ABAC (attribute based access control) using clerk's public metadata last year and we hit the ceiling a couple of months ago. Clerk is so buggy that instead of not letting you store data which exceeds the limit, it would put the client in an endless refresh loop. A pretty terrible oversight.
Just curious, what data did you put in there? I mean 8kB is huge isnt it? I guess not only stuff related to ABAC?
@@KWerder92 mainly an array of features and routes. 8kb is not that much when storing JSON.
Real devs make their own clerk
This is some good stuff. I was facing a similar problem in work. Thank you.
Looking forward to more content like this! Great video, by the way-very informative.
I feel like clerk overcomplicates everything here, seems much easier to just create the permission checking function ourselves (btw I just found CASL it seems really simple to use and it's free). I think this channel is great, but this video specifically is WebDevOverEngineered. And clickbait. I clicked expecting to see best practices on Permissions and how to structure them, instead I got baited lol. Didn't really go into depth on how to structure it yourself.
Clerk is a third party with data limits. Also this video is clickbait. It's a sponsor. It's a clerk review. Total click bait. It's not a video focused on permissions, it's about Clerk... Also I totally missed where he said it's a sponsor. I know he said it, but I didn't see/notice him saying it.
plus who uses a 3rd party for this? this is suitable for school projects
@abdarker1043 I swear the clerk implementation details he described makes no sense to me. Why the hell would I do all that. Why use a lib that just checks keys inside User/Roles from a database, and has some obscure implementation steps and functions. Simple DB Relations with tables:Users/Companys/Roles/Perms already do all that.
I was sure he was about to raw dog the implementation so I was confused he talked about Clerk.
Btw does that UI with the JSON have to do with Clerk? If so, that's a plus
Hi Kyle,
Love your content! One minor suggestion: could you make the code editor and browser output colors consistent (both black or white) in your future videos? The current contrast makes it hard to watch.
Thanks Kyle! The video is phenomenal! So professional, great work!
loving these content lately. thanks.keep cooking
I love senior dev contents ~
Quality content appreciates your efforts man.
Incredible work! A few days ago I looked for existing libraries for this type of permissions, but all of them were complicated and not so easy to use.
Do you want to make an npm package?
Great Video and imho a really very clean solution regarding permission management. Thanks
I have some concerns with Clerk. Maybe you could address them in a future video - it feels weird to store the most personal data with a 3rd party - and there are obvious GDPR concerns. Also what happens if clerk decides to shut down. - I know you have a paid cooperation with them - but could you do a video on those topics from a developer perspective. Maybe there are solutions for those issues. Working in the EU - with larger organisations, that share those concerns - it would be good to have answers from a developers perspective.
You only store username, email (for login, password reset) and, in this case, roles. You rarely need to give a 3rd party auth service more data than that.
You should also support "scope", so that users can delegate part of their permissions to third party (at least if you provide an API or something similar).
Another great vid Kyle. Always tough to see your stuff on phone with small font but usually fine to zoom the device for detail. Please try to minimize size of less relevant visual artifacts, perhaps including your face. 😂
Hi Kyle, thank you for this tutorial. I learn a lot from your tuts and saving to enroll on your course. Just wondering, why you choose to use {actions:resource} but not the other way around? I am thinking {resource:action} would be more readable and we can group them easily. We can have {resource:*} as well to allow all actions on the resource.
Either works. I find that it reads more like English to say create:thing than to say thing:create
Thank you so much for everything, can you please continue also with more video with javascript :)
removing clerk, everything said here, is what I thought I invented for a system. glad that what I did is actually a real-world practice.
Sage advice. SAP has been doing it this way for decades
sponsored shit show
Best dev content on TH-cam
Love the masterclass episodes!
Thanks. I have really enjoyed making them!
😭😭😭😭 thank you so much for making this
Great content! Need more videos like these❤
Bro never fails to deliver.
Would love to see oauth, jwt token for viewing images.
When will you start working on a MERN microservice or microfrontend architecture? All your previous projects have been monolithic. Please consider creating an e-commerce application using a microfrontend and microservice architecture
need masterclass on how to set hair like you
Exactly when i needed it! thanks goat
The video was really nice!
can you make a video on how to use the clerk webhook directly?
ABAC is pretty nice. I’ve been pondering how gdrive does it lately. However, the final example does not implement the generic resource-user-role table approach, it is the uber copy/paste approach 😢
32:46 why user "3" has update and delete permission even though blocked by user "2"
edited: I thought user "3" should be blocked from every access user "2" provides...
Nice implementation tho... I was doing some .Net roles and permissions stuff on the backend and this is lit
Thanks. Could you add a video on how to store the roles & permissions (especially the Functions for the resource itself) inside Database?
I don't plan on expanding this to storing in a DB. If you wanted to store this in a DB you would need to not use functions and instead store your data in a form like JSON which you could then use to do checks with. For example you could store something like { authorId: "eq({userId}" } in JSON to signify the authorId must equal the current user's id.
@WebDevSimplified yes, I like this approach. That can work. Thanks for this informative video 😊
Take a look at CEL expressions. You could store code in the form of these expressions in the database and then evaluate them when the actual permission check happens.
Thanks Great video!! we wanted to use clerk as well but the problem with that is we started our project with manual role based auth. we are using trpc, prisma and zenstack. If you can make a video around these stack with clerk that would be very helpful.
3:50 I'd make those inner arrays into maps - `"permission": true` for faster checks 😉
3:55 change arrays into set. It's require more memory, but I'll check these permissions very often, so it's better avoid extra iterations
I think it's about 3000 elements where it starts to be faster to get the from a hashmap. Below 3000 elements itsfaater to iterate through an array and check each element. In some contexts it's 3000, in others 10000
Hey Kyle, there's an extension of vs code that hides .env values for recording purposes.
Hope it helps
Thanks for letting me know, but I have no issues showing my .env file since I always delete my keys after recording a video.
Heya Kyle 😎. Love your contents man
Can you make a playlist with all of your "Like A Senior Dev" videos please ?
I remember before understanding access control I accidentally over engineered my way up to inventing a terrible abac. It wouldn’t surprise me at all if that site is still using most of my newbie code haha
bro youtube is missing your zustand crash course please consider it for your next video
Thanks! Really good video.
Very interesting video. But I'm not sure whats the best practice to design backend DB queries to take this into consideration. Example has hard-coded data, which is the same as fetching all records from database and filtering it based on roles. But this is not optimal for DB querying. In example, if my users are split into departments, and my user has permissions only to view users from his own department, and he requests the list of users from backend... I need to add to query something like "where departmentId = user.departmentId". Of course, I can hard-code this into API requst (get user's departmentId from auth session data), but is this good practice? It seems I'm just spreading permissions data configuration from a single place (permissions file/db) into code.
Great video, but can you cover what extensions you have running in VS?
I think RBAC is Ok for relatively simple projects. Others are including the sponsored one is for huge projects
Banga vid my dude
This is really good one i watched full video 🔥🔥🔥🔥
In Rails I usually use the cancancan library for exactly this type of stuff. The problem usually comes when I need to expose the permissions for the client when making an SPA. How does Clerk do that? Do they serialize the permissions somehow, or is it just an extra http call everytime you check a permission on the client?
I was just about to implement this. Nice
this is gold, thanks!!!!
I created a Permission manager class and have added the static methods in it which works perfectly fine for actions I m driving the method which I want to calls and get the value which is way a lot easier without depending on third party packages 😅
Kyle is not teacher he is content creators 😊😊
you taught me to do permissions like that 0:01 few years ago 😆
What do you do/use to sort your code to make it look better and align?
Awesome video! Could you please also make a tutorial on implementing ABAC with node.js?
Everything in this video is applicable to Node.js as I used no React specific features.
@@WebDevSimplifiedRight, but a tutorial showing ABAC with database integration would be really helpful! Thanks!
Hey, could you make a video which handles server side rendering for react other than the framework such as next, etc. Like to learn how to make use of custom ssr react, maybe with vite initial start up and deploy on ec2
wow new guitar ! is that 7 strings ?
Could you please create a Project by watching and checking it with a Figma file having any design and upload that video to this channel so that we learn & get benefits?
We need to learn the strategy to complete a project fast through Figma.
maybe I am wrong, but at 32:52, when use 3 is blocked by user 2, it doesn't have view permission, how it still has update and delete permission?
another banger of a tetorial
can u explain the typescript behind the keyof and typeof in the ROLE constant ?
Next episode: Super ultimate pro max ultra senior ?
35:00 Basically everyone who flexes with typescript 😬
Next video idea, user-defined order for rows in SQL.
It's right on time.❤
Thanks Kyle…..more “brain dead easy” content please!😂
Great video !!!
With this approach, if we have multiple front-ends (mobile app, desktop app) we would have to duplicate and maintain the permissions setup in each of them. Shouldn't this be centralized in the server with an api endpoint to which you send the subject, action, resource and any extra data, so it returns whether the user is allowed or not?
Regarding security, just as a reminder, this is front-end permissions just to show or not buttons, full sections or whatever which is not secure by definition. The real security controls should always be implemented at server level (or db?)
A common case is that Roles are unknown, as users can create their own and assign permissions to each role. In other words, there is no point in handling roles, besides from a UX perspective?
Very helpful 👍🏻
It's as if you knew exactly what I'm currently working on
this is such a great video ..
Cool, but permissions aren't always simply about what action can be done on a resource. They can be much more complicated, like how many of something can be done or for how often or at what times, etc. But the basic ideas is to define a Permissions object in addition to the usual Role.
One thing I don't see with you solution is how does that scale? Let's say you have hundreds of roles, and thousands of permissions, do you define a rule for each action on every resource in your system? I'd say another logical approach is to go with the RBAC approach, but just add scoping to it. Of course it wouldn't be as flexible, but you'd at least be able to dynamically add permissions and assign users to them, even from within your application, but I don't see how you'd do that with the last approach you gave.
This system is specifically meant to scale to incredibly large numbers of permissions and roles. Yes you would need to define specific rules for each role/action, but you can also create helpers that make this easier (for example having an "all" key that gives a user permissions for all actions on a resources, or grouping resources to make assigning actions easier)
@WebDevSimplified thank you for this video and replying!