@cjr-unb/autho
TypeScript icon, indicating that this package has built-in type declarations

1.1.1 • Public • Published

pt-br

@cjr-unb/autho

Module for authorization in NestJS built with CASL and integrated with Prisma.

Installation

Nest and Prisma must be installed with at least one migration executed. Then, run the following command:

npm install @cjr-unb/autho

How to use

Defining Rules

Define the authorization rules for your application in a callback function of type Rules. This function receives the type of user stored in the JWT token and an object with the properties can, cannot, and user.

import { Rules } from "@cjr-unb/autho";
import { JwtPayload } from "./auth/dtos/jwt-payload.dto";

export const rules: Rules<JwtPayload> = ({ can, cannot, user }) => {
  // Define your application's authorization rules here. Example:

  if (user.roles.includes("admin")) can("manage", "all");

  can("update", "post", { authorId: user.id });
};

The possible action names are: manage, create, read, update, and delete. The possible resource names are: all and the names of entities in your database. You can define custom actions and resources. See the Defining Custom Actions and Resources section.

The rules are defined as described in the CASL documentation.

AuthoModule

Add the AuthoModule using the forRoot method in one of your application's modules. The arguments that the method receives are:

  • <JwtPayload>: Type of user stored in the JWT token.
  • Options:
    • PrismaModule: Prisma module that should export the PrismaService
    • rules: Callback function that contains the authentication rules. Receives an object with the properties can, cannot, and user.
    • userProperty?: Name of the property that contains the authenticated user in the request object. Default: user.
    • exceptionIfNotFound?: Type of exception to be thrown if the resource is not found in the database. Possible values are: 404, 403, and prisma. Default: 404.
    • forbiddenMessage?: Function that receives the name of the action and resource that the user does not have permission to access, and returns the message to be displayed in the exception. If not defined, the message "Forbidden resource" will be displayed. Default: undefined.
    • numberIdName?: Name of the property that contains the resource ID in Prisma. Should be used when the resource ID is a number. You must choose between numberIdName and stringIdName. Default: id.
    • stringIdName?: Name of the property that contains the resource ID in Prisma. Should be used when the resource ID is a string. You must choose between numberIdName and stringIdName. Default: undefined.
import { AuthoModule } from "@cjr-unb/autho";
import { JwtPayload } from "./auth/dtos/jwt-payload.dto";
import { Module } from "@nestjs/common";
import { PrismaModule } from "./prisma/prisma.module";
import { rules } from "./auth/auth.rules";

@Module({
  imports: [
    AuthoModule.forRoot<JwtPayload>({
      PrismaModule,
      rules,
    }),
  ],
})
export class AppModule {}

Ability Decorator

Now you can use the @Ability decorator on any route of your application. The decorator receives the action the user is trying to perform, the name of the resource they are trying to access, and additional options.

import { Ability } from "@cjr-unb/autho";
import { Controller, Get, UseGuards } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";

@Controller("post")
export class PostsController {
  @Ability("read", "post")
  @UseGuards(AuthGuard("jwt")) // The authentication guard must be executed before the authorization guard
  @Get()
  findAll() {
    // ...
  }
}

If it's necessary to query the database to check if the user has permission to access the resource, you can use the useDb option. The resource will be fetched using the ID passed in the route parameter.

The name of the property that contains the resource ID is defined in the numberIdName or stringIdName options.

If the property name in your route that contains the resource ID is different from the one defined in the numberIdName or stringIdName option, you can pass the correct name in the param option.

If the resource is not found, Autho will throw an exception of the type defined in the exceptionIfNotFound option.

import { Ability } from "@cjr-unb/autho";
import { Controller, Get, UseGuards } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";

@Controller("post")
export class PostsController {
  @Ability("read", "post", { useDb: true, param: "postId" })
  @UseGuards(AuthGuard("jwt"))
  @Get(":postId")
  findOne() {
    // ...
  }
}

Now, when a user who doesn't have permission tries to access the route, a ForbiddenException will be thrown.

Defining Custom Actions and Resources

You can define your own custom actions and resources by creating a type that contains the action and resource properties and passing that type as a parameter to the rules function for the AuthoModule, to the Ability decorator, and to the forbiddenMessage function if it is defined.

You can extend the default Actions and Resources using the DefaultActions and DefaultResources types.

import { DefaultActions, DefaultResources } from "@cjr-unb/autho";

export type CustomOptions = {
  actions: "operate" | DefaultActions;
  resources: "calculator" | DefaultResources;
};

In the rules function:

import { Rules } from "@cjr-unb/autho";
import { JwtPayload } from "./auth/dtos/jwt-payload.dto";
import { CustomOptions } from "./custom-options";

export const rules: Rules<JwtPayload, CustomOptions> = ({
  can,
  cannot,
  user,
}) => {
  if (user.roles.includes("admin")) can("operate", "calculator");
};

In the AuthoModule:

import { AuthoModule } from "@cjr-unb/autho";
import { JwtPayload } from "./auth/dtos/jwt-payload.dto";
import { Module } from "@nestjs/common";
import { PrismaModule } from "./prisma/prisma.module";
import { rules } from "./auth/auth.rules";
import { CustomOptions } from "./custom-options";

@Module({
  imports: [
    AuthoModule.forRoot<JwtPayload, CustomOptions>({
      PrismaModule,
      rules,
    }),
  ],
})
export class AppModule {}

In the Ability decorator:

import { Ability } from "@cjr-unb/autho";
import { Controller, Get, UseGuards } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";
import { CustomOptions } from "./custom-options";

@Controller("calculator")
export class CalculatorController {
  @Ability<CustomOptions>("operate", "calculator")
  @UseGuards(AuthGuard("jwt"))
  @Get()
  operate() {
    // ...
  }
}

Limitations

Currently, for Autho to work correctly, all Prisma models must have the same column name for the primary key.

Additionally, Autho does not support defining aliases for actions.

Package Sidebar

Install

npm i @cjr-unb/autho

Weekly Downloads

8

Version

1.1.1

License

MIT

Unpacked Size

47.5 kB

Total Files

32

Last publish

Collaborators

  • edson25