
Security News
Axios Maintainer Confirms Social Engineering Attack Behind npm Compromise
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.
@sapientpro/nestjs-gate
Advanced tools
Lightweight authorization gate for NestJS with policy classes, ability callbacks, and before/after hooks.
Lightweight authorization gate for NestJS with:
This package is designed to be framework‑friendly and minimal, using Nest's DiscoveryModule to automatically find policies.
npm install @sapientpro/nestjs-gate
// 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]));
}
}
// 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);
});
}
}
// 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);
}
}
// 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]);
// 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
});
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.
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.
FAQs
Lightweight authorization gate for NestJS with policy classes, ability callbacks, and before/after hooks.
We found that @sapientpro/nestjs-gate demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?

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.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.