Skip to main content
Paid Feature

This is a paid feature. Email us to get a license key to start a SuperTokens subscription.

If you want to try this feature without contacting us, you can sign up for our managed service, and use this feature in our development environment for free.

Creating and configuring a tenant

Step 1: Create a tenant and enable passwordless login for them#

The first step in setting up a multi tenant login system is to create a tenant in the SuperTokens core. Each tenant has a unique tenantId (a string data type) mapped to that tenant's configuation. The tenantId could be that tenant's sub domain, or a workspace URL, or anything else using which you can uniquely identify them.

The configuration mapped to each tenant contains information about which login methods are enabled for them. You can create a tenant via our backend SDK or via a cURL command to the core. This also allows you to dynamically create tenants without manual intervention:

import Multitenancy from "supertokens-node/recipe/multitenancy";

async function createNewTenant() {

let resp = await Multitenancy.createOrUpdateTenant("customer1", {
passwordlessEnabled: true,
});

if (resp.createdNew) {
// new tenant was created
} else {
// existing tenant's config was modified.
}
}
Next steps

You have now successfully configured a new tenant in SuperTokens. The next step is to wire up the frontend SDK to show the right login UI for this tenant. The specifics of this step depend on the UX that you want to provide to your users, but we have two common UX flows documented in the next section.

Providing additional configuration per tenant#

You can also configure a tenant to have different configurations as per the core's config.yaml (or docker env) variabls. Below is how you can specify the config, when creating or modifying a tenant:

import Multitenancy from "supertokens-node/recipe/multitenancy";

async function createNewTenant() {

let resp = await Multitenancy.createOrUpdateTenant("customer1", {
coreConfig: {
"email_verification_token_lifetime": 7200000,
"password_reset_token_lifetime": 3600000,
"postgresql_connection_uri": "postgresql://localhost:5432/db2",
}
});

if (resp.createdNew) {
// new tenant was created
} else {
// existing tenant's config was modified.
}
}

In the above example, we are setting different values for certain configs for customer1 tenant. All other configs are inherited from the base config (config.yaml file or docker env vars).

We even specify a postgresql_connection_uri config. This means that all the information related to this tenant (users, roles, metadata etc) will be saved in the db pointed to by the value of postgresql_connection_uri (A similar config exists for MySQL as well). This can be used to achieve data isolation on a tenant level. This config is not necessary and if not provided, the tenant's information will be stored in the db as specified in the core's config.yaml or docker env vars (it will still be a different user pool though).

Here is the list of full core config variables that can be configured, and below are the lists of variables depending on the database you use:

important

Some configs cannot be different across tenants - they must be the same within an app. In the above links, if a config has a comment saying DIFFERENT_ACROSS_TENANTS, then it can be changed for each tenant, else if it has DIFFERENT_ACROSS_APPS, then it must be the same for all tenants within an app.

If a config has neither of these, then it can only be set per core instance.

Once you have set the configs for a specific tenant, you can fetch the tenant info as shown below:

import Multitenancy from "supertokens-node/recipe/multitenancy";

async function getTenant(tenantId: string) {

let resp = await Multitenancy.getTenant(tenantId);

if (resp === undefined) {
// tenant does not exist
} else {
let coreConfig = resp.coreConfig;

let isEmailPasswordLoginEnabled = resp.emailPassword.enabled;
let isThirdPartyLoginEnabled = resp.thirdParty.enabled;
let isPasswordlessLoginEnabled = resp.passwordless.enabled;

let configuredThirdPartyProviders = resp.thirdParty.providers;
}
}

The returned coreConfig is the same as what we had set when creating / updating the tenant. The rest of the core configurations for this tenant are inherited from the app's (or the public tenant) config. The public tenant, for the public app inherits its configs from the config.yaml / docker env var values.