npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@apipass/cerbos-pep

v0.0.109

Published

Cerbos PEP utility for NestJS

Readme

@apipass/cerbos-pep

English | Português


NestJS Policy Enforcement Point (PEP) for Cerbos. Provides a declarative interceptor that authorizes requests against a Cerbos PDP before the handler runs, with two strategies: CheckResources and PlanResources.

Installation

npm install @apipass/cerbos-pep

Module Registration

Register CerbosModule in your AppModule. It is @Global() — providers are available everywhere without re-importing.

Minimal

import { CerbosModule } from '@apipass/cerbos-pep'

@Module({
  imports: [
    CerbosModule.register({
      url: process.env.CERBOS_PDP_URL ?? 'http://127.0.0.1:3592',
    }),
  ],
})
export class AppModule {}

With per-account feature toggle

import { CerbosModule } from '@apipass/cerbos-pep'

@Module({
  imports: [
    CerbosModule.register({
      url: process.env.CERBOS_PDP_URL ?? 'http://127.0.0.1:3592',
      featureToggle: { useClass: FeatureToggleCerbosAdapter },
      imports: [FeatureToggleModule],
    }),
  ],
})
export class AppModule {}

When featureToggle is provided the interceptor calls isCerbosEnabled(accountId) before each check. Accounts that return false fall back to PermissionStrategy.LEGACY.


Strategies

| Strategy | Use case | Throws ForbiddenException when | |---|---|---| | CheckResources | Single or multi-resource write/read endpoints | all checked resources are denied | | PlanResources | List / search endpoints — returns a query filter | Cerbos returns KIND_ALWAYS_DENIED |


Usage

Apply @CerbosPolicy on a route method. The interceptor runs automatically — no @UseInterceptors needed.

List endpoint — PlanResources

import { CerbosPolicy, CerbosStrategy, PermissionContext, PermissionContextType } from '@apipass/cerbos-pep'

@CerbosPolicy({
  strategy: CerbosStrategy.PlanResources,
  kind: 'project',
  actions: ['read'],
})
@Get('/projects')
async listProjects(@PermissionContext() ctx: PermissionContextType) {
  // ctx.queryPlan — pass this to your repository to filter results
  return this.projectsService.findAll(ctx.queryPlan)
}

Single-resource endpoint — CheckResources

@CerbosPolicy({
  strategy: CerbosStrategy.CheckResources,
  resources: [{ kind: 'flow', actions: ['write'] }],
  resourceContext: (req) => ({
    id: req.params.flowId,
    attributes: { parentProject: req.params.projectId },
  }),
})
@Put('/flows/:flowId')
async updateFlow(@Param('flowId') id: string) {
  // handler runs only if Cerbos allows — ForbiddenException is thrown otherwise
}

Multi-resource endpoint — CheckResources

@CerbosPolicy({
  strategy: CerbosStrategy.CheckResources,
  resources: [
    { kind: 'stage', actions: ['read'] },
    { kind: 'flow',  actions: ['read'] },
  ],
})
@Get('/stages')
async listStages(@PermissionContext() ctx: PermissionContextType) {
  // ForbiddenException only if BOTH resources are denied
  // ctx.deniedResources contains which resources had denied actions (partial denial)
}

@PermissionContext()

Param decorator that extracts the PermissionContextType set by the interceptor.

export type PermissionContextType =
  | { strategy: PermissionStrategy.LEGACY }
  | {
      strategy: PermissionStrategy.CERBOS
      queryPlan?: Record<string, unknown>      // PlanResources — apply as repository filter
      deniedResources?: CerbosCheckDenial[]    // CheckResources — empty = fully allowed
    }

Use strategy to distinguish between legacy-authorized routes and Cerbos-authorized routes.


CerbosFeatureTogglePort

Implement this interface in the consuming API to enable per-account Cerbos toggling:

import { Injectable } from '@nestjs/common'
import { CerbosFeatureTogglePort } from '@apipass/cerbos-pep'

@Injectable()
export class FeatureToggleCerbosAdapter implements CerbosFeatureTogglePort {
  constructor(private readonly featureToggleService: FeatureToggleS3Service) {}

  async isCerbosEnabled(accountId: string): Promise<boolean> {
    const features = await this.featureToggleService.getFeatures(accountId)
    return features?.isCerbosEnabled() ?? false
  }
}

Expected Request Headers

The interceptor reads authorization context from headers injected by the API Gateway — never from the JWT directly.

| Header | Description | |---|---| | account_id | Tenant account ID — used as the Cerbos accountId scope | | role | User role (e.g. account-admin) — sanitized to account_admin before sending to Cerbos | | account_domain | Account domain — merged into principal.attr and resource.attr |


@apipass/cerbos-pep — Português

