Introduction
What is Multitenancy?
Multitenancy is an architectural pattern where a single instance of software serves multiple customers (tenants). Each tenant's data and configuration remain isolated from others, creating the illusion of having their own dedicated system. For SaaS applications, multitenancy is essential for scalability, cost-efficiency, and maintaining separate customer environments.
The Challenge
When building modern SaaS applications, you often face complex authentication requirements:
- Tenant Isolation: Different organizations need separate user pools and authentication policies
- Flexible Authentication: Each organization may require different login methods (social, enterprise SSO, username/password)
- Branding: Organizations want customized login experiences reflecting their brand
- Security: Strict isolation between tenants to prevent data leakage
- Scalability: Managing hundreds or thousands of organizations without infrastructure overhead
Why Auth0 Organizations?
Auth0 Organizations provide a native solution for multitenancy within a single Auth0 tenant. Instead of creating multiple Auth0 tenants (expensive and hard to manage) or building custom isolation logic, Organizations offer:
- Built-in tenant isolation with proper security boundaries
- Flexible connection management per organization
- Simplified user management with organization membership
- Customizable branding for each organization
- Single infrastructure to manage, reducing operational complexity
Architecture Overview
Auth0 Organizations create logical groupings within your Auth0 tenant. Each organization acts as an isolated container for users and authentication methods, while sharing the underlying Auth0 infrastructure.
High-Level Architecture
Key Components
- Auth0 Tenant: Your main Auth0 account
- Organizations: Logical containers representing each customer/tenant
- Connections: Authentication methods (database, social, enterprise) available to organizations
- Users: Individuals who belong to one or more organizations
- Applications: Your SaaS app(s) that authenticate users
Benefits Over Alternative Approaches
| Approach | Pros | Cons |
|---|---|---|
| Multiple Auth0 Tenants | Complete isolation | Expensive, complex management, no shared infrastructure |
| Single Tenant + Custom Logic | Full control | Security risks, maintenance burden, reinventing the wheel |
| Auth0 Organizations | Native isolation, scalable, flexible, cost-effective | Requires proper implementation, learning curve |
Implementation Steps
Step 1: Creating Machine-to-Machine (M2M) Application
Machine-to-Machine applications enable your backend services to interact with Auth0 Management API programmatically. This is essential for automating organization creation, user management, and configuration.
What are M2M Applications?
M2M applications use the OAuth 2.0 Client Credentials flow to obtain access tokens without user interaction. They authenticate using a Client ID and Client Secret, making them perfect for server-to-server communication.
Creating an M2M Application
Via Auth0 Dashboard:
- Navigate to Auth0 Dashboard → Applications → Applications
- Click Create Application
- Enter application name (e.g., "Organization Management Service")
- Select Machine to Machine Applications
- Choose the Auth0 Management API as the authorized API
- Select required scopes:
read:organizationscreate:organizationsupdate:organizationsdelete:organizationsread:organization_memberscreate:organization_membersread:organization_connectionscreate:organization_connectionsupdate:organization_connectionsread:connections
- Click Authorize
Obtaining Credentials:
After creation, navigate to the application's Settings tab to find:
- Client ID: Public identifier for your M2M application
- Client Secret: Secret key (keep this secure!)
-
Domain: Your Auth0 domain (e.g.,
your-tenant.auth0.com)
M2M Authentication Flow
sequenceDiagram
participant App as Your Backend Service
participant Auth0 as Auth0 Token Endpoint
participant API as Auth0 Management API
App->>Auth0: POST /oauth/token<br/>(client_id, client_secret, audience)
Auth0->>Auth0: Validate credentials
Auth0-->>App: Access Token (JWT)
App->>API: API Request<br/>(Authorization: Bearer {token})
API->>API: Validate token
API-->>App: API Response
Example: Authenticating with M2M Credentials
Python:
import requests
import os
def get_management_api_token():
"""
Obtain an access token for Auth0 Management API
"""
auth0_domain = os.getenv('AUTH0_DOMAIN')
client_id = os.getenv('AUTH0_M2M_CLIENT_ID')
client_secret = os.getenv('AUTH0_M2M_CLIENT_SECRET')
token_url = f'https://{auth0_domain}/oauth/token'
payload = {
'client_id': client_id,
'client_secret': client_secret,
'audience': f'https://{auth0_domain}/api/v2/',
'grant_type': 'client_credentials'
}
response = requests.post(token_url, json=payload)
response.raise_for_status()
return response.json()['access_token']
# Usage
token = get_management_api_token()
print(f"Access token obtained: {token[:20]}...")
Step 2: Creating Organizations and Linking Login Methods
Organizations are the core entities that represent your tenants. Each organization can have its own set of enabled authentication connections, branding, and metadata.
Understanding Auth0 Organizations
An organization in Auth0 represents a group of users who share common access to applications. Key properties include:
-
Organization ID: Unique identifier (e.g.,
org_abc123xyz) - Display Name: Human-readable name shown to users
- Enabled Connections: Authentication methods available for this organization
- Metadata: Custom key-value pairs for your application logic
- Branding: Colors, logos, and styling for login pages
Creating Organizations
Via Auth0 Dashboard (Manual):
- Navigate to Organizations in the Auth0 Dashboard
- Click Create Organization
- Enter Organization Name and Display Name
- (Optional) Add metadata
- Click Create
Via Management API (Programmatic):
import requests
def create_organization(token, name, display_name, metadata=None):
"""
Create a new organization in Auth0
"""
auth0_domain = os.getenv('AUTH0_DOMAIN')
url = f'https://{auth0_domain}/api/v2/organizations'
headers = {
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
}
payload = {
'name': name, # Must be unique, URL-friendly
'display_name': display_name,
'metadata': metadata or {}
}
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
org = response.json()
print(f"Organization created: {org['id']}")
return org
# Usage
token = get_management_api_token()
org = create_organization(
token,
name='acme-corp',
display_name='Acme Corporation',
metadata={
'plan': 'enterprise',
'industry': 'technology'
}
)
Linking Authentication Connections
Connections define how users authenticate. Auth0 supports:
- Database Connections: Username/password authentication
- Social Connections: Google, Microsoft, Facebook, LinkedIn, etc.
- Enterprise Connections: SAML, OIDC, ADFS, Azure AD, etc.
Enabling Connections for an Organization:
def enable_connection_for_org(token, org_id, connection_id, assign_membership_on_login=True):
"""
Enable an authentication connection for an organization
"""
auth0_domain = os.getenv('AUTH0_DOMAIN')
url = f'https://{auth0_domain}/api/v2/organizations/{org_id}/enabled_connections'
headers = {
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
}
payload = {
'connection_id': connection_id,
'assign_membership_on_login': assign_membership_on_login
}
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
return response.json()
# Enable Google Social connection
enable_connection_for_org(token, 'org_abc123xyz', 'con_google123')
# Enable Database connection
enable_connection_for_org(token, 'org_abc123xyz', 'con_database456')
Getting Available Connections:
def get_connections(token):
"""
Retrieve all available connections
"""
auth0_domain = os.getenv('AUTH0_DOMAIN')
url = f'https://{auth0_domain}/api/v2/connections'
headers = {
'Authorization': f'Bearer {token}'
}
response = requests.get(url, headers=headers)
response.raise_for_status()
connections = response.json()
for conn in connections:
print(f"Connection: {conn['name']} (ID: {conn['id']}, Strategy: {conn['strategy']})")
return connections
Step 3: User Authentication with Organization Context
The final step is directing users to authenticate within the context of their organization. This ensures they only see login methods available to their organization and that tokens include organization information.
The /authorize Endpoint
Auth0's /authorize endpoint initiates the authentication flow. When you include the organization parameter, Auth0:
- Filters available login methods to only those enabled for that organization
- Includes organization claims in the returned tokens
- Applies organization-specific branding (if configured)
Building the Authentication URL
Required Parameters:
-
organization: The organization ID (e.g.,org_abc123xyz) -
client_id: Your application's Client ID -
redirect_uri: Where Auth0 redirects after authentication -
response_type: Typicallycodefor authorization code flow -
scope: Requested scopes (e.g.,openid profile email)
Example Authentication URL:
https://your-tenant.auth0.com/authorize
?organization=org_abc123xyz
&client_id=your_app_client_id
&redirect_uri=https://yourapp.com/callback
&response_type=code
&scope=openid profile email
&state=random_state_value
Complete Authentication Flow
Implementation Example
Python (Flask):
from flask import Flask, redirect, request, session, url_for
from authlib.integrations.flask_client import OAuth
import os
app = Flask(__name__)
app.secret_key = os.getenv('FLASK_SECRET_KEY')
oauth = OAuth(app)
auth0 = oauth.register(
'auth0',
client_id=os.getenv('AUTH0_CLIENT_ID'),
client_secret=os.getenv('AUTH0_CLIENT_SECRET'),
api_base_url=f'https://{os.getenv("AUTH0_DOMAIN")}',
access_token_url=f'https://{os.getenv("AUTH0_DOMAIN")}/oauth/token',
authorize_url=f'https://{os.getenv("AUTH0_DOMAIN")}/authorize',
client_kwargs={'scope': 'openid profile email'}
)
@app.route('/login/<org_id>')
def login(org_id):
"""
Initiate login for a specific organization
"""
# Store org_id in session for validation later
session['expected_org_id'] = org_id
return auth0.authorize_redirect(
redirect_uri=url_for('callback', _external=True),
organization=org_id
)
@app.route('/callback')
def callback():
"""
Handle the Auth0 callback
"""
# Exchange authorization code for tokens
token = auth0.authorize_access_token()
# Get user info from ID token
user_info = token.get('userinfo')
# Validate organization
org_id = user_info.get('org_id')
expected_org_id = session.get('expected_org_id')
if org_id != expected_org_id:
return "Organization mismatch!", 403
# Store user session
session['user'] = {
'email': user_info.get('email'),
'name': user_info.get('name'),
'org_id': org_id
}
return redirect('/dashboard')
@app.route('/dashboard')
def dashboard():
"""
Protected route - requires authentication
"""
if 'user' not in session:
return redirect(url_for('login', org_id='default'))
user = session['user']
return f"Welcome {user['name']} from organization {user['org_id']}!"
Extracting Organization Information from Tokens
After successful authentication, the ID token will contain organization claims:
{
"sub": "auth0|123456789",
"email": "user@example.com",
"name": "John Doe",
"org_id": "org_abc123xyz",
"org_name": "Acme Corporation",
"iat": 1635360000,
"exp": 1635363600
}
Token Validation:
import jwt
from jwt import PyJWKClient
def validate_token(token, expected_org_id):
"""
Validate JWT token and verify organization claim
"""
auth0_domain = os.getenv('AUTH0_DOMAIN')
jwks_url = f'https://{auth0_domain}/.well-known/jwks.json'
# Get signing key
jwks_client = PyJWKClient(jwks_url)
signing_key = jwks_client.get_signing_key_from_jwt(token)
# Decode and verify token
payload = jwt.decode(
token,
signing_key.key,
algorithms=['RS256'],
audience=os.getenv('AUTH0_CLIENT_ID'),
issuer=f'https://{auth0_domain}/'
)
# Verify organization claim
if payload.get('org_id') != expected_org_id:
raise ValueError('Organization ID mismatch')
return payload
Additional Resources
- Auth0 Documentation: https://auth0.com/docs/manage-users/organizations
- Management API Reference: https://auth0.com/docs/api/management/v2/organizations
- Auth0 Community: https://community.auth0.com
- GitHub Examples: Search for "auth0-organizations" for community examples
Questions or need help? Join the Auth0 community forums or reach out to Auth0 support. Share your implementation experiences and help others building multitenant applications!




Top comments (0)