Skip to content
asim.dev
all work
open sourceSystems design & build · 2024

Scalable Authz

RBAC as a clean layer, not scattered if-statements

A role-based access control engine built to prove permissions can be a domain-agnostic layer — typed policies, composable roles, and audit-friendly checks — exercised across Posts and Events domains on Next.js App Router and MongoDB.

  • Next.js App Router
  • TypeScript
  • MongoDB
  • RBAC
Role-based CRUD permission matrix

01 / context

Authorization is where most apps quietly rot: role checks smeared across components, routes and API handlers, each slightly different, none testable. I wanted to build the version I'd want to inherit — permission logic as an explicit, typed layer that reads like policy, not archaeology.

02 / problem

The system had to answer three questions uniformly — who can do what to which resource — support role inheritance and resource-scoped rules, and stay framework-agnostic enough to drop into a Next.js app router project without contortions.

03 / decisions

Policies as data, checked in one place

ts
const policy = definePolicy({
  role: "editor",
  can: ["post:read", "post:update"],
  inherits: ["viewer"],
  scope: { "post:update": { ownerOnly: true } },
});

Roles compose through inheritance; resource-scoped conditions (like owner-only writes) are part of the policy, not a special case at the call site.

Two demo domains, one engine

Posts and Events exercise the engine with different shapes — ownership rules on one, RSVP capacity rules on the other — proving the layer doesn't leak domain assumptions.

04 / outcome

  • Single audit surface: every permission decision traces to one policy object.
  • Role inheritance and per-resource scoping without framework coupling.
  • The patterns now ship in production work at Revnix — RBAC on real storefronts.

05 / what i'd do differently

Next step would be derived caching of resolved permissions per session, and a policy diff tool — the moment permissions multiply, seeing what changed between two policy versions becomes the real product.