DEV Community

KASOIR ABBAS
KASOIR ABBAS

Posted on

Building Multi-Tenant Auth from Scratch Is Painful. So I Open-Sourced MT-URBAC (NestJS + Angular)

Every time you build a SaaS product, you hit the same wall: spending the first few days re-writing multi-tenant architecture, handling tenant context isolation, setting up JWT guards, and building permission directives.

After open-sourcing the initial Unified Role-Based Access Control boilerplate, the most common question I thought about was: “How to scale this for multi-tenancy?”

Building multi-tenant apps means dealing with a cascade of complexities: tenant context resolution, isolated access control policies, routing adjustments, and clean database partitioning. Building all of that from scratch for every B2B SaaS project is a massive time sink.

So I built a production-ready solution once, engineered it cleanly, and open-sourced it: MT-URBAC (Multi-Tenant Unified Role-Based Access Control).

What is MT-URBAC?

MT-URBAC is a full-stack, enterprise-grade boilerplate designed to let you spin up a secure, multi-tenant B2B application in under five minutes.

  • Backend: NestJS, TypeORM, PostgreSQL
  • Frontend: Angular, OptimusUI, Tailwind CSS
  • License: 100% Free & Open-Source (MIT)

Key Architectural Breakthroughs

1. Zero-Hassle Local Multi-Tenant Routing
Testing subdomains locally usually requires hacking your OS /etc/hosts file and running custom proxy configurations. MT-URBAC solves this out of the box with dual-mode routing:

  • Local Development (Path-Based): Zero setup required. Test tenant boundaries instantly using clean paths like http://localhost:4200/tenant-a/login or http://localhost:4200/admin/....
  • Production (Subdomain-Based): Automatically maps incoming host headers (tenant-a.yourdomain.com) to tenant contexts seamless in production.

2. Clean Top-Down Grouping (No Junction-Table Hell)
Instead of messy three-way many-to-many junction tables that destroy query performance, MT-URBAC enforces a streamlined hierarchy:
User → Group → Role → Privilege

3. Automatic Privilege Escalation Defense
Security flaw #1 in custom RBAC systems is horizontal/vertical privilege escalation (e.g., an Admin granting someone Super Admin privileges). MT-URBAC assigns numeric weight levels to every role (e.g., Admin = 50, Super Admin = 100). The NestJS guards intercept and reject any action where a user attempts to mutate or assign a role higher than their own level.

Developer Experience (DX) First

Protecting backend endpoints takes a single line:

@Post('create')
@RequirePermissions('user:create')
async createNewUser() {
  // Executed only if the user possesses 'user:create' in their active tenant context
}
Enter fullscreen mode Exit fullscreen mode

Hiding or rendering elements dynamically in Angular requires zero boilerplate logic in your components:

<!-- Automatically listens to user permission state -->
<button *hasPermission="'user:delete'" class="p-button-danger">
  Delete User
</button>
Enter fullscreen mode Exit fullscreen mode

Try It in 2 Minutes

# 1. Clone & install
git clone https://github.com/kasoir/mt-urbac.git
cd mt-urbac/backend && npm install

# 2. Seed database & start
npm run seed
npm run start:dev
Enter fullscreen mode Exit fullscreen mode

The repository ships with an automated database seeder that provisions default roles, privileges, and a Super Admin account out of the box (admin@mt-urbac.com / Admin123!).

Check out the source code on GitHub: https://github.com/kasoir/mt-urbac

If this saves you a weekend of architecture setup, drop a Star on the repo! I'd love to hear in the comments how you typically handle multi-tenancy isolation in your projects.

Top comments (0)