rbac-ui
Role-Driven UI & EPS Framework
A lightweight, tree-based RBAC framework for predictable, explicit, and
flexible access control in frontend applications.
#rbac-ui
Resource-Based Access Control for modern frontend apps.
A lightweight, tree-based, zero-dependency RBAC framework for frontend applications: predictable, explicit, and flexible access control.
- Fast tree-based permission evaluation.
- Intuitive permission grammar like
ui:dashboard:checklist. - Nested hierarchical permissions.
- Negation rules like
!ui:settings. - Backend-agnostic design.
- Framework-agnostic core with optional framework bindings.
#The Problem We're Solving
Frontend applications need to control what users can see and do, but traditional approaches have limitations:
- Role-based checks scattered throughout code become hard to maintain.
- String comparisons and role lists don't scale as features grow.
- No clear way to represent hierarchical permissions (e.g., 'dashboard' but not 'dashboard:checklist').
- Difficult to let non-developers manage access without code changes.
- No standard way to express 'deny this specific thing' while allowing the parent.
This framework solves UI role access by providing a tree-based permission system that's fast, explicit, and manageable.
#Why Use This Approach
- Tree-based evaluation means O(depth) complexity—fast even with thousands of permissions.
- Explicit permission tokens make it clear what each UI element requires.
- Hierarchical structure matches how products are organized (pages → sections → controls).
- Negation rules let you grant broad access and surgically remove specific features.
- Simple string-based tokens work with any backend—just pass an array of strings.
- Admin dashboards can manage permissions without developer intervention.
#Core Principles
- Treat the server as the source of truth for authorization and the client as a guide for visibility.
- Prefer capability permissions over role names in every interface decision.
- Use a single readable token language for both UI visibility and API enforcement.
- Adopt a compact signed Effective Permission Set (EPS) per user and context.
- Keep the vocabulary human-readable, documented, and guessable.
- Favor small primitives composed well over complex policy tools.
#Framework Use Cases
#Product Managers Managing Access via Dashboard
This is one of the most valuable real-world use cases: PMs/Ops/Support manage access in a dashboard while devs implement the permission model once and reuse it forever.
Why this is powerful:
- PMs/Ops/Support can grant access instantly, revoke features without deployments, and run experiments (feature flags via RBAC).
- Developers don't get interrupted for every access change and only implement the system once.
Your RBAC grammar maps directly to checkboxes and toggles in an admin UI:
Example tokens
ui:dashboard
ui:billing
!ui:billing:refund
ui:dashboardgrants access to all dashboard features (reports, analytics, widgets, etc.).ui:billinggrants access to all billing features.!ui:billing:refunddenies the refund feature specifically, while keeping other billing features accessible.
This evolves naturally into RBAC as a feature management system: feature gating, audience control, gradual rollouts, permissions, and admin overrides.
#Feature Flags & Experimentation
RBAC tokens can double as feature flags, enabling product teams to control feature visibility and access without code deployments.
- Use permission tokens to gate new features during development and testing.
- Gradually roll out features to specific user segments using permission assignments.
- Run A/B tests by granting different permission sets to different user groups.
- Quickly disable features by revoking permissions without code changes.
#Framework Features
#Smart Permission Grammar
ui:dashboardgrants access.ui:dashboard:reportsgrants nested access.!ui:dashboard:checklistdenies a child path.*can represent wildcard top-level access (if you enable it).
#Tree-Based Permission Engine
- Permissions compile into a static permission tree.
- No repeated looping over role strings.
- Ultra-fast access checks with complexity proportional to depth (
O(depth)).
#Deny Semantics
- Treat deny as removal of a node and its descendants unless a more specific allow exists.
- Reserve deep wildcards and broad denies for administrative bundles and audits.
#Framework Usage
#Permission Language
Use permission tokens as the contract between product intent (what a user can see and do) and implementation (what the UI shows).
Token grammar
namespace:resource[:segment...][:action]
ui:dashboard
ui:billing:refunds
ui:invoice:toolbar:export
ui:settings:profile:edit
- Use the
uinamespace for UI visibility and feature access. - Use hierarchy with intent; keep depth reasonable for clarity.
- Granting a parent permission (e.g.,
ui:dashboard) gives access to all child paths (e.g.,ui:dashboard:reports,ui:dashboard:analytics) until a specific child is denied. - Use negation for surgical pruning: deny specific children while keeping parent access (e.g.,
ui:dashboardwith!ui:dashboard:checklistgrants all dashboard features except the checklist). - Use wildcards carefully: single-level
*.
#Naming Guidance
- Prefer intent-based names such as
ui:invoice:toolbar:exportover implementation labels. - Keep segments lowercase and use kebab-case where needed.
- Limit token depth to a practical range that matches the product shape.
#Admin / PM Dashboard Workflow
At runtime the system can stay simple: permissions are just strings stored in a DB, managed by a dashboard, and issued to clients as a signed EPS.
How it looks in storage
ui:dashboard
ui:billing
!ui:billing:refund
ui:invoice:export
- Represent tokens as a catalog-driven tree (so the UI is generated, not hardcoded).
- Persist changes as token lists (or diffs) in the database.
- Mint a fresh EPS at login (and on tenant switch) and ship it to the client.
- Always validate permissions on the server; UI gates are for visibility, not security.
#Developer Experience (Enums / Typed Tokens)
From a developer-experience standpoint, raw strings are risky: typos become silent access bugs. Enums/typed tokens give autocomplete, refactor safety, and eliminate a whole class of mistakes.
Enums instead of raw strings
hasAccess("ui:dashbord"); // typo -> silent bug
export enum UIResources {
Dashboard = "ui:dashboard",
DashboardChecklist = "ui:dashboard:checklist",
Settings = "ui:settings",
}
hasAccess(UIResources.DashboardChecklist);
- Typed tokens are best for application code and internal tools.
- Runtime payloads (DB/EPS) can remain strings; types are a build-time safety layer.
#Support BOTH (Runtime Strings + Typed Tokens)
The same RBAC engine can support both admin-managed strings and developer-friendly types, because at runtime everything is still a string[].
- For admins/PMs: store and edit plain strings in a DB; ship strings in EPS.
- For developers: use generated enums/constants for autocomplete and safe refactors.
- Both feed the same matcher because the runtime engine operates on tokens (strings).
#Catalog, Linting & Conventions
- Maintain a permission catalog in both markdown and JSON for teams and tools.
- Describe each token with one sentence stating what it unlocks and where.
- Generate diffs for role changes and review them like code changes.
- Enforce naming lint rules in CI to prevent mistakes.
- Disallow deep wildcard by default; allow only when explicitly configured.
- Resolve aliases to canonical tokens at build time for consistency.
- Fail builds on unknown namespaces, malformed tokens, and invalid catalog entries.
#Strategic Takeaway
This is not just a frontend RBAC library. It becomes an engine layer for access control, feature flags, permission management, no-code access configuration, and product experimentation.
- Tree-based matching, wildcards, and negation make the language expressive.
- Framework-agnostic design means it works with any frontend stack.
- Admin dashboard management makes access self-serve without deployments.
- Type-safe tokens make it safe and scalable for large teams.
- Simple string-based API means easy integration with any backend system.