@supertokens-plugins/tenant-discovery-nodejs
v0.2.1
Published
Tenant Discovery Plugin for SuperTokens
Readme
SuperTokens Plugin Tenant Discovery
Automatically discover and route users to appropriate tenants based on their email domains. This plugin provides endpoints to infer tenant IDs from email domains.
Installation
npm install @supertokens-plugins/tenant-discovery-nodejsQuick Start
Backend Configuration
Initialize the plugin in your SuperTokens backend configuration:
import SuperTokens from "supertokens-node";
import TenantDiscoveryPlugin from "@supertokens-plugins/tenant-discovery-nodejs";
SuperTokens.init({
appInfo: {
// your app info
},
recipeList: [
// your other recipes
],
experimental: {
plugins: [
TenantDiscoveryPlugin.init({
enableTenantListAPI: false,
}),
],
}
});API Endpoints
The plugin automatically creates these endpoints:
Get Tenant from Email
- POST
/plugin/supertokens-plugin-tenant-discovery/from-email - Body:
{ "email": "[email protected]" } - Response:
{ "status": "OK", "tenant": "company1" }
Block emails from tenant
The default fallback for getting the tenant ID from the email is "public". If this doesn't work in your use-case, we provide a function that can be overridden to avoid this.
You can avoid redirecting users to the public tenant by overriding the isTenantAllowedForEmail function like this:
import SuperTokens from "supertokens-node";
import TenantDiscoveryPlugin from "@supertokens-plugins/tenant-discovery-nodejs";
SuperTokens.init({
appInfo: {
// your app info
},
recipeList: [
// your other recipes
],
plugins: [
TenantDiscoveryPlugin.init({
enableTenantListAPI: false,
override: (originalImplementation) => ({
...originalImplementation,
isTenantAllowedForEmail: (email: string, tenantId: string) => {
// Check whether the email can access the tenant
return tenantId !== "public;
},
}),
}),
],
});List All Tenants
[!IMPORTANT]
This is disabled by default. TheenableTenantListAPIfield in config has to be set totruein order to enable it.
- GET
/plugin/supertokens-plugin-tenant-discovery/list - Response:
{ "status": "OK", "tenants": [ { "tenantId": "public", "displayName": "public" }, { "tenantId": "tenant1", "displayName": "tenant1" } ] }
Configuration Options
| Option | Type | Default | Description |
| --------------------- | --------- | ------- | ----------------------------------------------------- |
| enableTenantListAPI | boolean | false | Whether to show tenant selector (enable API's or not) |
How It Works
Email Domain to Tenant ID Inference
- The plugin extracts the domain from user email addresses (e.g.,
[email protected]→company.com) - It then extracts the tenant ID from the domain by taking the second-to-last part (e.g.,
company.com→companyortest.company.com->company) - For domains with only one part, it uses the entire domain as tenant ID
- If the inferred tenant doesn't exist in your SuperTokens setup, it falls back to the
publictenant
Domain Restrictions
- Popular email domains (Gmail, Yahoo, Outlook, etc.) are automatically blocked from tenant inference
- Restricted domains automatically return
publicas the tenant ID - This prevents assignment of public email users to inferred tenant IDs
Tenant Validation
- The plugin validates if the inferred tenant ID actually exists in your SuperTokens configuration
- If the inferred tenant exists, it's returned as the final tenant
- If the inferred tenant doesn't exist,
publicis returned as the fallback
Ways to Use Tenant Discovery
Frontend plugin
You can use the @supertokens-plugins/tenant-discovery-react plugin on the frontend to automatically integrate with this plugin
Frontend Integration
If you are using a custom UI or want to avoid using the above mentioned plugin:
Plugin APIs
Use the plugin's API endpoints from your frontend to determine which tenant a user belongs to:
// Discover tenant from email during sign-up/sign-in
const discoverTenant = async (email: string) => {
const response = await fetch("/plugin/supertokens-plugin-tenant-discovery/from-email", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ email }),
});
const result = await response.json();
if (result.status === "OK") {
// Use the validated tenant ID
console.log(`Final tenant: ${result.tenant}`);
// Redirect user to tenant-specific sign-in page
window.location.href = `/auth?tenantId=${result.tenant}`;
}
};
// Get list of all available tenants
const getTenants = async () => {
const response = await fetch("/plugin/supertokens-plugin-tenant-discovery/list");
const result = await response.json();
return result.tenants;
};Multi-Step Authentication Flow
- User enters email on landing page
- Call
/from-emailendpoint to infer and validate tenant - Use the returned
tenantfield for routing (validated tenant) - Redirect user to tenant-specific authentication flow
- User completes sign-up/sign-in in correct tenant context
API Integration
// Example: Email-based tenant discovery during user onboarding
const handleEmailSubmit = async (email: string) => {
try {
const response = await fetch("/plugin/supertokens-plugin-tenant-discovery/from-email", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ email }),
});
const result = await response.json();
if (result.status === "OK") {
// Proceed with authentication in validated tenant
console.log(`User ${email} belongs to tenant: ${result.tenant}`);
// Initialize SuperTokens with validated tenant
initAuthWithTenant(result.tenant);
}
} catch (error) {
console.error("Tenant discovery failed:", error);
// Fallback to public tenant
initAuthWithTenant("public");
}
};Error Handling
The plugin returns standardized error responses:
// Missing email
{
"status": "ERROR",
"message": "Email is required"
}
// Restricted domain (returns public)
{
"status": "OK",
"tenant": "public", // Restricted domain fallback
"email": "[email protected]"
}
// Invalid tenant (inferred tenant doesn't exist)
{
"status": "OK",
"tenant": "public", // Fallback when inferred tenant doesn't exist
"email": "[email protected]"
}Domain Restrictions
The plugin automatically blocks these popular email domains from tenant inference:
- gmail.com, yahoo.com, hotmail.com, outlook.com
- icloud.com, aol.com, live.com, msn.com
- And other popular domains
You can add custom restrictions:
TenantDiscoveryPlugin.init({
override: (originalImplementation) => ({
...originalImplementation,
isRestrictedEmailDomain: (emailDomain: string) => {
return originalImplementation.isRestrictedEmailDomain(emailDomain) || emailDomain === "example.com"
},
}),
});Examples of tenant inference:
[email protected]→ inferscompany(if company tenant exists)[email protected]→ infersenterprise(if enterprise tenant exists)[email protected]→ inferscompany(takes second-to-last part)[email protected]→ returnspublic(restricted domain)[email protected]→ infersnonexistentbut returnspublic(tenant doesn't exist)
Requirements
- SuperTokens Node.js SDK >= 23.0.0
- Multi-tenancy must be properly configured in your SuperTokens setup