NestJS Policy Enforcement Point (PEP) para o Cerbos. Fornece um interceptor declarativo que autoriza requisições contra um Cerbos PDP antes do handler executar, com duas estratégias: CheckResources e PlanResources.

Instalação

npm install @apipass/cerbos-pep

Registro do Módulo

Registre o CerbosModule no seu AppModule. Ele é @Global() — os providers ficam disponíveis em todos os módulos sem precisar reimportar.

Mínimo

import { CerbosModule } from '@apipass/cerbos-pep'

@Module({
  imports: [
    CerbosModule.register({
      url: process.env.CERBOS_PDP_URL ?? 'http://127.0.0.1:3592',
    }),
  ],
})
export class AppModule {}

Com feature toggle por conta

import { CerbosModule } from '@apipass/cerbos-pep'

@Module({
  imports: [
    CerbosModule.register({
      url: process.env.CERBOS_PDP_URL ?? 'http://127.0.0.1:3592',
      featureToggle: { useClass: FeatureToggleCerbosAdapter },
      imports: [FeatureToggleModule],
    }),
  ],
})
export class AppModule {}

Quando featureToggle é fornecido, o interceptor chama isCerbosEnabled(accountId) antes de cada verificação. Contas que retornam false usam PermissionStrategy.LEGACY.


Estratégias

| Estratégia | Caso de uso | Lança ForbiddenException quando | |---|---|---| | CheckResources | Endpoints de leitura/escrita em um ou múltiplos recursos | todos os recursos verificados são negados | | PlanResources | Endpoints de listagem/busca — retorna um filtro de query | Cerbos retorna KIND_ALWAYS_DENIED |


Uso

Aplique @CerbosPolicy no método de rota. O interceptor executa automaticamente — não é necessário @UseInterceptors.

Endpoint de listagem — PlanResources

import { CerbosPolicy, CerbosStrategy, PermissionContext, PermissionContextType } from '@apipass/cerbos-pep'

@CerbosPolicy({
  strategy: CerbosStrategy.PlanResources,
  kind: 'project',
  actions: ['read'],
})
@Get('/projects')
async listProjects(@PermissionContext() ctx: PermissionContextType) {
  // ctx.queryPlan — passe para o repositório para filtrar os resultados
  return this.projectsService.findAll(ctx.queryPlan)
}

Endpoint de recurso único — CheckResources

@CerbosPolicy({
  strategy: CerbosStrategy.CheckResources,
  resources: [{ kind: 'flow', actions: ['write'] }],
  resourceContext: (req) => ({
    id: req.params.flowId,
    attributes: { parentProject: req.params.projectId },
  }),
})
@Put('/flows/:flowId')
async updateFlow(@Param('flowId') id: string) {
  // o handler só executa se o Cerbos permitir — caso contrário, ForbiddenException é lançada
}

Endpoint com múltiplos recursos — CheckResources

@CerbosPolicy({
  strategy: CerbosStrategy.CheckResources,
  resources: [
    { kind: 'stage', actions: ['read'] },
    { kind: 'flow',  actions: ['read'] },
  ],
})
@Get('/stages')
async listStages(@PermissionContext() ctx: PermissionContextType) {
  // ForbiddenException somente se TODOS os recursos forem negados
  // ctx.deniedResources indica quais recursos tiveram ações negadas (negação parcial)
}

@PermissionContext()

Decorator de parâmetro que extrai o PermissionContextType definido pelo interceptor.

export type PermissionContextType =
  | { strategy: PermissionStrategy.LEGACY }
  | {
      strategy: PermissionStrategy.CERBOS
      queryPlan?: Record<string, unknown>      // PlanResources — aplicar como filtro no repositório
      deniedResources?: CerbosCheckDenial[]    // CheckResources — vazio = totalmente permitido
    }

Use strategy para distinguir rotas autorizadas pelo Cerbos das rotas legacy.


CerbosFeatureTogglePort

Implemente esta interface na API consumidora para habilitar o toggle do Cerbos por conta:

import { Injectable } from '@nestjs/common'
import { CerbosFeatureTogglePort } from '@apipass/cerbos-pep'

@Injectable()
export class FeatureToggleCerbosAdapter implements CerbosFeatureTogglePort {
  constructor(private readonly featureToggleService: FeatureToggleS3Service) {}

  async isCerbosEnabled(accountId: string): Promise<boolean> {
    const features = await this.featureToggleService.getFeatures(accountId)
    return features?.isCerbosEnabled() ?? false
  }
}

Headers Esperados

O interceptor lê o contexto de autorização dos headers injetados pelo API Gateway — nunca diretamente do JWT.

| Header | Descrição | |---|---| | account_id | ID da conta (tenant) — usado como escopo accountId no Cerbos | | role | Role do usuário (ex: account-admin) — sanitizado para account_admin antes de enviar ao Cerbos | | account_domain | Domínio da conta — mesclado em principal.attr e resource.attr |