Skip to main content
Which frontend SDK do you use?
supertokens-web-js / mobile
supertokens-auth-react
Paid Feature

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

Example 2: Tenants use their sub domain to login

In this UX flow, all tenants login using their assigned sub domain (customer1.example.com, customer2.example.com and so on). The login method that's shown on the login page on each sub domain depends on that tenant's tenantId configuration.

important

Throughout this page, we will assume that the tenant ID for a tenant is equal to their sub domain - so if the sub domain assigned to a tenant is customer1.example.com, then their tenantId is customer1.

Step 1: Creating a new tenant#

Whenever you want to onboard a new customer, you should create and configure a tenantId for them in the SuperTokens core.

Step 2: Change CORS setting and websiteDomain#

CORS setup#

  • In order for the browser to be able to make requests to the backend, the CORS setting on the backend needs to reflect the right set of allowed origins. For example, if you have customer1.example.com on the frontend, then the CORS setting on the backend should allow customer1.example.com as an allowed origin. You can specifically whitelist the set of frontend sub domains on the backend, or you can use a regex like *.example.com.

websiteDomain setup#

  • On the frontend, set the websiteDomain to window.location.origin
  • On the backend, you should set the websiteDomain to be your main domain (example.com if your sub domains are sub.example.com), and then you want to override the sendEmail functions to change the domain of the link dynamically based on the request's origin. See the Email Delivery section in our docs for how to override the sendEmail function.

Step 3: Load login methods dynamically on the frontend based on the tenantId#

Modify the SuperTokens.init to do the following:

  1. Set the usesDynamicLoginMethods to true. This will tell our frontend SDK that the login page is based on the tenantId and to fetch the tenant config from the backend before showing any login UI.
  2. Initialize the Multitenancy recipe and provide getTenantId config function.
import React from 'react';

import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react";
import ThirdParty from "supertokens-auth-react/recipe/thirdparty";
import Session from "supertokens-auth-react/recipe/session";
import Multitenancy from "supertokens-auth-react/recipe/multitenancy";

SuperTokens.init({
appInfo: {
appName: "<YOUR_APP_NAME>",
apiDomain: "<YOUR_API_DOMAIN>",
websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
apiBasePath: "/auth",
websiteBasePath: "/auth"
},
usesDynamicLoginMethods: true,
recipeList: [
ThirdParty.init(),
Session.init(),
Multitenancy.init({
getTenantId: async () => {
// We treat the sub domain as the tenant ID
return window.location.host.split('.')[0]
}
})
]
});

Step 4: Tell SuperTokens about tenant's sub domains#

We want to restrict users to only be able to access their (sub)domains. SuperTokens makes it easy for you to do this. We start by telling SuperTokens which domain each tenantId has access to:

TODO

The config above will tell SuperTokens to add the list of domains returned by you into the user's session claims once they login. This claim can then be read on the frontend and backend to restrict user's access to the right domain(s).

Step 5: Sharing sessions across sub domains#

You may want to allow the user's session to be shearable across sub domains. This would lead to a better UX in which even if they visit the main domain (logged in via a.example.com, and visit example.com), the frontend app there can detect if the user has a session or not.

This can be achieved by setting the sessionTokenFrontendDomain value in the Session recipe.

If the sub domain and the main website domain have different backends (on different sub domains), then you can also enable sharing of sessions across API domains.

note

This is not a security issue because we will anyway be restricting access to users based on their domain allow list as shown below.

Step 6: Limiting the user's access to their sub domain.#

We will be using session claim validators on the frontend and backend to restrict sub domain access.

Restrict API access#

Let's take an example here. We have a tenantId: tId1 which has access to example.com, tId1.example.com (where their UI is shown), and to api.tId1.example.com (API layer that is allowed to be queried only by tId1.examlpe.com).

First, make sure that all these domains are returned from the GetAllowedDomainsForTenantId:

TODO

This will add all the returned domains to that tenant's session. Then, we can add the following global claim validator on the backend to restrict it so that only tenants with api.tId1.example.com allowed domain can query that backend

TODO
  • This will make sure that whenever you call the verifySession or getSession functions, SuperTokens will check that the tenant has access to api.tId1.example.com (which should be the current API layer's code).
  • In case you do not want to apply this check to all APIs, you can add this claim validator on a per API level as well.

Restrict frontend access#

On the frontend, we want to check if the tenant has access to the current sub domain. If not, we want to redirect them to the right sub domain. This can be done by using the hasAccessToCurrentDomain session validator from the multi tenancy recipe:

import React from "react";
import { SessionAuth, useSessionContext } from 'supertokens-auth-react/recipe/session';
import { MultitenancyClaim } from 'supertokens-auth-react/recipe/multitenancy';

const ProtectedRoute = (props: React.PropsWithChildren<any>) => {
return (
<SessionAuth
overrideGlobalClaimValidators={(globalValidators) =>
[...globalValidators,
MultitenancyClaim.validators.hasAccessToCurrentDomain()
]
}
>
<InvalidClaimHandler>
{props.children}
</InvalidClaimHandler>
</SessionAuth>
);
}

function InvalidClaimHandler(props: React.PropsWithChildren<any>) {
let sessionContext = useSessionContext();
if (sessionContext.loading) {
return null;
}

if (sessionContext.invalidClaims.some(i => i.validatorId === MultitenancyClaim.id)) {
return <div>You cannot access this page.</div>
}

return <div>{props.children}</div>;
}

Above we are creating a generic component called ProtectedRoute which enforces that its child components can only be rendered if the user is on the right sub domain based on the Multi tenancy claim.