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

rbac-guard

v1.0.1

Published

A lightweight, framework-agnostic, TypeScript-first role-based access control (RBAC) utility

Downloads

10

Readme

rbac-guard

A lightweight, framework-agnostic, TypeScript-first role-based access control (RBAC) utility.

npm version TypeScript Zero Dependencies

Why rbac-guard?

Managing role-based access in JavaScript/TypeScript applications often leads to scattered, inconsistent permission checks. rbac-guard provides a clean, predictable API for checking user roles that works across React, Node.js, Express, Next.js, and any other JavaScript environment.

Features:

  • 🎯 Simple API - One function, clear behavior
  • 📦 Zero dependencies - No bloat
  • 🔷 TypeScript-first - Full type safety
  • 🔌 Framework-agnostic - Works everywhere
  • 🪶 Tiny footprint - Under 1KB minified

Installation

npm install rbac-guard
yarn add rbac-guard
pnpm add rbac-guard

Quick Start

import { canAccess } from 'rbac-guard';

const user = { role: 'ADMIN' };

// Check if user can access
if (canAccess(user, ['ADMIN', 'EDITOR'])) {
  // ✅ User has access
}

API Reference

canAccess(user, allowedRoles)

Check if a user has access based on their roles.

Parameters:

  • user - User object with role: string or roles: string[], or null/undefined
  • allowedRoles - Array of allowed role names, or "*" for any authenticated user

Returns: boolean

// Single role user
canAccess({ role: 'ADMIN' }, ['ADMIN', 'EDITOR']); // true

// Multiple roles user
canAccess({ roles: ['USER', 'EDITOR'] }, ['ADMIN', 'EDITOR']); // true

// Wildcard - any authenticated user
canAccess({ role: 'VIEWER' }, '*'); // true

// Unauthenticated user
canAccess(null, ['ADMIN']); // false

Fluent API (Optional)

For more complex or readable permission checks:

import { can } from 'rbac-guard';

const user = { roles: ['ADMIN', 'VERIFIED'] };

// Check single role
can(user).withRole('ADMIN').allow(); // true

// Check any of multiple roles
can(user).withAnyRole(['ADMIN', 'SUPERADMIN']).allow(); // true

// Check all roles required
can(user).withAllRoles(['ADMIN', 'VERIFIED']).allow(); // true

// Chain conditions (all must pass)
can(user)
  .withRole('VERIFIED')
  .withAnyRole(['ADMIN', 'MODERATOR'])
  .allow(); // true

Usage Examples

React

import { canAccess } from 'rbac-guard';

function AdminPanel({ user }) {
  if (!canAccess(user, ['ADMIN'])) {
    return <p>Access denied</p>;
  }

  return <div>Admin Panel Content</div>;
}

With a custom hook:

import { canAccess, AllowedRoles } from 'rbac-guard';
import { useAuth } from './your-auth-provider';

export function useCanAccess(allowedRoles: AllowedRoles): boolean {
  const { user } = useAuth();
  return canAccess(user, allowedRoles);
}

// Usage
function Dashboard() {
  const canEdit = useCanAccess(['ADMIN', 'EDITOR']);
  
  return (
    <div>
      <h1>Dashboard</h1>
      {canEdit && <button>Edit Settings</button>}
    </div>
  );
}

Express Middleware

import { canAccess, AllowedRoles } from 'rbac-guard';
import { Request, Response, NextFunction } from 'express';

function requireRoles(allowedRoles: AllowedRoles) {
  return (req: Request, res: Response, next: NextFunction) => {
    if (!canAccess(req.user, allowedRoles)) {
      return res.status(403).json({ error: 'Forbidden' });
    }
    next();
  };
}

// Usage
app.get('/admin', requireRoles(['ADMIN']), (req, res) => {
  res.json({ message: 'Welcome, admin!' });
});

app.get('/dashboard', requireRoles('*'), (req, res) => {
  res.json({ message: 'Welcome, authenticated user!' });
});

Next.js (App Router)

// middleware.ts
import { canAccess } from 'rbac-guard';
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const user = getUserFromToken(request); // Your auth logic
  
  if (request.nextUrl.pathname.startsWith('/admin')) {
    if (!canAccess(user, ['ADMIN'])) {
      return NextResponse.redirect(new URL('/unauthorized', request.url));
    }
  }
  
  return NextResponse.next();
}

Next.js (Server Component)

import { canAccess } from 'rbac-guard';
import { getCurrentUser } from './auth';

export default async function AdminPage() {
  const user = await getCurrentUser();
  
  if (!canAccess(user, ['ADMIN'])) {
    return <div>Access Denied</div>;
  }
  
  return <div>Admin Content</div>;
}

TypeScript Support

All types are exported for full TypeScript integration:

import type { 
  RoleLike, 
  AllowedRoles, 
  UserWithRole, 
  UserWithRoles 
} from 'rbac-guard';

// Your user type can extend the base types
interface MyUser extends UserWithRoles {
  id: string;
  email: string;
  roles: string[];
}

const user: MyUser = {
  id: '123',
  email: '[email protected]',
  roles: ['ADMIN', 'USER']
};

canAccess(user, ['ADMIN']); // Full type safety

Type Guards

Utility functions for type checking:

import { hasRole, hasRoles, extractRoles } from 'rbac-guard';

hasRole(user);      // true if user has { role: string }
hasRoles(user);     // true if user has { roles: string[] }
extractRoles(user); // Returns string[] of all user roles

Edge Case Behavior

| Scenario | Result | |----------|--------| | user is null or undefined | false | | user.role is empty string | false (no valid roles) | | user.roles is empty array [] | false | | allowedRoles is empty array [] | false | | allowedRoles is "*" with valid user | true | | allowedRoles is "*" with null user | false | | Role comparison | Case-sensitive |

Design Philosophy

  1. No side effects - Pure functions, predictable behavior
  2. Fail closed - When in doubt, deny access
  3. Minimal API - One import, one function for most use cases
  4. Framework agnostic - No React/Express/Next.js specific code
  5. Junior-friendly - Code that's easy to read and understand

License

MIT