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

devclassic-rbac

v1.0.0

Published

Enterprise Role-Based (RBAC) & Attribute-Based (ABAC) Permission & Route Guard Engine for React, Next.js, and Modern Web Applications by devclassic.

Readme

devclassic-rbac

Enterprise Role-Based (RBAC) & Attribute-Based (ABAC) Permission Engine for Modern Full-Stack Web Applications

npm version License: MIT TypeScript Dual ESM/CJS Zero Runtime Deps

Guard your Frontend UI and your Backend APIs with the exact same security rules — zero discrepancy, zero exploits.


📖 Table of Contents


✨ Why devclassic-rbac?

Most permission libraries either only run in React (leaving your backend vulnerable to direct Postman/curl requests) or only run in Node.js (leaving your frontend developers to manually build button-hiding logic).

devclassic-rbac solves this by giving you a unified, isomorphic engine:

| Capability | What it gives you | | :--- | :--- | | Full-Stack Parity | Share one single role/permission config between your React components and your Backend API. | | Graceful "Disabled" Mode | Instead of buttons mysteriously vanishing from the page, keep them visible but disabled with an explanatory tooltip (fallback="disabled"). | | Role Hierarchy & Inheritance | Define parent/child role graphs (e.g. super_admin > admin > manager > viewer) with automatic cycle detection. | | Wildcard Matcher | Standard globs (users:*, facility:reports:*, *). | | Dynamic ABAC | Evaluate runtime conditions (resource ownership, geographic boundaries, financial limits). | | Zero Runtime Dependencies | The core engine is lightweight pure TypeScript — blazingly fast with 0 external dependencies. | | Dual ESM & CJS | Seamlessly imports in modern Vite/Next.js (import) and legacy Node.js (require). |


📦 Installation

npm install devclassic-rbac
# or
yarn add devclassic-rbac
# or
pnpm add devclassic-rbac

🚀 60-Second Quickstart

Step 1: Define your roles once (rbac.config.ts)

// rbac.config.ts
import { RBACConfig, createRBACServer } from "devclassic-rbac";

export const rbacConfig: RBACConfig = {
  roles: {
    super_admin: ["admin"],
    admin: {
      inherits: ["manager"],
      permissions: ["facilities:*", "users:*"],
    },
    manager: {
      inherits: ["viewer"],
      permissions: ["facilities:create", "facilities:edit", "reports:export"],
    },
    viewer: {
      permissions: ["facilities:read", "reports:read"],
    },
  },
  superRole: "super_admin", // Automatically bypasses all checks
};

// Backend server instance:
export const serverRBAC = createRBACServer(rbacConfig);

Step 2: Wrap your app (layout.tsx or main.tsx)

"use client";

import { RBACProvider } from "devclassic-rbac";
import { rbacConfig } from "./rbac.config";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  // Current user from your auth session (NextAuth, Supabase, JWT, etc.)
  const currentUser = {
    id: "usr_10",
    name: "Amina Lawal",
    roles: ["manager"], // inherits 'manager' + 'viewer'
  };

  return (
    <RBACProvider config={rbacConfig} user={currentUser}>
      {children}
    </RBACProvider>
  );
}

Step 3: Guard your button

import { Protect } from "devclassic-rbac";

export function ActionButtons() {
  return (
    <Protect
      permission="reports:export"
      fallback="disabled"
      disabledTooltip="Requires Manager or Admin role to export reports."
    >
      <button onClick={handleExport}>Export CSV</button>
    </Protect>
  );
}

🛡️ Part 1: Frontend Guarding (React & Next.js)

1. <Protect> Declarative Gate

A. Hide unauthorized buttons entirely:

<Protect permission="facilities:create">
  <button className="btn-primary">Add Facility</button>
</Protect>

B. Enterprise UX: Keep button visible, but disabled with tooltip:

<Protect
  permission="facilities:delete"
  fallback="disabled"
  disabledTooltip="Only Administrators can delete facilities."
>
  <button onClick={handleDelete}>Delete Facility</button>
</Protect>

C. Role-based check:

<Protect role={["admin", "super_admin"]} fallback={<span>Admin only</span>}>
  <AdminPanel />
</Protect>

D. Dynamic ABAC check on a resource:

<Protect permission="facilities:edit" resource={selectedFacility} fallback="disabled">
  <button onClick={handleEdit}>Edit Facility</button>
</Protect>

2. <Can> Semantic Gate

For developers who prefer natural English syntax:

import { Can } from "devclassic-rbac";

// Verb + Noun syntax:
<Can I="export" a="report" fallback="disabled">
  <button>Export Data</button>
</Can>

// Resource-passed check:
<Can I="edit" a="user" pass={targetUser}>
  <button>Edit User</button>
</Can>

3. <ProtectedRoute> Page Guard

Guards entire pages or layouts. Unauthorized visitors are shown a customizable <AccessDenied /> screen or redirected.

// app/admin/page.tsx
"use client";

import { ProtectedRoute } from "devclassic-rbac";

