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)
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.
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!
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.
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?
You're so underated dude like for real!! I'm really inspired so much because of you. Plan to make a RUclips 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!
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
@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'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?
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.
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
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
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
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
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 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
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
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?
@mariusespejo Thank You for this detailed explanation. It's exactly what I was looking for. We are currently working on a huge monolith project, with an in-deep permission system, often we reuse methods from one service in another one. For this reason, we don't use guards but check permissions directly within the service method like in your example. It's quite the same as You showed in the tutorial, there are different organizations, and they have different user groups, so users can have various levels of access, The organization manager can manage everything inside the organization, but the group manager can only manage staff within his group. How would you implement this inside a service method? I find a guard implementation pretty clean and straightforward, but since we reuse service methods within other services directly, I'm afraid that we can find ourselves in a situation when for example user should not be allowed to access the organization, but he will be able to access some data within the organization because method will only check for it's own allowed actions, but not the whole hierarchy.
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.
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});
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?
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
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?
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
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
@@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
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
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!
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
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
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
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
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.
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.
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 😄
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
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! RUclips has honestly just been sort of a big experiment for me and feedback like yours is very helpful!
Dude your tutorial and presentation is very informative and showing the different ways of implementation is the highlight one . 👍
Thanks for the feedback!
Hi @Marius, fantastic content as usual 👏. 0:03 nice presentation 😜 I was featured
Revisiting this video after having watched it about a year ago. Such great content. Thank you
Simple and great. Thanks for such videos
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!
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!!
Much cleaner implementation than the one in the Nest docs! Thank you, keep it up!
Gifted individual, seriously a pleasure following and learning along with you
Thank you 🙏
Can you share the repository of this code example, please?
Master of 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?
You got a thumbs up before I even saw the video. Keep up the good work!
Thanks man! 🙏
amazing teaching, rich knowledge, thank you very much
Another great video! Love that! With ur help I've started my Nestjs journey
You're so underated dude like for real!! I'm really inspired so much because of you.
Plan to make a RUclips 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!
Thanks for all your videos, nestjs is my favorite framework like your channel
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 💪💪💪
At last! Awesome! Thanks Marius : )
Yes Marius! You're a machine, thanks!
🦾🦾
@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.
Do you have github repository with those codes?
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!
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!!
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
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.
Great video, helped a lot!
I learned alot from your videos
Keep up the good work bro and thank you
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.
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
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 , 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
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
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!
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
Please make video on NestJs rate limiting using redis storage.
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
Thank you.
This is amazing thank you
Hello! Do you have repository to download your this app-code?
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?
@mariusespejo Thank You for this detailed explanation. It's exactly what I was looking for. We are currently working on a huge monolith project, with an in-deep permission system, often we reuse methods from one service in another one. For this reason, we don't use guards but check permissions directly within the service method like in your example. It's quite the same as You showed in the tutorial, there are different organizations, and they have different user groups, so users can have various levels of access, The organization manager can manage everything inside the organization, but the group manager can only manage staff within his group. How would you implement this inside a service method? I find a guard implementation pretty clean and straightforward, but since we reuse service methods within other services directly, I'm afraid that we can find ourselves in a situation when for example user should not be allowed to access the organization, but he will be able to access some data within the organization because method will only check for it's own allowed actions, but not the whole hierarchy.
There is my comment shown there🤩🤩 thank u sir,
And very helpful video,thank u sir🤩🔥
😄🙌
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.
Thank's!
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});
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?
Thank your 🙏
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
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
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
what is your template for VScode ?
Template?
@@mariusespejo sorry theme
I believe I’m using monokai pro here!
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
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
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
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
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
Hye Marius great job. Can you do tutorial on casl rulesToQuery method for typeorm?
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
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!
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 .
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
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 upload this code from video to the github pls
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
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.
Could you share code with us ?
please can you provide the code
Please upload this project to your github. I don't want to type manually the codes :(
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.
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
It would be cool to also see the github for this. =/
🙏 Promo'SM.