Evolving SaaS Identity: How We Architected Multi-Tenancy in Amazon Cognito (and What’s Next)
Evolving SaaS Identity: How We Architected Multi-Tenancy in Amazon Cognito (and What’s Next)
Building a Multi-Tenant SaaS application is a balancing act between data isolation and user convenience. In our recent project, we chose Amazon Cognito as our authentication backbone. It provides the security and compliance we need out of the box, but making it play nicely with a complex multi-tenant requirement—specifically regarding Microsoft SSO—has been an interesting engineering journey.
Here is a deep dive into our current architecture, the specific challenges we faced with Enterprise SSO onboarding, and the research we are conducting to solve them.
Phase 1: Our Current Architecture (The "Siloed" Strategy)
In our current live implementation, we prioritized strict isolation and standard configuration. We treated every customer tenant as a distinct entity configuration-wise.
1. Handling Email/Password Users
We decided to create a Single App Client in Cognito for each customer client. However, Cognito User Pools are shared spaces. If “john@example.com” belongs to Tenant A and also wants to join Tenant B using the same email, Cognito’s default behavior blocks the duplicate username.
The Solution: To enable users to use the same email across multiple clients, we implemented a “composite username” strategy. Internally, we save the username as: tenantName_userEmail (e.g., acme_john@example.com) This ensures uniqueness at the Cognito level while allowing the user to simply type their email address at login.
2. Federated Login (Google & Microsoft)
- Google: Since Google login is generally personal and consistent, we set it up as a global provider.
- Microsoft SSO: This is where things get complex. Currently, we utilize SAML Federation. For an organization to use their corporate Microsoft credentials, we treat their Azure AD as a unique Identity Provider (IdP) and attach it to their specific App Client in Cognito.
The Pain Point: The “Enterprise App” Friction
While this architecture works, it is operationally heavy.
For a customer to enable Microsoft SSO, we currently have to ask them to create an Enterprise Application in their own tenant Azure account. This requires their IT admin to exchange XML metadata with us and configure claims manually. This high-friction onboarding often delays deployment and requires significant support from our team.
Phase 2: The Future (Researching a "Unified" Approach)
To eliminate the friction of manual SAML configuration, our engineering team has been researching a “Zero-Touch” SSO strategy.
Instead of asking customers to configure apps in their Azure instances, our research proposes reversing the flow: utilizing a single multi-tenant app in our Azure environment.
The Proposed Architecture: Multi-Tenant Azure Registration
The core concept we are exploring is registering a single Multi-Tenant Application in our own Azure (Entra ID) tenant. We would configure this app to allow accounts from “Any organizational directory (Any Microsoft Entra ID tenant).”
This effectively shifts the experience from “Configuration” to “Consent.” A customer admin would simply click to consent to our app, instantly enabling login for their entire organization.
How We Plan to Bridge This with Cognito
Since this approach bypasses the standard Cognito SAML federation (which relies on 1-to-1 mapping), our research points toward using Cognito Custom Authentication Challenges to handle the logic.
The Design:
- Domain Resolution: When a user enters their email, we resolve their customer_id based on their hosted domain (e.g., @acme.com -> Tenant A).
- Microsoft OAuth Flow: Instead of a standard SAML redirect, we take the user to the Microsoft OAuth 2.0 authorization page.
- The Custom Challenge: Once Microsoft returns a successful login token, we redirect the user back to our application and initiate a custom login flow with Cognito.
- Lambda Verification:
Cognito triggers a Lambda function.
This function validates the Microsoft token signature.
Authorization Check: Crucially, the Lambda will check if this Microsoft user is authorized to access the resolved customer_id (using custom attributes or a database lookup).
- Access Granted: If the checks pass, Cognito issues the standard tokens, and the user is in.
Conclusion
Authentication is rarely “set and forget.” While our current SAML-based approach offers robust security and isolation, our research into multi-tenant Azure apps suggests a path toward a much smoother customer experience. By leveraging Cognito’s Custom Auth triggers, we hope to soon offer an onboarding process that is as simple as a single click.


