Notes on RBAC, architecture, and transparency

Blog

The first question in every access postmortem

When an access incident hits, the first question is never "how did the bug happen" — it's "who could do this, and who approved it." Here's why most teams can't answer that in under an hour, and what changes when the answer is a grep.

audit-loggingengineering-managementincident-response

Can file-based RBAC scope what an AI agent touches?

2026's agent security data says the dominant failure mode is over-permissioning, not model behavior — here's an honest look at where folder-scoped RBAC actually helps, and where it runs out.

ai-agentssecurityarchitecture

Why rbac-fs's live-reload never races its own writes

The specific chokidar configuration and cache-invalidation ordering that keep rbac-fs's live-reload from ever serving a role it just wrote itself, or missing an edit from someone else.

live-reloadarchitecturecore-engine

What a Quarterly Access Review Actually Costs You

SOC 2 doesn't just want you to review access quarterly — it wants evidence for every quarter, and most teams are paying for that in engineering-manager hours nobody budgeted.

complianceengineering-managementaudit-logging

Signs your RBAC model is about to outgrow itself

The concrete symptoms that separate "this needs a condition" from "this needs a relationship graph" — and the honest, incremental path if you're actually in the second category.

architecturemulti-tenantrbac

rbac-fs vs OPA vs Zanzibar-style authorization

OPA/Rego and Zanzibar-style engines like OpenFGA and SpiceDB solve real problems rbac-fs doesn't — here's what each actually costs to operate, and an honest line for where rbac-fs stops being the right tool.

comparisonoparebac

The Authorization Cost Nobody Is Pricing In

The build-vs-buy literature treats authorization as a choice between building a service and buying one, but the cost data both sides cite actually argues for a third option neither names.

build-vs-buyengineering-costsfounders

Why the permission check has zero dependencies

2026's npm supply-chain attacks got names and dates — here's why the code path that decides who's allowed to do what is the worst place to carry that exposure, and what rbac-fs does about it specifically.

securitycore-enginearchitecture

Permission drift is a solved problem in IaC. Not in RBAC.

Infrastructure teams spent years naming and tooling against "drift" — the gap between declared and enforced state. Most RBAC systems have the exact same failure mode and no name for it.

architecturerbaclive-reload

What a due-diligence checklist finds in your authorization layer

SOC 2 auditors and acquisition due-diligence teams both eventually ask who can do what and prove it — here's what they check, and how rbac-fs answers most of it without extra tooling.

compliancesecuritydue-diligence

Why file-based RBAC beats a policy blob

Git-diffable roles aren't a gimmick — they change who can review a permission change, and when, compared to an opaque policy blob in a database.

rbacarchitecturesecurity

rbac-fs vs Casbin vs CASL

Three real libraries, three different trade-offs — storage model, framework coverage, and what happens when you need to audit a permission change.

comparisoncasbincasl

Multi-tenant permissions without a database

Folder isolation instead of a WHERE clause — what that structurally buys you for tenant isolation, and where it stops being enough at real scale.

multi-tenantarchitecture

How rbac-fs resolves a permission check

What actually happens between calling can() and getting true or false back — role loading, inheritance, and condition evaluation, in order.

core-enginearchitecture

Building your first permission check with rbac-fs

A tutorial-paced walkthrough of installing rbac-fs, creating a role, and running your first can() check, in both JavaScript and TypeScript.

core-enginetutorial

Why roles should change without a redeploy

A permission system that requires a deploy to add one role is solving the wrong problem — how rbac-fs makes role changes a runtime operation instead.

dynamic-rolesarchitecture

Tutorial: create, grant, revoke, delete roles

A hands-on walkthrough of every dynamic role management call in rbac-fs, with the actual file contents shown at each step.

dynamic-rolestutorial

Every allow and deny, logged

How rbac-fs's built-in audit trail works — JSONL format, why not a single JSON array, and what's actually in each record.

audit-loggingsecurity

Tutorial: querying and rotating rbac-fs audit logs

A hands-on walkthrough of configuring log rotation and querying audit history in rbac-fs, including what each rotation option actually controls.

audit-loggingtutorial

Conditional permissions in rbac-fs

Beyond allow or deny — how rbac-fs's condition system handles "approve your own expense report" without reaching for eval() or a rules engine.

conditionsarchitecture

Tutorial: building a condition tree with rbac-fs

Step-by-step construction of an AND/OR condition tree in rbac-fs, from a single clause to a nested, real-world approval rule.

conditionstutorial

Tutorial: setting up multi-tenant roles

