Summary
RBAC becomes interesting when the product gains tenants, modules, revocation rules, and data scope. The core lesson from my office projects: keep permission resolution grounded in the database, make tenant boundaries explicit, and treat module access as a final gate instead of duplicating role data.
What I learned comparing flat permission catalogs, per-request scope injection, tenant roles, module gates, and immediate revocation. In this post, I'll walk through the key concepts with code examples drawn from real production implementations.
The Real Problem
I worked on production ERP-style systems where access control was not just a list of permissions. The hard parts were row-level scope, tenant isolation, module subscriptions, soft-delete reactivation, and immediate revocation when an admin changes a role. A token carrying stale permissions would have been convenient, but it would also be wrong.
Design 1: Flat Roles with Scope Injection
The simpler system used a flat User -> Role -> Permission graph. The middleware resolved active roles and permissions per request, then injected a scope object into the context so handlers could filter rows without rebuilding authorization logic.