SSO SAML Multi-Tenant Auth0 Organization Context on Universal Login

Hi @tfu

Welcome to the Auth0 Community!

You are building a multi-tenant SaaS application using Auth0 Organizations, where each client has one organization with multiple tenant organizations underneath. You want to use SAML SSO for each client, and you need Auth0 to automatically add users to the correct organization on their first SAML login — without requiring an explicit organization parameter in the login context.

I would recommend reading our documentation on multi-tenant application best practices and multiple organization architecture before moving forward

Auth0 does not natively support automatic organization assignment based on SAML connection alone. However, you can achieve this using a combination of SAML attribute mapping and Post-Login Actions. The key limitation is that IdP-initiated SAML flows do not support organization context — you must use Service Provider (SP) initiated flows or implement a workaround.

[Root Cause]

Auth0's organization system requires explicit organization context during authentication. The organization parameter must be passed in the /authorize request, but:

  1. SAML connections are not bound to organizations — A SAML connection can be used by multiple organizations or clients. Auth0 does not automatically infer which organization a user belongs to based on the connection alone.
  2. IdP-initiated SAML does not support organization context — When the IdP initiates the login (user clicks "Login" on the IdP side), Auth0 cannot receive the organization parameter. This is a known limitation.
  3. SAML attribute mapping only maps to user profile attributes — You can map SAML attributes (like email, name, groups) to Auth0 user profile fields, but not directly to organizations.
  4. Multiple SAML connections per tenant — If you have one SAML connection per client, Auth0 still needs to know which organization to add the user to. The connection name alone is not sufficient.

[Solution]

Step 1: Configure SAML connections per client (one per organization)

Navigate to Auth0 Dashboard → Connections → Enterprise → SAML.

For each client, create a SAML connection with:

  • Connection Name: saml-client-a, saml-client-b, etc. (use a naming convention that maps to your organization)
  • Sign in URL: Your client's IdP sign-in URL
  • Certificate: Your client's IdP certificate
  • User ID Attribute: The SAML attribute that uniquely identifies users (e.g., http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier)

Enable this connection for your application.

Step 2: Map SAML attributes to Auth0 user profile

In the SAML connection settings, configure Mappings to extract user information from the SAML assertion:

{
  "email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
  "name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
  "given_name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname",
  "family_name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname",
  "groups": "http://schemas.xmlsoap.org/claims/Group"
}

This ensures user profile data is populated correctly on first login.

Step 3: Create a Post-Login Action to auto-assign users to organizations

This is the key step. Use a Post-Login Action to detect which organization the user should belong to based on the SAML connection they used:

Navigate to Auth0 Dashboard → Actions → Library → Create Action.

Use this code as a template:

const { ManagementClient } = require('auth0');

exports.onExecutePostLogin = async (event, api) => {
  // 1. Only run on first login
  if (event.stats.logins_count !== 1) {
    return;
  }

  // 2. Check if user authenticated via SAML
  const samlConnection = event.connection;
  if (!samlConnection || !samlConnection.startsWith('saml-')) {
    return; // Not a SAML login
  }

  // 3. Map SAML connection name to organization ID
  const connectionToOrgMapping = {
    'saml-client-a': 'org_xxxxA',  // Replace with actual org IDs
    'saml-client-b': 'org_xxxxB',
    'saml-client-c': 'org_xxxxC'
  };

  const orgId = connectionToOrgMapping[samlConnection];
  if (!orgId) {
    console.log(`No organization mapping found for connection: ${samlConnection}`);
    return;
  }

  // 4. Use Management API to add user to organization
  const managementApi = new ManagementClient({
    domain: event.secrets.DOMAIN,
    clientId: event.secrets.CLIENT_ID,
    clientSecret: event.secrets.CLIENT_SECRET,
  });

  try {
    await managementApi.organizations.addMembers(orgId, {
      members: [event.user.user_id]
    });
    console.log(`User ${event.user.user_id} added to organization ${orgId}`);
    
    // 5. Add org_id to tokens for immediate use
    api.idToken.setCustomClaim('org_id', orgId);
    api.accessToken.setCustomClaim('org_id', orgId);
  } catch (err) {
    console.error(`Error adding user to organization: ${err}`);
  }
};

Attach this Action to the Post-Login flow.

Step 4: Pass the organization parameter in SP-initiated flows

For Service Provider-initiated flows (user clicks "Login" on your app), pass the organization in the authorization URL:

https://YOUR_DOMAIN/authorize?
  response_type=code&
  client_id=YOUR_CLIENT_ID&
  redirect_uri=https://yourapp.com/callback&
  scope=openid%20profile%20email&
  connection=saml-client-a&
  organization=org_xxxxA

This ensures the user is authenticated in the correct organization context from the start.

Step 5: Handle IdP-initiated flows (workaround)

IdP-initiated SAML does not natively support organization context in Auth0. To work around this:

Option A: Use a relay state parameter

Configure your IdP to include a RelayState parameter that points to your app with the organization context:

RelayState: https://yourapp.com/callback?organization=org_xxxxA

Auth0 will redirect to this URL after authentication, and your app can extract the organization parameter.

Option B: Redirect to re-authenticate with organization context

  1. User authenticates via IdP-initiated SAML (without organization context)
  2. Your app detects the user is not in an organization context
  3. Your app redirects to /authorize with the correct organization parameter
  4. User is silently authenticated (session already exists) and receives tokens with organization context

Option C: Use Home Realm Discovery (HRD)

Configure HRD on your SAML connection so that when users enter their email, Auth0 automatically routes them to the correct IdP and organization:

Navigate to Auth0 Dashboard → Connections → Enterprise → SAML → Settings.

Enable Home Realm Discovery and configure the domain-to-organization mapping.

Step 6: Verify organization membership in tokens

After login, verify that the org_id claim is present in the access token:

{
  "iss": "https://YOUR_DOMAIN/",
  "sub": "samlp|saml-client-a|user@example.com",
  "org_id": "org_xxxxA",
  "aud": ["YOUR_API"],
  "iat": 1663000000,
  "exp": 1663086400
}

Your backend API should validate this claim and use it to determine which tenant database to query.

[Recommended Architecture]

  1. One SAML connection per client — Named consistently (e.g., saml-client-{client_id})
  2. Post-Login Action for auto-provisioning — Maps connection name to organization ID
  3. SP-initiated flows for primary UX — Pass organization context in /authorize
  4. IdP-initiated flows as fallback — Use RelayState or re-authentication workaround
  5. Home Realm Discovery for email-based routing — Optional, improves UX for multi-org users

You might be interested in these similar community topics on the matter:

  1. Auth0 community: Configure Multi tenant architecture
  2. Auth0 community: IdP initiated SSO when using Organizations
  3. Auth0 community: Auto-provisioning users into correct organization based on email domain

Next steps: Start with Step 1–3 (SAML connection setup + Post-Login Action) for SP-initiated flows. If you need IdP-initiated support, implement the RelayState or re-authentication workaround in Step 5.

Kind Regards,
Nik