export default function AdminSettingsPage() {
  return (
    <ProtectedRoute
      role="admin"
      redirectTo="/unauthorized" // Optional: redirect unauthorized visitors
      loading={<p>Verifying admin privileges...</p>}
    >
      <AdminSettingsDashboard />
    </ProtectedRoute>
  );
}

4. React Hooks Reference

import { useRBAC, usePermission, useRole, useGuard } from "devclassic-rbac";

function MyComponent() {
  // 1. Reactive permission boolean:
  const canCreate = usePermission("facilities:create");

  // 2. Reactive role boolean:
  const isAdmin = useRole("admin");
  const isManagerOrAdmin = useRole(["manager", "admin"]); // any

  // 3. Full engine access:
  const { user, roles, permissions, can, hasRole, explain } = useRBAC();

  // 4. Client-side navigation guard:
  const { isAuthorized } = useGuard({
    role: "admin",
    redirectTo: "/403",
  });

  return <div>{canCreate && <button>Create</button>}</div>;
}

🖥️ Part 2: Backend & API Guarding (Node.js, Express, Next.js Route Handlers)

1. Next.js Route Handlers & Server Actions

Use rbac.assert() to reject unauthorized requests with a clean 403 status:

// app/api/facilities/route.ts
import { NextResponse } from "next/server";
import { serverRBAC } from "@/app/rbac.config";
import { getAuthUser } from "@/lib/auth";

export async function POST(req: Request) {
  const user = await getAuthUser(req);

  // 🛡️ Blocks unauthorized calls from Postman/curl:
  try {
    serverRBAC.assert(user, "facilities:create");
  } catch (err: any) {
    return NextResponse.json({ error: err.message }, { status: 403 });
  }

  const body = await req.json();
  const created = await db.facility.create({ data: body });
  return NextResponse.json(created, { status: 201 });
}

2. Express.js REST API Middleware

Use pre-built middleware rbac.requirePermission and rbac.requireRole:

import express from "express";
import { createRBACServer } from "devclassic-rbac";

const app = express();
app.use(express.json());

const rbac = createRBACServer(rbacConfig);

// Enforce permission:
app.post(
  "/api/facilities",
  authMiddleware, // sets req.user
  rbac.requirePermission("facilities:create"),
  async (req, res) => {
    res.json({ success: true, message: "Facility created" });
  }
);

// Enforce role:
app.delete(
  "/api/users/:id",
  authMiddleware,
  rbac.requireRole(["admin", "super_admin"]),
  async (req, res) => {
    res.json({ success: true, message: "User deleted" });
  }
);

3. Next.js Edge Middleware (middleware.ts)

Protect frontend routes at the Edge before the page bundle even downloads:

// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { createRBACMatcher } from "devclassic-rbac";

const routeMatcher = createRBACMatcher([
  { path: "/admin/**", roles: ["admin", "super_admin"], redirectTo: "/403" },
  { path: "/finance/**", permissions: ["finance:view"], redirectTo: "/403" },
]);

export function middleware(req: NextRequest) {
  const user = getUserFromToken(req);
  const result = routeMatcher.match(req.nextUrl.pathname, user);

  if (!result.authorized && result.redirectTo) {
    return NextResponse.redirect(new URL(result.redirectTo, req.url));
  }

  return NextResponse.next();
}

export const config = {
  matcher: ["/admin/:path*", "/finance/:path*"],
};

🎯 Dynamic ABAC (Attribute-Based Access Control)

Support real-world dynamic rules based on the user, resource, or environment:

const rbacConfig: RBACConfig = {
  policies: [
    // 1. Author ownership rule
    {
      name: "author-only",
      permission: "articles:edit",
      condition: ({ user, resource }) => user?.id === resource?.authorId,
    },

    // 2. Spending threshold rule
    {
      name: "spending-limit",
      permission: "invoices:approve",
      condition: ({ user, resource }) =>
        (resource?.amount ?? 0) <= (user?.attributes?.approvalLimit ?? 0),
    },

    // 3. State-level jurisdiction
    {
      name: "state-boundary",
      permission: "facilities:edit",
      condition: ({ user, resource }) =>
        user?.attributes?.state?.toLowerCase() === resource?.state?.toLowerCase(),
    },
  ],
};

🔍 Audit & Explainability (explain())

Diagnose permissions or stream access decisions to Datadog/Sentry:

const decision = engine.explain("facilities:edit", facility);

console.log(decision.granted);       // true or false
console.log(decision.reason);        // e.g. "Denied by ABAC policy condition: 'state-boundary'"
console.log(decision.matchedPolicy); // "state-boundary"
console.log(decision.rolesChecked);  // ["manager", "viewer"]

🎨 Production <AccessDenied /> Screen

Self-contained, responsive 403 page with zero external CSS or icon dependencies:

import { AccessDenied } from "devclassic-rbac";

export default function ForbiddenPage() {
  return (
    <AccessDenied
      title="Restricted Access"
      message="You do not have the required permissions to view this audit."
      code="403"
      homeUrl="/dashboard"
      showBackButton={true}
    />
  );
}

📚 Complete Guides & Documentation


❓ FAQ & Troubleshooting


📄 License

MIT © devclassic