A hands-on walkthrough of tenant-scoped and shared roles in rbac-fs, including the path-sanitization behavior you should verify yourself.

multi-tenanttutorial

Hand-editing roles and how live-reload picks it up

Role files are cached in memory for speed — here's how rbac-fs's chokidar-backed watcher keeps that cache honest when someone edits a file by hand.

live-reloadarchitecture

Tutorial: hand-editing a role file, live

A step-by-step demo of rbac-fs's live-reload — edit a role JSON file directly and see the permission change without restarting anything.

live-reloadtutorial

Permissions in the browser, without a filesystem

rbac-fs's Node core never belongs in a browser bundle — here's how RBACClient gives the frontend the same can() call without any filesystem dependency.

browser-clientarchitecture

Tutorial: RBACClient without a framework

A vanilla-JS walkthrough of RBACClient — useful on its own, and as the mental model underneath every rbac-fs frontend framework adapter.

browser-clienttutorial

The guardrails you don't have to build yourself

rbac-fs bakes path sanitization, schema validation, reserved names, and circular-inheritance detection into Core Engine, not left to consumers.

securityarchitecture

Tutorial: verifying the security guardrails

Don't take the docs' word for it — four runnable snippets proving path sanitization and circular-inheritance detection actually reject what they claim to.

securitytutorial

NestJS guards: why unguarded routes fail open

rbac-fs's NestJS adapter is opt-in per route via @RequirePermission() — a route with no decorator is allowed through unchecked, deliberately.

nestjsadapters

Tutorial: wiring up the NestJS RbacGuard

A runnable walkthrough of rbac-fs's NestJS guard and decorator, driving RbacGuard directly so you can see every outcome without booting a full Nest app.

nestjstutorial

One middleware shape, three Node HTTP frameworks

rbac-fs's Express, Koa, and Fastify adapters share the same rbacMiddleware shape — here's what stays the same and what each framework forces to differ.

expressadapters

Tutorial: guarding an Express route with rbac-fs

A runnable, curl-able Express example — one guarded route, three requests, three different outcomes, and the auth-ordering rule that makes it work.

expresstutorial

Fastify's adapter is a plugin, not middleware

rbac-fs's Fastify adapter must be registered at the root app, not inside an encapsulated sub-plugin — the encapsulation rule that makes that a hard requirement.

fastifyadapters

Tutorial: the Fastify rbacPlugin end to end

A runnable Fastify example covering plugin registration, per-route rbac config, and both the allowed and denied response paths.

fastifytutorial

Koa: why rbac-fs reads the user from ctx.state

rbac-fs's Koa adapter shares Express's rbacMiddleware signature but reads the user from ctx.state — Koa's own documented convention, not an arbitrary choice.

koaadapters

Tutorial: guarding a Koa route with rbac-fs

A runnable Koa example — same rbacMiddleware shape as Express, ctx.state instead of req.user, three requests and three outcomes.

koatutorial

Declarative permissions in React with <Can>

rbac-fs's React adapter follows CASL's I/a naming convention on purpose — one less thing to relearn if your team already knows CASL's mental model.

reactadapters

Tutorial: testing React components headlessly

A headless react-test-renderer walkthrough of <Can>, RbacProvider, and usePermission() — the same technique the adapter's own test suite uses.

reacttutorial

Vue's v-can directive: why it hides, not unmounts

rbac-fs's v-can directive toggles display:none like v-show — a deliberate choice, different from the true unmount you get from rbac-fs's Angular and React adapters.

vueadapters

Tutorial: verifying the Vue adapter headlessly

A runnable, no-browser walkthrough of rbac-fs's Vue plugin, v-can directive, and usePermission() composable using the same verification approach as its test suite.

vuetutorial

Angular's *rbacCan: real unmount, not hide

rbac-fs's Angular adapter does a real ViewContainerRef unmount/remount, matching *ngIf's own public API instead of a display:none toggle.

angularadapters

Tutorial: verifying *rbacCan, no compiler needed

A runnable walkthrough that drives RbacService and RbacCanDirective directly with a fake ViewContainerRef — the same approach the adapter's own test suite uses.

angulartutorial

Svelte: explicit stores and actions, not context

rbac-fs's Svelte adapter closes over an explicit RBACClient instead of Svelte's context API — favoring traceability over implicit wiring.

svelteadapters

Tutorial: verifying the Svelte adapter headlessly

A runnable, no-browser walkthrough of createPermissionStore and createCanAction — the store and action primitives underneath rbac-fs's Svelte adapter.

sveltetutorial