Fyi on v6 of CASL the Ability class is deprecated, instead you need to use “createMongoAbility”. For example at 8:04 you should instead use: const builder = new AbilityBuilder(createMongoAbility)
Keep up the great content. I appreciate how you get to the point and assume the viewer has knowledge fundamentals on any included topics (NestJS, Casl). It makes your video title truthful and allows you to dive deeper into the topic without making it too long. Also really appreciate your edits and how clean they are. Not sure how you do it honestly. Keeping the audio going seamlessly while cutting out typos and cutting in typo fixes. Subbed!
Your nestjs authentication video helped me land my first full time Job in tech and now your videos are helping me keep it. Keep up the good work, you're awesome.
What I personally do is create 2 SetMetadatas, one for the controller to set the entity to use at class level (ex: @SetEntity(User)), and the second one to set the required permission at method level (ex: @RequiresPermission(Action.Update)). Then all the logic to get the entity instance and check for permission is in the AbilityGuard.
UPD: I had to rewrite my comment because my previous comment got spammed because of the link to my GitHub (Marius, unblock it, please :) there's a lot of useful information for other people and, maybe, for your next video). Yeah, I did the same thing. I need to hide data from the user based on his rights and protect my endpoints via action rights. So I created @RequiredRights decorator and ActionRights Guard where I check if the user has required rights or not, also I created @Public decorator to mark endpoints that don't require authorization. To hide data from users, I used class-transformer, custom RightsBasedSerializer Interceptor and @SetResponseTransformationType decorator to explicitly mark what type my endpoint returns. I think my way is more convenient than CASL.
Interesting ideas, thanks I will explore those!! RagNCode: sorry youtube will automatically delete if you post a link, it’s not even held for review on my end, it’s gone
@@mariusespejo If you will need more information, my github nickname is GrapeoffJS, go to CRMServer repo and switch to refactoring branch (pls don’t look at the master branch, there are a lot of messy code, i am embarrassing :)) It seems there’s no information about my method in the internet, so I had to come up with it by myself, so if you are really inspired by this, my repo can help you I think.
You're so underated dude like for real!! I'm really inspired so much because of you. Plan to make a TH-cam Channel that also cover Nest.js if I lucky enough, ha! Wish me luck.
Go for it! I personally hesitated for way too long. Best advice honestly is to just try it. You can get a pretty good sounding usb microphone for fairly cheap nowadays. That’s all you really need! It’s not even about luck honestly, mostly just about being persistent. But good luck anyways!
@deprecated use createMongoAbility function instead and MongoAbility interface. In the next major version PureAbility will be renamed to Ability and this class will be removed 'Ability' is deprecated. Maybe you could update the tutorial or use Casbin instead. Great content, smooth approach to teaching
Good callout, it a minor thing though I wouldn’t make an entirely new video just for that. I did add a pinned comment to mention it. As for casbin, not very familiar, but I would personally pick a library purposely built for JS rather than just having a JS version of it.
I was studying for an interview and nestjs was a requirement. I think I've watched all nestjs videos on this channel at least twice (5 times the teamseas one lol) and now I'm making almost 5 times what I used to do at my old job. Still not sure if I'm dreaming lol
I'm really liked your nestjs playlist, because of it's easy to understand explanations, Thanks a lot. Could you make a video about file uploading in NestJS?
2 years later and this is very very helpful to me. Thanks. One question though, I am trying to have that kinda policies guard, but I'm having a difficulty pulling the data for the user to do the can check. Any links to read up please?
Thank you for the video. You explain it great. It would be great if you could explain this in the context of Angular. How can I display pages only for certain users?
The fundamentals to understand is that you need to define the permissions and do ability.can() checks where you need to do it.. e.g. you might have ability.can(‘read’, ‘dashboard’) … how you enable/disable routes in your app based on the outcome of that check however is up to you
Great tutorial thanks for your work, you are great. later can we have a tutorial on integration of multer in a nestjs api for the file and image upload
Nice content mate! Nice to be learning NestJS Auth in this video. BTW what extension did you use to make that fade grey text intellisense appear when you are typing the code?
I did cover several examples of using the custom decorator for the get/delete. It’s the same exact concept, I recommend go back and review that pattern. Setup your ability to add can/cannot for updates. User the decorator to say that your controller method requires that it can update that subject.
I have the same question on this topic recently. I implemented the rbac model using casbin to manage Nest Guard Middleware. Maybe I can consider CASL as another strategy choice. Nice introduction, so good!
@@timchen3062 Can you please share your repo link (if it is public) where you implemented casbin for Nest Guard Middleware, or you can guide me to some resource for the same. Thanks
not at the moment, likely won't cover Angular to be honest. If you want your app to deploy to together as one, then you need to setup your pipeline to statically build your angular SPA and have it served up by nest using serve static: docs.nestjs.com/recipes/serve-static
Great video again. Thank you. I tried nest-casl package. U may extend this subject with that package. And in addition, what do u think about custom logging. For detailed logs I need req in logs and pino offers that?
Nest-casl is pretty much just a slightly different implementation of the same thing we did here, only benefit is perhaps slightly less setup. For logging, Nest comes with a built in logger if you check the docs, it’s fairly basic. If it’s not good enough for you you can pretty much use any logger library out there and use it as middleware
Hey, I really like your teaching style. Have you considered a full-blown nest course eg with mongo db (full project a-z) ? I'm sure you'd get a lot of participants on udemy!
I'm getting following error `Conversion of type 'Function' to type '"all"' may be a mistake because neither type sufficiently overlaps with the other.` on detectSubjectType, which is correct. Why aren't you getting this?
Potentially, I do want to cover prisma in general in more detail as I learn more about it. As for the casl integration if you need it sooner: as long as you have a good understanding of both prisma and casl, their docs seem straightforward (although I haven’t tried it personally) casl.js.org/v5/en/package/casl-prisma
Hi marius, i really like you tutorials and helped me a lot. I had a concern about, if a i had another endpoint, like, not a crud endpoint, how i protect them? Or i should had a endpoint like that?
Not sure I understand your question. Auth really has nothing to do with whether or not it’s a crud endpoint. You would protect any endpoint basically in the same way, it’s all the same fundamentals. With Nest specifically you would use guards to do most of your auth checks
Ok, I'll rephrase, I have endpoints different from those of basic CRUD, for example, getall, get, update, delete and create, I have endpoints on the user to add groups, @post /add-user, it is not a common update, as Only some users will be able to do this, not everyone with write permission. How could I do this granular control using casl. Or should I not have an endpoint like that? and only use the common update, e.g. @patch /User.
I made some tables, like services and groups, i group can have many services, and one User can hava many Groups. My service table is like: Route, Method, Name, Description. So if a have one group with one service, i can do the request to that service endpoint. I want my guard check if my user have that service. I using the right approach? i dont know, but this is what i´m doing. Pls give a light about it
Re: your question about /add-user, with CASL you should be able to define granular control. I thought that I covered that in this video but if not, there is another video in my channel where I introduce CASL in detail. But basically you would define an ability off of the “User” subject, such as can( ‘create’, User, conditions ) // what conditions is up to you, e.g. { accessLevel: ‘X’ } Every user then would then have their ability built off those rules that you put into place. If you have a dedicated route for /add-user then you could protect that with a custom guard such as @RequirePermisssions(Permission.CREATE_USER) Which internally would simply check userAbility.can(‘create’, User) If you instead had a common update endpoint, and wanted granular control depending on what field they are updating then you would do something like If (dto.someProperty && userAbility.cannot( ‘update’, User, [ ‘someProperty ] ) then throw new ForbiddenException() Basically whatever your granular restrictions are, CASL should be able to model with a combination of action, subject, fields, and conditions. Once you have that model created, you simply create the ability object for each user, and you can do your checks either in guards or within the service layer. It’s up to you. I suggest reviewing CASL docs in detail for all of this to make sense
coming from PHP/Laravel, setting this up is complicated compared to as how simple Gates are being implemented in Laravel. well this is expected as this is an external package.
The setup with Nest I think comes off complex because you have to line up the type definitions to make TS happy, and potentially make custom decorators, but the package itself is fairly simple and easy to use. But maybe laravel is really just simpler lol I’m not familiar
That’s why you would set up something like CASL or similar, as a tool to check what access users have before performing an action. E.g. if the user is not allowed to see everything you either completely prevent it or you automatically filter by changing your filter to a “find where access matches x user’s privileges/role)
@@mariusespejo Ok and what if the user can read some entity, and by extent he can read other entities related to it. How would I do that? something like can(Action.Manage, EntityX); can(Action.Manage, EntityY, where: {idEntityX = idEntityX});
@@mariusespejo sure I will looking in that tutorial. But I need admin can signup/login and create post. I am enum role user and admin where default is user and when i am trying to signup with a admin account but at that times give error. As simply admin account is not created. I used prisma as pg db is there, package use passportjwt, passwortlocal
CASL doesn’t care however many “organizations” you might have, if you can represent the rules to create the ability for it, then it should work. Again it’s just a mixture of can and cannots. e.g. apply certain rules/ability given the user’s organization and whatever other conditions you might have, that’s totally doable
Guards have access to the request and can extract that. But if you’re talking about the decorator that simply sets metadata I don’t think that has access to it. If I understand what you might be trying to achieve, it means you’ll have to create a custom guard that constructs the ability dynamically
@@mariusespejo so I have a user object which contains a list of posts which the user has access to, so when the user is trying to call a GET /posts/:id I would need to check if this user has permissions for reading this particular post. What would be the best way to achieve this?
Well with CASL you’d achieve that by creating a condition like can(‘read’, Post, { id: { $in: user.postIds } }) Basically your user ability that you create should have that defined in there, then at the time of access checking you just need to perform const post = await getPost(id); ability.can(‘read’, post); Although technically all you need is the Id, which you already have, so you probably don’t need to query the post upfront. So you’d have to work with your subject detection, so maybe you’d create a partial/psuedo post like const post = new Post(); post.id = id; can(‘read’, post); You can do that logic within a custom guard for example. Hope that helps! For more ideas I suggest look through the docs more, ask around in stackoverflow, etc.
Having the "isAdmin" property kinda defeats the purpose of PBAC? I was thinking on having all my permissions/grants stored on the database and act on them, not on the "isAdmin" property.
It’s just an extremely simple example of creating abilities off of the data that you have, obviously a real-world example would not be that simple. You absolutely can store your permissions on the database, casl allows you to initialize abilities off of json (for scenarios where the rules are dynamic or remote like yours). My original Casl video just before this one talk about it towards the end, or feel free to check the docs
Amazing tutorial, very effective learnt nestjs from your channel. I have been implementing casl with nestJs, although I am using database persisted permissions using mongoose. but am not able to understand how to check the ability. I have collection of roles:{role, permissionId[]} and a permissions:{action, subject,condition} collection which contains all the permissions. And I have defined ability factory with the Ability constructor and passed the authenticated user permissions in it. The only issue is how can I implement gaurd so that I don't have to rewrite the defineAbility and ForbiddenError logic in each controller methods. Also is it possible to use Gaurd while using casl-mongoose. Please help me!!
The purpose of guard is exactly so that you can define that logic in one place and not have to keep re-writing it so I’m not sure I understand your question. Your guard should be reusable. If you have that role/permission info in your database then you need to query it and map it to to an ability… once you have the ability it’s just a matter of checking authorization via can(). The fundamentals is pretty much what I covered in the video
@@mariusespejo Thanks for the quick response, I have been reading the casl documentation: cookbook/roles-with-persisted-permissions and in that documentation, it shows how to check the ability using ForbiddenError class: ForbiddenError.from(ability).throwUnlessCan('create', subject('Article', partialArticle)); here in this statement the second argument is the subject of the ability, in this case, it is the Article model and also a partialArticle object which they are creating. But the Gaurd which I have used in the project is using the ForbiddenError class to check the ability for each rule: rules.forEach((rule) => { ForbiddenError.from(ability).throwUnlessCan(rule.action, rule.subject) }) here I won't be able to pass the article which I am creating or looking for
Whatever you’re trying to have different between environments should be mostly handled by environment variables, e.g. if you have different database connections then that should be just coming in via env variables
Nice video. However, I would suggest that you don't ever add business or auth logic to controller methods - that's what services are for. You can derive the user from cookies or JWT via guards. Posting this comment at 17:44
Guards are actually the more proper place to do it, not services, which I did cover I believe if you watched the rest. And yes that is correct all business logic generally should be in services, but guards are meant to be used for both authentication and authorization.
hello, Marius, thank you for your wonderful tutorial, but I'm stuck on this error: Nest can't resolve dependencies of the AbilityFactory (?). Please make sure that the argument CASL_FEATURE_OPTIONS at index [0] is available in the AbilityModule context. Possible solutions: - If CASL_FEATURE_OPTIONS is a provider, is it part of the current AbilityModule? - If CASL_FEATURE_OPTIONS is exported from a separate @Module, is that module imported within AbilityModule? @Module({ imports: [ /* the Module containing CASL_FEATURE_OPTIONS */ ] }) Error: Nest can't resolve dependencies of the AbilityFactory (?). Please make sure that the argument CASL_FEATURE_OPTIONS at index [0] is available in the AbilityModule context. Potential solutions: - If CASL_FEATURE_OPTIONS is a provider, is it part of the current AbilityModule? - If CASL_FEATURE_OPTIONS is exported from a separate @Module, is that module imported within AbilityModule? @Module({ imports: [ /* the Module containing CASL_FEATURE_OPTIONS */ ] })
Did you follow the video as shown? That tells me you’re missing a dependency, did you install casl? Did you register the factory properly as a provider? Don’t think there’s much more to the setup than what I’ve shown here so make sure you didn’t miss any steps
it’s a lot to share in a comment dude, It’s nothing fancy… mostly defaults. Random color theme. Prettier, thunder client, Bunch of things for frontend like react snippets… what caught your eye?
I would love this with explanations on how to use conditions/fields because at the moment it seems as if conditions and fields can only be implemented outside of a guard (no matter the package). Been banging my head against the wall trying to gain access to those and use some of the @casl/prisma perks like the function accessibleBy(ability).Subject. Really wish they had more in depth examples on the site. Prisma is massively popular so it would be a great in depth video *nudge nudge* lol. Honestly, these NestJS and Casl videos are huge, there’s just not enough quality content on such mainstream libraries. Clientside JS/TS has all of the content with serverside lacking.
Awesome tutorial! Now say instead of the 'user.orgId' property you had to compare against a 'user.org.id' property, how would you nest the $ne condition?
If you compare the docs it’s basically the same thing between v5 and v6. They deprecated the Ability class in favor of createMongoAbility but I don’t see any other changes
@@mariusespejo 😔 I am getting issues when I try to read from user table if login user is = to param id if you can provide me that code it will be very helpful
Fyi on v6 of CASL the Ability class is deprecated, instead you need to use “createMongoAbility”. For example at 8:04 you should instead use:
const builder = new AbilityBuilder(createMongoAbility)
For type checking
const builder = new AbilityBuilder(createMongoAbility);
and instead of:
export type AppAbility = Ability
use:
export type AppAbility = MongoAbility
?
That’s right
I lost it trying to research the new syntax but seems all I had to do is check the comments 😂
@mariusespejo why Mongo? How is CASL related to mongo?
Dude, seriously, keep doing your tutorials, they are really good, it really saved me when I was learning nest, thanks!
Glad to have helped! thanks for stopping by to comment 😄
Keep up the great content. I appreciate how you get to the point and assume the viewer has knowledge fundamentals on any included topics (NestJS, Casl). It makes your video title truthful and allows you to dive deeper into the topic without making it too long. Also really appreciate your edits and how clean they are. Not sure how you do it honestly. Keeping the audio going seamlessly while cutting out typos and cutting in typo fixes. Subbed!
Thank you so much! TH-cam has honestly just been sort of a big experiment for me and feedback like yours is very helpful!
Your nestjs authentication video helped me land my first full time Job in tech and now your videos are helping me keep it.
Keep up the good work, you're awesome.
That’s awesome man! I’m glad to have helped in some way, Congratulations on getting your first job!
@@mariusespejo Thank you
Dude your tutorial and presentation is very informative and showing the different ways of implementation is the highlight one . 👍
Thanks for the feedback!
Revisiting this video after having watched it about a year ago. Such great content. Thank you
What I personally do is create 2 SetMetadatas, one for the controller to set the entity to use at class level (ex: @SetEntity(User)), and the second one to set the required permission at method level (ex: @RequiresPermission(Action.Update)). Then all the logic to get the entity instance and check for permission is in the AbilityGuard.
UPD: I had to rewrite my comment because my previous comment got spammed because of the link to my GitHub (Marius, unblock it, please :) there's a lot of useful information for other people and, maybe, for your next video).
Yeah, I did the same thing. I need to hide data from the user based on his rights and protect my endpoints via action rights. So I created @RequiredRights decorator and ActionRights Guard where I check if the user has required rights or not, also I created @Public decorator to mark endpoints that don't require authorization.
To hide data from users, I used class-transformer, custom RightsBasedSerializer Interceptor and @SetResponseTransformationType decorator to explicitly mark what type my endpoint returns.
I think my way is more convenient than CASL.
Interesting ideas, thanks I will explore those!!
RagNCode: sorry youtube will automatically delete if you post a link, it’s not even held for review on my end, it’s gone
@@mariusespejo If you will need more information, my github nickname is GrapeoffJS, go to CRMServer repo and switch to refactoring branch (pls don’t look at the master branch, there are a lot of messy code, i am embarrassing :))
It seems there’s no information about my method in the internet, so I had to come up with it by myself, so if you are really inspired by this, my repo can help you I think.
Thanks for sharing!
Much cleaner implementation than the one in the Nest docs! Thank you, keep it up!
I was about to comment on your other video to make this video but you already made it. Subscribed. Keep up good work!
Thank you Milena!!
Gifted individual, seriously a pleasure following and learning along with you
Thank you 🙏
Hi @Marius, fantastic content as usual 👏. 0:03 nice presentation 😜 I was featured
Another great video! Love that! With ur help I've started my Nestjs journey
Thanks for all your videos, nestjs is my favorite framework like your channel
You got a thumbs up before I even saw the video. Keep up the good work!
Thanks man! 🙏
You're so underated dude like for real!! I'm really inspired so much because of you.
Plan to make a TH-cam Channel that also cover Nest.js if I lucky enough, ha!
Wish me luck.
Go for it! I personally hesitated for way too long. Best advice honestly is to just try it.
You can get a pretty good sounding usb microphone for fairly cheap nowadays. That’s all you really need!
It’s not even about luck honestly, mostly just about being persistent. But good luck anyways!
amazing teaching, rich knowledge, thank you very much
@deprecated
use createMongoAbility function instead and MongoAbility interface. In the next major version PureAbility will be renamed to Ability and this class will be removed
'Ability' is deprecated. Maybe you could update the tutorial or use Casbin instead. Great content, smooth approach to teaching
Good callout, it a minor thing though I wouldn’t make an entirely new video just for that. I did add a pinned comment to mention it.
As for casbin, not very familiar, but I would personally pick a library purposely built for JS rather than just having a JS version of it.
I can't say thank you enough, but thank you so much for the tutorial it helped me a lot.
hey Ralf, glad to help!!
I was studying for an interview and nestjs was a requirement. I think I've watched all nestjs videos on this channel at least twice (5 times the teamseas one lol) and now I'm making almost 5 times what I used to do at my old job. Still not sure if I'm dreaming lol
Happy to hear that! sounds like you put in the time to prep, and it paid off, nice work 💪💪💪
Yes Marius! You're a machine, thanks!
🦾🦾
At last! Awesome! Thanks Marius : )
Master of NestJs
Super good videos. If I had a well documented open source project I'd definitely be trying to sponsor you do a video on it
I'm really liked your nestjs playlist, because of it's easy to understand explanations, Thanks a lot. Could you make a video about file uploading in NestJS?
Thanks! I’ll add it to my todo list!
2 years later and this is very very helpful to me. Thanks.
One question though, I am trying to have that kinda policies guard, but I'm having a difficulty pulling the data for the user to do the can check. Any links to read up please?
I learned alot from your videos
Great video, helped a lot!
Keep up the good work bro and thank you
Thank you.
This is amazing thank you
Thank's!
There is my comment shown there🤩🤩 thank u sir,
And very helpful video,thank u sir🤩🔥
😄🙌
Can you share the repository of this code example, please?
Please make video on NestJs rate limiting using redis storage.
Thank you for the video. You explain it great.
It would be great if you could explain this in the context of Angular.
How can I display pages only for certain users?
The fundamentals to understand is that you need to define the permissions and do ability.can() checks where you need to do it.. e.g. you might have ability.can(‘read’, ‘dashboard’) … how you enable/disable routes in your app based on the outcome of that check however is up to you
Thank your 🙏
Great tutorial thanks for your work, you are great. later can we have a tutorial on integration of multer in a nestjs api for the file and image upload
Do you have github repository with those codes?
Nice content mate! Nice to be learning NestJS Auth in this video.
BTW what extension did you use to make that fade grey text intellisense appear when you are typing the code?
I’m pretty sure that’s actually just a vs code built-in setting but I’m not remembering what’s it’s called at the moment!
Great learning. Just wanting to know, if you want to do the update/Patch thing, how would you do with custom decorator?
I did cover several examples of using the custom decorator for the get/delete. It’s the same exact concept, I recommend go back and review that pattern. Setup your ability to add can/cannot for updates. User the decorator to say that your controller method requires that it can update that subject.
I have the same question on this topic recently.
I implemented the rbac model using casbin to manage Nest Guard Middleware.
Maybe I can consider CASL as another strategy choice.
Nice introduction, so good!
It sounds like Casbin can also do ABAC if you want to switch strategies. Casl though was written in TS so it integrates a bit better with Nest I think
Exactly, appreciate that!
@@timchen3062 Can you please share your repo link (if it is public) where you implemented casbin for Nest Guard Middleware, or you can guide me to some resource for the same. Thanks
What about using it with prisma? It needs the actual DB record in the guard, sometimes I need to `include` also and check based on relationship record
Yes you can use it with any orm
hi , thank you for your learning series , do you have any learning tutorial about angular and nest , and development and deploy together ?
not at the moment, likely won't cover Angular to be honest. If you want your app to deploy to together as one, then you need to setup your pipeline to statically build your angular SPA and have it served up by nest using serve static: docs.nestjs.com/recipes/serve-static
Great video again. Thank you. I tried nest-casl package. U may extend this subject with that package. And in addition, what do u think about custom logging. For detailed logs I need req in logs and pino offers that?
Nest-casl is pretty much just a slightly different implementation of the same thing we did here, only benefit is perhaps slightly less setup.
For logging, Nest comes with a built in logger if you check the docs, it’s fairly basic. If it’s not good enough for you you can pretty much use any logger library out there and use it as middleware
Hey, I really like your teaching style. Have you considered a full-blown nest course eg with mongo db (full project a-z) ? I'm sure you'd get a lot of participants on udemy!
Maybe one day! I’m okay with putting stuff out for free for now and just focusing on growing the channel
I'm getting following error `Conversion of type 'Function' to type '"all"' may be a mistake because neither type sufficiently overlaps with the other.` on detectSubjectType, which is correct. Why aren't you getting this?
I'm getting the same issue rn, can you provide the solution in case you fixed that error?
Very great video Mr. Espejo. Do you have a plan to make video about nestJs casl with Prisma?
Potentially, I do want to cover prisma in general in more detail as I learn more about it. As for the casl integration if you need it sooner: as long as you have a good understanding of both prisma and casl, their docs seem straightforward (although I haven’t tried it personally) casl.js.org/v5/en/package/casl-prisma
@@mariusespejo Thank you for your response. After seeing some of your videos, I finally decided to just use the typeorm.
Hi marius, i really like you tutorials and helped me a lot. I had a concern about, if a i had another endpoint, like, not a crud endpoint, how i protect them? Or i should had a endpoint like that?
Not sure I understand your question. Auth really has nothing to do with whether or not it’s a crud endpoint. You would protect any endpoint basically in the same way, it’s all the same fundamentals. With Nest specifically you would use guards to do most of your auth checks
Ok, I'll rephrase, I have endpoints different from those of basic CRUD, for example, getall, get, update, delete and create, I have endpoints on the user to add groups, @post /add-user, it is not a common update, as Only some users will be able to do this, not everyone with write permission. How could I do this granular control using casl. Or should I not have an endpoint like that? and only use the common update, e.g. @patch /User.
I made some tables, like services and groups, i group can have many services, and one User can hava many Groups. My service table is like: Route, Method, Name, Description. So if a have one group with one service, i can do the request to that service endpoint. I want my guard check if my user have that service. I using the right approach? i dont know, but this is what i´m doing. Pls give a light about it
Re: your question about /add-user, with CASL you should be able to define granular control. I thought that I covered that in this video but if not, there is another video in my channel where I introduce CASL in detail. But basically you would define an ability off of the “User” subject, such as
can( ‘create’, User, conditions ) // what conditions is up to you, e.g. { accessLevel: ‘X’ }
Every user then would then have their ability built off those rules that you put into place.
If you have a dedicated route for /add-user then you could protect that with a custom guard such as @RequirePermisssions(Permission.CREATE_USER)
Which internally would simply check userAbility.can(‘create’, User)
If you instead had a common update endpoint, and wanted granular control depending on what field they are updating then you would do something like
If (dto.someProperty && userAbility.cannot( ‘update’, User, [ ‘someProperty ] ) then throw new ForbiddenException()
Basically whatever your granular restrictions are, CASL should be able to model with a combination of action, subject, fields, and conditions. Once you have that model created, you simply create the ability object for each user, and you can do your checks either in guards or within the service layer. It’s up to you. I suggest reviewing CASL docs in detail for all of this to make sense
@@mariusespejo thx, i will study more about and try it.
coming from PHP/Laravel, setting this up is complicated compared to as how simple Gates are being implemented in Laravel. well this is expected as this is an external package.
The setup with Nest I think comes off complex because you have to line up the type definitions to make TS happy, and potentially make custom decorators, but the package itself is fairly simple and easy to use. But maybe laravel is really just simpler lol I’m not familiar
Bro what if I am doing a findAll() with a DTO, but the user should not see all of them because he has no access to it?
That’s why you would set up something like CASL or similar, as a tool to check what access users have before performing an action. E.g. if the user is not allowed to see everything you either completely prevent it or you automatically filter by changing your filter to a “find where access matches x user’s privileges/role)
@@mariusespejo
Ok and what if the user can read some entity, and by extent he can read other entities related to it. How would I do that?
something like
can(Action.Manage, EntityX);
can(Action.Manage, EntityY, where: {idEntityX = idEntityX});
Kindly make video roles & permission with graphql
It’s honestly basically the same thing as what I covered here, guards in nest work for both rest and graphql
Also Try to make a tutorial on manage the user through RBAC?
Does it possible to do?
With use of prisma🙏🏽
I did cover basic rbac in the original authorization video that I mentioned. Also casl can also be used for rbac
@@mariusespejo sure I will looking in that tutorial.
But I need admin can signup/login and create post. I am enum role user and admin where default is user and when i am trying to signup with a admin account but at that times give error. As simply admin account is not created. I used prisma as pg db is there, package use passportjwt, passwortlocal
Hye Marius great job. Can you do tutorial on casl rulesToQuery method for typeorm?
Please upload this project to your github. I don't want to type manually the codes :(
how can this pattern work when you need support multiple organizations for a user?
CASL doesn’t care however many “organizations” you might have, if you can represent the rules to create the ability for it, then it should work. Again it’s just a mixture of can and cannots. e.g. apply certain rules/ability given the user’s organization and whatever other conditions you might have, that’s totally doable
Is it possible to somehow read the path param (e.g. the :id) in the decorator so that the post ID can be part of the rule?
Guards have access to the request and can extract that. But if you’re talking about the decorator that simply sets metadata I don’t think that has access to it.
If I understand what you might be trying to achieve, it means you’ll have to create a custom guard that constructs the ability dynamically
@@mariusespejo so I have a user object which contains a list of posts which the user has access to, so when the user is trying to call a GET /posts/:id I would need to check if this user has permissions for reading this particular post. What would be the best way to achieve this?
Well with CASL you’d achieve that by creating a condition like
can(‘read’, Post, { id: { $in: user.postIds } })
Basically your user ability that you create should have that defined in there, then at the time of access checking you just need to perform
const post = await getPost(id);
ability.can(‘read’, post);
Although technically all you need is the Id, which you already have, so you probably don’t need to query the post upfront. So you’d have to work with your subject detection, so maybe you’d create a partial/psuedo post like
const post = new Post();
post.id = id;
can(‘read’, post);
You can do that logic within a custom guard for example.
Hope that helps! For more ideas I suggest look through the docs more, ask around in stackoverflow, etc.
Hello! Do you have repository to download your this app-code?
Having the "isAdmin" property kinda defeats the purpose of PBAC? I was thinking on having all my permissions/grants stored on the database and act on them, not on the "isAdmin" property.
It’s just an extremely simple example of creating abilities off of the data that you have, obviously a real-world example would not be that simple. You absolutely can store your permissions on the database, casl allows you to initialize abilities off of json (for scenarios where the rules are dynamic or remote like yours). My original Casl video just before this one talk about it towards the end, or feel free to check the docs
@@mariusespejo thanks!
Is it the same with grapgql or will we need extra configuration
Guards in nestjs work for both rest and graphql so it should be mostly the same thing with maybe some minor changes
Amazing tutorial, very effective learnt nestjs from your channel.
I have been implementing casl with nestJs, although I am using database persisted permissions using mongoose.
but am not able to understand how to check the ability. I have collection of roles:{role, permissionId[]} and a permissions:{action, subject,condition} collection which contains all the permissions. And I have defined ability factory with the Ability constructor and passed the authenticated user permissions in it.
The only issue is how can I implement gaurd so that I don't have to rewrite the defineAbility and ForbiddenError logic in each controller methods.
Also is it possible to use Gaurd while using casl-mongoose.
Please help me!!
The purpose of guard is exactly so that you can define that logic in one place and not have to keep re-writing it so I’m not sure I understand your question. Your guard should be reusable. If you have that role/permission info in your database then you need to query it and map it to to an ability… once you have the ability it’s just a matter of checking authorization via can(). The fundamentals is pretty much what I covered in the video
@@mariusespejo Thanks for the quick response, I have been reading the casl documentation: cookbook/roles-with-persisted-permissions and in that documentation, it shows how to check the ability using ForbiddenError class: ForbiddenError.from(ability).throwUnlessCan('create', subject('Article', partialArticle)); here in this statement the second argument is the subject of the ability, in this case, it is the Article model and also a partialArticle object which they are creating.
But the Gaurd which I have used in the project is using the ForbiddenError class to check the ability for each rule:
rules.forEach((rule) => {
ForbiddenError.from(ability).throwUnlessCan(rule.action, rule.subject)
}) here I won't be able to pass the article which I am creating or looking for
Dude, would you like make tutorial hide codebase connection with 2 different env prod and dev, so on the app.module.ts we just change dev or prod
Whatever you’re trying to have different between environments should be mostly handled by environment variables, e.g. if you have different database connections then that should be just coming in via env variables
It would be cool to also see the github for this. =/
Nice video. However, I would suggest that you don't ever add business or auth logic to controller methods - that's what services are for. You can derive the user from cookies or JWT via guards. Posting this comment at 17:44
Guards are actually the more proper place to do it, not services, which I did cover I believe if you watched the rest. And yes that is correct all business logic generally should be in services, but guards are meant to be used for both authentication and authorization.
Could you share code with us ?
please can you provide the code
hello, Marius, thank you for your wonderful tutorial, but I'm stuck on this error:
Nest can't resolve dependencies of the AbilityFactory (?). Please make sure that the argument CASL_FEATURE_OPTIONS at index [0] is available in the AbilityModule context.
Possible solutions:
- If CASL_FEATURE_OPTIONS is a provider, is it part of the current AbilityModule?
- If CASL_FEATURE_OPTIONS is exported from a separate @Module, is that module imported within AbilityModule?
@Module({
imports: [ /* the Module containing CASL_FEATURE_OPTIONS */ ]
})
Error: Nest can't resolve dependencies of the AbilityFactory (?). Please make sure that the argument CASL_FEATURE_OPTIONS at index [0] is available in the AbilityModule context.
Potential solutions:
- If CASL_FEATURE_OPTIONS is a provider, is it part of the current AbilityModule?
- If CASL_FEATURE_OPTIONS is exported from a separate @Module, is that module imported within AbilityModule?
@Module({
imports: [ /* the Module containing CASL_FEATURE_OPTIONS */ ]
})
Did you follow the video as shown? That tells me you’re missing a dependency, did you install casl? Did you register the factory properly as a provider? Don’t think there’s much more to the setup than what I’ve shown here so make sure you didn’t miss any steps
@@mariusespejo Yes I followed the same steps as in the tutorial.
I found the solution by renaming AbilityFactory to AbilityFactoryService .
can you share your vs code settings and extensions?
it’s a lot to share in a comment dude, It’s nothing fancy… mostly defaults. Random color theme. Prettier, thunder client, Bunch of things for frontend like react snippets… what caught your eye?
Nice tutorial, but i think i made something wrong, while my subject and action work fine, coditions and fields have no impact :c
You like don’t have subject detection configured properly
can you upload this code from video to the github pls
what is your template for VScode ?
Template?
@@mariusespejo sorry theme
I believe I’m using monokai pro here!
How about casl/prisma? 😀
I would love this with explanations on how to use conditions/fields because at the moment it seems as if conditions and fields can only be implemented outside of a guard (no matter the package). Been banging my head against the wall trying to gain access to those and use some of the @casl/prisma perks like the function accessibleBy(ability).Subject. Really wish they had more in depth examples on the site. Prisma is massively popular so it would be a great in depth video *nudge nudge* lol. Honestly, these NestJS and Casl videos are huge, there’s just not enough quality content on such mainstream libraries. Clientside JS/TS has all of the content with serverside lacking.
Awesome tutorial! Now say instead of the 'user.orgId' property you had to compare against a 'user.org.id' property, how would you nest the $ne condition?
Thanks! There is support for nested fields via dot notation, see: casl.js.org/v6/en/advanced/typescript#nested-fields-with-dot-notation
Can U create an update for casl v6 ?
I don’t think there’s any difference, v6 just drops support for angular 13
@@mariusespejo it's not clear to me how detectSubejctType should look like in version 6, any hint ? :)
If you compare the docs it’s basically the same thing between v5 and v6. They deprecated the Ability class in favor of createMongoAbility but I don’t see any other changes
can you please provide a git repo link, please?
Sorry I don’t have a repo for this at the moment
@@mariusespejo 😔 I am getting issues when I try to read from user table if login user is = to param id if you can provide me that code it will be very helpful
🙏 Promo'SM.