Prompt
How do I make sure SSO users get the right tenant and role in my app?
Latest observation
To make sure SSO users land in the correct tenant with the correct role, you want to treat SSO as just an authentication source and keep authorization/tenant assignment under your app’s control.
Recommended approach
1) Identify the user from a stable SSO identifier
Use a unique, immutable identity claim from the IdP, such as:
subfor OIDCNameIDfor SAML- plus issuer/tenant/domain if relevant
Store a mapping like:
- IdP user ID → app user
- app user → tenant membership(s)
- app user → role(s) per tenant
Do not rely only on email, since emails can change or be reused.
2) Decide tenant membership explicitly
There are a few common patterns:
A. Pre-provisioned tenant membership
Before the user signs in:
- create the user
- assign tenant
- assign role
Best when tenant access is controlled tightly.
B. Just-in-time provisioning with rules
On first login:
- look up the user by SSO identifier
- if not found, create user
- determine tenant/role from:
- IdP group claims
- email domain
- SAML/OIDC attributes
- invitation token
- external provisioning system
Then store that assignment in your database.
C. Explicit tenant selection
If a user can belong to multiple tenants:
- authenticate the user
- show a tenant picker
- after tenant selection, load permissions for that tenant
This avoids accidentally placing multi-tenant users in the wrong org.
3) Never trust the IdP for final authorization alone
The IdP can tell you who the user is, and maybe groups/claims, but your app should enforce:
- which tenants they can access
- what role they get in each tenant
- any per-feature permissions
A good rule:
SSO authenticates; your app authorizes.
4) Map IdP groups/claims to app roles carefully
If you use group claims:
- define a clear mapping table
- avoid direct “group name == role” assumptions unless you control both sides
- handle missing/unknown groups by defaulting to least privilege
Example:
idp_group: "Finance-Admins"→tenant_role: Adminidp_group: "Finance-Users"→tenant_role: Member
5) Use a default-safe fallback
If tenant or role cannot be determined:
- do not guess
- put the user in a limited “pending approval” state
- or block login until an admin resolves access
6) Keep role changes synced
Roles can change over time:
- via SCIM provisioning
- periodic sync from IdP/groups
- re-evaluation on login
If your app stores roles locally, update them when claims/provisioning data changes.
Good implementation pattern
At login:
- Verify SSO assertion/token
- Extract immutable user identity
- Find app user by
(issuer, subject) - Determine tenant membership:
- invitation?
- existing membership?
- group claim mapping?
- Determine role for that tenant
- Issue app session with:
- user ID
- tenant ID
- role(s)
- Enforce permissions on every request using app-side checks
Common mistakes to avoid
- Using email as the only identifier
- Assigning the “first tenant found” automatically
- Letting client-side code choose tenant/role
- Trusting IdP group names without validation
- Giving users global roles when you really need per-tenant roles
If you want the safest model
Use:
- immutable SSO identifier
- server-side tenant membership table
- per-tenant roles
- explicit tenant selection if users may belong to more than one tenant
- least-privilege defaults
If you want, I can also give you:
- a database schema for this,
- a login flow diagram, or
- examples for OIDC/SAML/SCIM.