Trail Map Use-Case Catalog Multi-Tenant Org & Auth
🏢 Foundation · Module 01

Multi-Tenant Org & Auth: One Platform, Zero Data Leakage

Every SmartLite customer gets what feels like a private CRM — on a single shared platform. Learn the mechanism that makes cross-tenant data leakage structurally impossible, then prove it to yourself hands-on.

4
Units
~10 min
Time to Complete
80 pts
Available
1 Badge
Org Setup Specialist
Unit 1 · Business Problem

Why multi-tenancy matters

DC
Devon Cole · Platform Operations Lead

"We sell to hundreds of companies. Each one needs to feel like they have their own private CRM — but if we spin up a separate server and database per customer, our infrastructure bill and ops burden explode before we even hit our first hundred customers."

This is the core SaaS tension: customers want isolation, the business needs shared infrastructure. Get it wrong and either your infrastructure costs spiral, or — far worse — one customer's data becomes visible to another.

💡
Business outcome
One shared, cost-efficient platform serving unlimited customer organizations — with data isolation that is enforced structurally in code, not by convention or trust.
Unit 2 · How It Works

Anatomy of tenant isolation

SmartLite uses a shared-schema model: one database, one set of tables, serving every customer org. Isolation is enforced on every single request through a three-part chain:

StepMechanismWhat it guarantees
1. LoginJWT issued with an embedded orgId claimEvery subsequent request proves which org it belongs to
2. Request entersJwtAuthFilter writes the token's orgId into TenantContext (a ThreadLocal)The current org is known for the entire lifetime of the request
3. Every queryServices scope reads/writes with TenantContext.getOrgId()You can only ever operate on your own org's rows
4. Every single-record fetchOrgIsolationGuard.assertBelongsToCurrentOrg(entity.getOrgId())Even a guessed or leaked internal ID can't be used to read another org's record
Why the guard matters
Scoped queries alone stop most leaks, but a direct-by-ID lookup could still bypass a missing filter. The guard is the final, explicit check — the platform's rule is "always create with orgId, always query with orgId, always guard reads."

Org registration itself provisions a brand-new tenant in one transaction: it creates the organization row, the first Admin user, and seeds all 16 standard objects (Lead, Contact, Account, Opportunity, Case, and more) — so a new customer is productive immediately, with no manual setup step from your ops team.

Unit 3 · Hands-On Challenge

Register a new org and prove the isolation

Open the registration pageGo to /org/register on your SmartLite frontend.
Create Org #1Enter an org name (e.g. "Northwind Distributors") and an admin email + password. Log in and create one test Lead.
Log out, then register Org #2Repeat registration with a different org name (e.g. "Contoso Supplies") and a different admin login.
Check the Leads list in Org #2You'll see it's empty — even though Org #1 already has a Lead in the same shared database.
Inspect the JWT (optional)Decode the token stored in localStorage after logging into either org (e.g. via jwt.io) and note the different orgId claim in each.
⚠️
What you just proved
Two organizations, same database, same application code — zero visibility into each other's records. That's tenant isolation working as designed, not a lucky coincidence of empty test data.
Unit 4 · Knowledge Check

Test what you learned

1. What does JwtAuthFilter write into TenantContext on every incoming request?
The user's password hash
The orgId claim extracted from the JWT
A list of every org in the database
2. Why does SmartLite call OrgIsolationGuard.assertBelongsToCurrentOrg() after every single-record fetch by ID?
To speed up the database query
To stop a guessed or leaked internal ID from reading another org's record
It's only used for audit logging