Designing Multi-Tenant SaaS with Spring Boot and Keycloak
How I handle tenant isolation, authentication, and data separation in CRMCup and PharmacyHub using JHipster, Keycloak, and PostgreSQL.
By Hafiz Syed Muhammad Usman
Every SaaS product I have built — CRMCup, PharmacyHub, AscendLMS — needs multi-tenant isolation. Tenants must not see each other's data, but the codebase should stay simple. Here is the pattern I have settled on.
Keycloak handles identity, not your app
Authentication and tenant resolution live in Keycloak. Each tenant gets a realm (or organization within a realm). The Spring Boot backend receives a JWT with tenant context already resolved — no custom auth code needed. This separation means you can add SSO, MFA, and social login without touching your business logic.
Tenant isolation strategies
- Schema-per-tenant — strongest isolation, harder to manage migrations (used in Procraftor per-service schemas)
- Shared schema with tenant_id column — simpler, requires discipline with queries (used in CRMCup)
- Database-per-tenant — maximum isolation, highest operational cost
JHipster as the starting point
JHipster generates a production-ready Spring Boot + frontend scaffold with Keycloak integration, Liquibase migrations, and Swagger docs out of the box. I use it as the foundation for CRMCup, PharmacyHub, and AscendLMS, then customize the domain model and modules on top. It saves weeks of boilerplate.
The mistake I keep seeing
Building custom authentication when Keycloak (or any mature IdP) handles it better. Your app should focus on business logic. Let the identity provider handle tokens, sessions, password policies, and federation.