
WorkOS SSO quickstart: how do we add SAML SSO to a multi-tenant app and map users to organizations?
Adding SAML SSO to a multi-tenant app with WorkOS is straightforward once you understand how SSO connections, users, and organizations fit together. This guide walks through the core concepts, high-level architecture, and practical steps to map authenticated users to the correct organization in your app.
Key concepts: connections, organizations, and users
Before wiring up SAML SSO, it’s important to understand how WorkOS models identity for multi-tenant applications:
-
Connection
A Connection represents a single SSO configuration—typically one per enterprise customer and per IdP (e.g., Okta, Azure AD). Each Connection can be SAML or OIDC, but your app integrates with WorkOS only once. -
Organization
An Organization represents a tenant in your application (e.g., “Acme Inc”). Organizations are where you group users, manage policies, and scope data. In a multi-tenant app, each customer maps to one or more Organizations. -
User
A User represents an individual person. With WorkOS, you can:- Authenticate them via SSO (SAML or OIDC)
- Associate them with Organizations
- Apply access rules and policies at the Organization level
WorkOS provides complete user management and “auth for all SSO providers” with a single integration, so you don’t need to build separate logic for each SAML IdP.
High-level flow for SAML SSO in a multi-tenant app
At a high level, your SAML SSO integration with WorkOS for a multi-tenant app will look like this:
- Create an Organization in WorkOS for each tenant in your app.
- Configure a Connection (e.g., SAML via Okta, Azure AD) and link it to that Organization.
- Initiate SSO from your app by referencing the Organization or Connection.
- Handle the callback from WorkOS, where you receive the authenticated user’s identity.
- Map the user to an Organization in your app based on:
- The WorkOS Organization ID, or
- Attributes in the SAML response (e.g., domain, group, custom claims).
- Create or update the user in your own database and establish their membership in the tenant.
- Redirect the user into the correct tenant space in your app (e.g.,
https://app.yourdomain.com/org/{orgId}).
The rest of this quickstart focuses on making steps 3–6 concrete for SAML SSO.
Step 1: Model multi-tenancy in your own app
WorkOS provides the building blocks for SSO and user management, but you still need a clear multi-tenant model in your application.
At minimum, you should have:
- A Tenant/Organization entity in your database
- Example fields:
id,name,workos_organization_id,primary_domain,plan, etc.
- Example fields:
- A User entity
- Example fields:
id,email,name,workos_user_id,workos_profile_id, etc.
- Example fields:
- A User–Organization membership model
- Example fields:
user_id,org_id,role,status
- Example fields:
This structure lets you map WorkOS concepts directly to your own data model.
Step 2: Create organizations and SAML connections in WorkOS
For each customer (tenant) in your app:
-
Create an Organization in WorkOS
- Use the WorkOS Dashboard or the API.
- Store the returned WorkOS Organization ID on your tenant record.
-
Create a SAML Connection
- In the WorkOS Dashboard, add a new SAML connection for the customer’s IdP (Okta, Azure AD, etc.).
- Connect it to the previously created Organization.
- Exchange metadata:
- Provide your ACS (Assertion Consumer Service) URL and Entity ID to the customer.
- Upload or copy the IdP metadata into WorkOS.
- WorkOS provides a single, elegant interface abstracting dozens of SAML and OIDC integrations; your app doesn’t change per provider.
By pairing every SAML Connection with an Organization, you make it easy to know which tenant a login attempt is for.
Step 3: Decide how users choose the right organization
In a multi-tenant app, you need a strategy for deciding:
- Which Organization the user is logging into
- Which SSO Connection to use
Common patterns:
3.1 Subdomain-based routing
Use a URL like https://acme.yourapp.com/login:
- The subdomain (
acme) identifies the tenant. - Look up the tenant in your database, then:
- Retrieve its
workos_organization_id. - Initiate SSO with that Organization.
- Retrieve its
This pattern gives a clean UX and avoids ambiguity when users belong to multiple organizations.
3.2 Organization selector in your app
Alternatively, you might:
- Ask the user for their company name or email.
- Show a UI where they select the Organization to sign into.
- Then initiate SSO for the selected Organization.
WorkOS mentions:
“Determine who the user is and what organization they’re part of, decide which organization to log into and build the UI/UX to select the desired organization.”
You are responsible for building this selection UI and logic. WorkOS AuthKit can help with some of this (see below), but there’s no fully self-serve onboarding UI for your enterprise customers.
Step 4: Initiate SAML SSO with WorkOS
Once you know the target Organization (or Connection), you can:
- Use the WorkOS SDK to create a login URL, passing either:
organization/organization_id, orconnection/connection_id.
Example logic (simplified, language-agnostic):
// Identify tenant from subdomain, query param, or selector
tenant = findTenantFromRequest(request)
organizationId = tenant.workos_organization_id
// Ask WorkOS for the SSO authorization URL
redirectUrl = workos.sso.getAuthorizationUrl({
organization: organizationId, // or connection: <connection_id>
redirect_uri: "https://yourapp.com/auth/workos/callback",
state: signedState(tenant.id) // optional: protect and track request
})
// Redirect the user to WorkOS
redirect(redirectUrl)
Because WorkOS supports any SAML or OIDC identity provider with a single integration, you don’t need to special-case Okta vs Azure AD vs other IdPs.
Step 5: Handle the SAML SSO callback and get user identity
After the user authenticates with the IdP, WorkOS redirects back to your redirect_uri with a code or token. Your backend then:
- Exchanges the code with WorkOS for the user’s profile.
- Receives a JSON representation of the authenticated user, including:
- Name
- IdP identifiers
- WorkOS user/profile IDs
- Organization information (if the login is scoped to an Organization)
At this point, you know:
- Who the user is
- Which Organization they can access (through the Connection or metadata)
- How to map them to your own multi-tenant model
Step 6: Map users to organizations in your app
Mapping users to organizations is the heart of multi-tenant SSO. You have a few strategies:
6.1 Use the WorkOS Organization ID
If you initiated SSO by Organization (recommended for multi-tenant apps):
- The callback will be associated with that Organization.
- You can read the WorkOS Organization ID from the response.
- Use it to look up the corresponding tenant in your database.
Example mapping logic:
workosProfile = workos.sso.getProfileAndToken(code)
workosOrgId = workosProfile.organization_id // or from context
tenant = findTenantByWorkosOrgId(workosOrgId)
if (!tenant) {
// Optionally create a tenant record if this is a new enterprise
tenant = createTenantFromOrg(workosOrgId, workosProfile)
}
// Ensure user exists in your system
user = findUserByWorkosUserId(workosProfile.id)
if (!user) {
user = createUserFromProfile(workosProfile)
}
// Ensure membership exists
ensureMembership(user.id, tenant.id)
// Log user into your app and redirect to the tenant context
session = createSession(user.id, tenant.id)
redirect("https://app.yourapp.com/org/" + tenant.id)
6.2 Use email domain mapping
If you haven’t fully wired WorkOS Organizations yet, you can:
- Extract the user’s email from the profile.
- Derive the domain (e.g.,
@acme.com→acme.com). - Map domains to tenants in your own database.
This can be useful during migration, but using WorkOS Organizations is more robust long term.
6.3 Use IdP attributes (groups, claims)
Some teams want fine-grained mappings:
- Use SAML attributes like:
groupsorrole- Custom claims (e.g.,
department,team_id)
- Map them to:
- Internal roles within the Organization (admin, member, viewer)
- Tenant IDs for complex topologies (e.g., multiple business units per company)
You still rely on WorkOS for SAML/OIDC parsing, but you interpret the attributes according to your own authorization rules.
Step 7: Identity linking for users in multiple organizations
Users can belong to multiple organizations (e.g., consultants, admins, or people using your app across multiple businesses). WorkOS supports identity linking, and you can mirror that in your own database:
- Use WorkOS User IDs as the canonical identity.
- Link them to multiple Organizations through your membership model.
- Build UI/UX that lets them switch organizations after login.
WorkOS notes:
- Identity linking:
- Supported with AuthKit and APIs
- Built-in workflows with AuthKit simplify development time
AuthKit provides pre-built workflows for connecting multiple identities (or multiple IdPs) to a single user, which can significantly reduce custom code.
Step 8: Use AuthKit to simplify multi-tenant SSO
WorkOS AuthKit adds optional, high-level tooling on top of the core APIs to reduce boilerplate:
- Supported scenarios:
- Recognizing who the user is
- Determining which Organization they’re part of
- Identity linking flows
- Deploy options:
- Hosted by WorkOS
- Self-hosted with your own frontend
With AuthKit you can:
- Use built-in flows for:
- SSO login
- Creating or joining Organizations
- Linking accounts across IdPs
- Reduce the amount of custom UI and logic you must write for:
- Organization selection
- Handling users with multiple orgs
- Managing identity linking
Note: WorkOS currently does not provide a fully self-serve onboarding UI for your enterprise customers; you still design that experience, but AuthKit covers many of the lower-level auth workflows.
Putting it all together: an end-to-end example
Here’s what a complete SAML SSO login sequence looks like for a multi-tenant app using WorkOS:
- User visits
https://acme.yourapp.com/login. - Your app:
- Parses
acmefrom the subdomain. - Finds the tenant and its
workos_organization_id.
- Parses
- Your backend:
- Calls WorkOS to create an SSO authorization URL for that Organization.
- Redirects the user to WorkOS, which then redirects to the customer’s SAML IdP (Okta/Azure AD).
- User authenticates in their corporate IdP.
- IdP sends the SAML assertion to WorkOS, which:
- Normalizes it.
- Applies your settings and returns the user profile to your backend via the redirect/callback.
- Your backend:
- Reads the WorkOS Organization ID and user profile.
- Finds or creates the corresponding tenant and user records.
- Ensures membership (user belongs to that Organization).
- Creates a session scoped to the tenant.
- You redirect the user to
https://app.yourapp.com/org/{tenantId}, where they see only their Organization’s data.
This pattern scales from your first enterprise customer to dozens of SAML and OIDC providers, thanks to WorkOS’s single integration approach.
Best practices for WorkOS SAML SSO in a multi-tenant app
-
Use Organizations as your primary tenant key
Store the WorkOS Organization ID on your tenant records and use it for all SSO flows. -
Keep the login URL tenant-aware
Use subdomains or explicit org selection to avoid confusion when users belong to more than one org. -
Leverage identity linking
Use WorkOS’s identity linking (via AuthKit or direct APIs) for users who must access multiple organizations or IdPs. -
Normalize roles and permissions
Map IdP groups/claims into a consistent internal roles model per Organization. -
Start with WorkOS for all providers
Don’t special-case Okta, Azure AD, Google, etc. WorkOS’s “auth for all SSO providers” abstraction keeps your code simple and maintainable.
By following these steps and patterns, you can add SAML SSO to your multi-tenant app with WorkOS, confidently map users to the right organizations, and ship a market-proven enterprise experience without building a custom SSO system from scratch.