Search code examples
typescriptnestjsprismacasl

Check CASL abilities before entity creation | NestJS + PrismaORM + CASL project


I'm trying my best to implement an authorization mechanism in an existing NestJS project since nearly a month now. But I'm blocked today at one of the last steps that will allow me to verify if the user can, or not create an entity.

I see many examples on the web but I didn't find any that is using the same configuration (I'm using NestJS + PrismaORM and CASL). Using Prisma has its benefits but for now it blocks me by the way it works.

As Prisma saves in the database the created entity as soon as the "create" order goes through, I can't use the technique I seen on other projects with mongoose where devs created the entity, then verified the entity using something like this :

if (!ability.can(EntityAction.CREATE, 'MyEntity', entity)) {
  throw new ForbiddenException('You are not authorized to create this entity.');
}

And finally saved the entity to the DB if no exception was thrown.

The fact is that I don't want to only check if the user can create an entity, otherwise I would just do :

if (!ability.can(EntityAction.CREATE, 'MyEntity') {
  throw new ForbiddenException('You are not authorized to create this entity.');
}

As I define conditions on my actions, as you can see in this example :

can(EntityAction.CREATE, 'MyEntity', {
    rank: { $gt: role.rank },
    unitId: role.unitId
});

(where role is the user's role, and I give permissions according to the roles properties)

I also want to check if the arguments given for the creation follow the conditions. If you have any idea of solution or need more informations, tell me about it !

I tried navigating through the ability created by my AbilityFactory to find any attributes or methods that would help me in my quest, searched the CASL documentation, examples on the web using same libraries, and of course GPT wasn't of any help


Solution

  • Found the answer looking at a link posted in a comment here. To test the ability on an object that isn't yet created, I have to create an object the most similar possible to what the object would look like after the prisma.create method. As you cans see here with the example :

    const USER_SUBJECT = subject('User', { ...args, createdAt: new Date(), uuid: 'false uuid', id: BigInt(-1) });
    if (ability.cannot(DirectoryAction.CREATE, USER_SUBJECT)) {
        throw new UnauthorizedException('Tried to create unauthorized resource (User)');
    }
    

    Of course, you'll maybe need adjustments if you need it in your project. See Sergii Stotskyi's comment on the original question to get a more general example in a complete code.