Skip to content

Fire ShieldType-safe RBAC Library

Fast, flexible, and framework-agnostic Role-Based Access Control for JavaScript/TypeScript

Fire Shield

Quick Start โ€‹

Install Fire Shield in your project:

bash
npm install @fire-shield/core
bash
yarn add @fire-shield/core
bash
pnpm add @fire-shield/core

Basic Usage โ€‹

typescript
import { RBAC } from '@fire-shield/core'

// Create RBAC instance
const rbac = new RBAC()

// Define roles and permissions
rbac.createRole('admin', ['posts:*', 'users:*'])
rbac.createRole('editor', ['posts:read', 'posts:write'])
rbac.createRole('viewer', ['posts:read'])

// Check permissions
const user = { id: '1', roles: ['editor'] }
rbac.hasPermission(user, 'posts:write') // โœ… true
rbac.hasPermission(user, 'users:delete') // โŒ false

Framework Integrations โ€‹

Fire Shield provides first-class support for popular frameworks:

vue
<template>
  <!-- Show button only if user can write posts -->
  <button v-can="'posts:write'">Create Post</button>

  <!-- Hide button if user can't delete -->
  <button v-cannot="'posts:delete'">Delete Post</button>
</template>

<script setup>
import { useRBAC } from '@fire-shield/vue'

const { can, cannot } = useRBAC()
</script>
tsx
import { Can, useRBAC } from '@fire-shield/react'

function PostEditor() {
  const { can } = useRBAC()

  return (
    <>
      {/* Conditional rendering */}
      <Can permission="posts:write">
        <button>Create Post</button>
      </Can>

      {/* Programmatic check */}
      {can('posts:delete') && (
        <button>Delete Post</button>
      )}
    </>
  )
}
tsx
import { RBACProvider } from '@fire-shield/react'
import { rbac } from '@/lib/rbac'

// In layout or _app
export default function RootLayout({ children }) {
  return (
    <RBACProvider rbac={rbac}>
      {children}
    </RBACProvider>
  )
}

// Middleware for route protection
export function middleware(request) {
  const user = getUser(request)
  if (!rbac.hasPermission(user, 'admin:access')) {
    return NextResponse.redirect('/unauthorized')
  }
}
vue
<template>
  <div>
    <!-- Use composables -->
    <button v-if="canWrite">Create Post</button>
    <button v-if="isAdmin">Admin Panel</button>
  </div>
</template>

<script setup>
const { can } = useFireShield()
const canWrite = can('posts:write')
const isAdmin = can('admin:access')
</script>
typescript
import { Component } from '@angular/core'
import { RBACService } from '@fire-shield/angular'

@Component({
  selector: 'app-posts',
  template: `
    <!-- Structural directive -->
    <button *fsCanPermission="'posts:write'">
      Create Post
    </button>

    <!-- Observable -->
    <button *ngIf="canDelete$ | async">
      Delete Post
    </button>
  `
})
export class PostsComponent {
  canDelete$ = this.rbac.can$('posts:delete')

  constructor(private rbac: RBACService) {}
}
svelte
<script>
  import { can, hasRole } from '@fire-shield/svelte'

  const canWrite = can('posts:write')
  const isAdmin = hasRole('admin')
</script>

<!-- Reactive permission checks -->
{#if $canWrite}
  <button>Create Post</button>
{/if}

{#if $isAdmin}
  <button>Admin Panel</button>
{/if}

<!-- Use actions -->
<button use:can={'posts:delete'}>Delete</button>
typescript
import { createExpressRBAC } from '@fire-shield/express'

const rbacMiddleware = createExpressRBAC(rbac, {
  getUser: (req) => req.user
})

// Protect routes
app.post('/posts',
  rbacMiddleware.requirePermission('posts:write'),
  createPost
)

app.delete('/posts/:id',
  rbacMiddleware.requirePermission('posts:delete'),
  deletePost
)
typescript
import { createFastifyRBAC } from '@fire-shield/fastify'

const { rbacPlugin, requirePermission } = createFastifyRBAC(rbac, {
  getUser: (request) => request.user
})

// Register plugin
fastify.register(rbacPlugin)

// Protect routes
fastify.post('/posts', {
  preHandler: requirePermission('posts:write')
}, createPost)
typescript
import { Hono } from 'hono'
import { HonoRBACAdapter } from '@fire-shield/hono'

const app = new Hono()
const rbacMiddleware = new HonoRBACAdapter(rbac)

// Protect routes
app.get('/admin',
  rbacMiddleware.permission('admin:access'),
  (c) => c.json({ admin: true })
)

// Works on edge: Cloudflare, Deno, Vercel
export default app

Why Fire Shield? โ€‹

Compared to other RBAC libraries

FeatureFire ShieldCasbinCASLAccessControlacl
TypeScriptโœ… Nativeโœ… Fullโœ… Full๐ŸŸก Partial๐ŸŸก Partial
Bundle Size๐ŸŽฏ ~15KB~600KB+~350KB~180KB~35KB
Dependenciesโœ… 0~510Few
Wildcard Permissionsโœ… Yesโœ… Yes (regex)๐ŸŸก Partialโœ… YesโŒ No
Role Hierarchyโœ… Yesโœ… YesโŒ NoโŒ NoโŒ No
Audit Loggingโœ… Built-in๐ŸŸก PluginโŒ NoโŒ NoโŒ No
Deny Permissionsโœ… Yesโœ… YesโŒ NoโŒ NoโŒ No
Framework Adaptersโœ… 9+๐ŸŸก Limited๐ŸŸก LimitedโŒ NoโŒ No
Maintainedโœ… Activeโœ… Activeโœ… Active๐ŸŸก Low Activity๐ŸŸก Old/Little Maintenance

Support the Project โ€‹

If you find Fire Shield helpful, consider supporting its development:

๐Ÿฅ–Buy me a banh mi

Your support helps maintain and improve Fire Shield! ๐Ÿ™

Ready to secure your application?

Get Started โ†’