New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

@sapientpro/nestjs-gate

Package Overview
Dependencies
Maintainers
2
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sapientpro/nestjs-gate

Lightweight authorization gate for NestJS with policy classes, ability callbacks, and before/after hooks.

latest
Source
npmnpm
Version
1.1.2
Version published
Maintainers
2
Created
Source

@sapientpro/nestjs-gate

NPM Package

Lightweight authorization gate for NestJS with:

  • Ability callbacks (define/has/allows/denies/any/none/authorize)
  • Policy classes discovered via a decorator
  • Before/after hooks for cross‑cutting authorization logic
  • Rich GateResponse to return messages and throw HTTP exceptions when denying

This package is designed to be framework‑friendly and minimal, using Nest's DiscoveryModule to automatically find policies.

Installation

npm install @sapientpro/nestjs-gate

Quick start

  • Import GateModule and inject GateService
// app.module.ts
import { Module } from '@nestjs/common';
import { GateModule } from '@sapientpro/nestjs-gate';

@Module({
  imports: [GateModule],
})
export class AppModule {}
// some.service.ts
import { Injectable } from '@nestjs/common';
import { GateService } from '@sapientpro/nestjs-gate';

@Injectable()
export class SomeService {
  constructor(private readonly gate: GateService) {}

  async canCreatePost(currentUser: any, postDto: any) {
    // Run checks under a specific user context (see runWithUser below)
    return this.gate.runWithUser(currentUser, () => this.gate.allows('create-post', [postDto]));
  }
}
  • Define abilities programmatically (optional)
// abilities.setup.ts (e.g., inside a module onModuleInit or bootstrap)
import { Injectable, OnModuleInit } from '@nestjs/common';
import { GateService } from '@sapientpro/nestjs-gate';

@Injectable()
export class AbilityBootstrap implements OnModuleInit {
  constructor(private readonly gate: GateService) {}

  onModuleInit() {
    this.gate
      .define('create-post', (user, postDto) => {
        return !!user && user.role === 'editor';
      })
      .define('delete-post', (user, post) => {
        return !!user && (user.role === 'admin' || post.authorId === user.id);
      });
  }
}
  • Create policies and use the @Policy decorator
// post.entity.ts
export class Post {
  constructor(public id: string, public authorId: string, public published: boolean) {}
}
// post.policy.ts
import { Injectable } from '@nestjs/common';
import { Policy } from '@sapientpro/nestjs-gate';
import { Post } from './post.entity';

@Policy(Post)
export class PostPolicy {
  // Optional policy-wide precheck
  before(user: any, ability: string, post?: Post) {
    if (user?.role === 'superadmin') return true; // short-circuit allow
    return null; // continue normal checks
  }

  // Ability methods (name derived from ability string)
  createPost(user: any) {
    return !!user && user.role !== 'banned';
  }

  deletePost(user: any, post: Post) {
    return !!user && (user.role === 'admin' || post.authorId === user.id);
  }
}
  • Ability name mapping:
    • kebab-case and spaced names are converted to camelCase method names.
    • E.g., 'create-post' -> createPost.
  • Check abilities with a model instance or class
// using a model instance (policy resolved by instance constructor)
const allowed = await gate.allows('delete-post', [postInstance]);

// using a class as the first arg (policy knows its model type)
const allowed2 = await gate.allows('create-post', [Post]);
  • Use before/after hooks for cross-cutting policies
// on bootstrap
this.gate
  .before((user, ability, args) => {
    // return true/false to short-circuit, or null/undefined to continue
    if (user?.blocked) return false; // deny everything for blocked users
    return null;
  })
  .after((user, ability, result, args) => {
    // observe or adjust result
    if (result === false && ability === 'delete-post' && user?.role === 'moderator') {
      // e.g., grant moderators delete on weekends (demo only)
      const isWeekend = [0, 6].includes(new Date().getDay());
      if (isWeekend) return true;
    }
    return result; // leave as is
  });
  • GateResponse and throwing exceptions
import { GateResponse } from '@sapientpro/nestjs-gate';

// Return rich responses from abilities or policies
this.gate.define('publish-post', (user, post) => {
  if (!user) return GateResponse.deny('Unauthenticated').withStatus(401);
  if (!user.canPublish) return GateResponse.deny('Not allowed');
  return GateResponse.allow();
});

// In handlers/services
await this.gate.runWithUser(currentUser, () => this.gate.authorize('publish-post', [post]));
// authorize() throws 403 by default or the provided status when denied.
  • User context with runWithUser

GateService tracks the current user via AsyncLocalStorage. Wrap your checks with runWithUser when you need to pass the user implicitly:

const result = gate.runWithUser(currentUser, () => gate.allows('create-post', [dto]));

You can still pass the user explicitly by designing your ability callbacks to accept the user as the first parameter; GateService calls your ability with (user, ...args) automatically.

Middleware example:

// auth.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response } from 'express';
import { GateService } from '@sapientpro/nestjs-gate';

@Injectable()
export class AuthMiddleware implements NestMiddleware {
  constructor(private readonly gateService: GateService) {}

  use(req: Request, _res: Response, next: (err?: any) => void) {
    // Resolve user from the request in your own way
    // e.g., from a session, a JWT, or a header
    const user = (req as any).user; // replace with your real extraction logic

    // Ensure every downstream authorization call runs with this user
    this.gateService.runWithUser(user, next);
  }
}

This way, any providers/controllers executed after the middleware can call gate methods (allows/authorize/etc.) without needing to pass the user explicitly.

API Summary

  • GateModule: Nest module that provides GateService. Imports DiscoveryModule internally to discover policies.
  • GateService:
    • define(ability, callback)
    • has(ability | ability[])
    • allows(ability | ability[], args?)
    • denies(ability | ability[], args?)
    • any(ability | ability[], args?)
    • none(ability | ability[], args?)
    • authorize(ability, args?) -> throws on denial
    • inspect(ability, args?) -> GateResponse
    • raw(ability, args?) -> boolean | null | GateResponse | undefined
    • before(callback), after(callback)
    • runWithUser(user, callback, ...args)
  • Policy decorator: @Policy(ModelOrForwardRef)
  • GateResponse: allow/deny factories, withStatus, asNotFound, authorize(), toJSON(), toString()

Keywords

nestjs

FAQs

Package last updated on 06 Oct 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts