You are authenticated with SuperTokens! (UserId: {session.userId})
Your email retrieved from Supabase: {userEmail}
axios.create?
)
}}>
After you have signed up, you can skip over the initial wizard that generates an example application.
You already have created one by going though the quickstart guide.
Once you are on the main dashboard page, select a region that is closest to where your services are hosted.
Click **Deploy** and wait for the action to complete.
Our internal service will deploy a separate environment based on your selection.
After this process is complete, the UI will render the new list of deployments.
:::info
The initial setup flow only configures a development environment.
In order to use SuperTokens in production, you will have to create a separate deployment.
:::
### 3. Connect the Backend SDK with SuperTokens 🔌
Select the newly created deployment in order to access its details.
Copy the `Connection URI` and `API Key` values from this page and paste them in your backend code.
#### 1.2 Set up authentication routes
Create a `/auth` resource and then `/auth/{proxy+}` resources.
This will act as a catch-all for all SuperTokens auth routes.
**Enable CORS** while creating the proxy resource.
#### 1.3 Attach lambda to the `ANY` method of the proxy resource
Click on the "ANY" method and then "Integration" to configure the lambda function.
Check **Lambda proxy integration** and then select your lambda function.
:::important
Ensure that the **Lambda proxy integration** toggle is turned on.
:::
#### 1.4 Enable CORS for the proxy path
Click on the `{proxy+}` resource and then "Enable CORS" button to open the CORS configuration page.
In the CORS configuration page do the following:
- Select the 'Default 4XX' and 'Default 5XX' checkboxes under Gateway responses
- Select the 'OPTIONS' checkbox under Methods
- Add `rid,fdi-version,anti-csrf,st-auth-mode` to the existing `Access-Control-Allow-Headers`
- Set `Access-Control-Allow-Origin` to `'
#### 1.5 Deploy the API Gateway
Click the **Deploy API** button in the top right corner to deploy the API. During deployment, you'll be prompted to create a stage; for this tutorial, name the stage `dev`. After deployment, you will receive your `Invoke URL`.
:::important
Update `apiDomain`, `apiBasePath`, and `apiGatewayPath` in both Lambda configuration and your frontend config if they have changed post API Gateway configuration.
:::
### 2. Set up Lambda layer
#### 2.1 Create Lambda layer with required libraries
Click "Create Layer" button:
Give a name for your layer, upload the zip and select the runtime
Select `Custom Layer` and then select the layer we created in the first step:
:::
https://try.supertokens.com as the connection URI in the init function?
)
}} defaultAnswer="Yes">
You are authenticated with SuperTokens! (UserId: {session.userId})
Your email retrieved from Supabase: {userEmail}
You can find the [source code of this template on GitHub](https://github.com/supertokens/email-sms-templates/blob/master/email-html/password-reset.html).
To customize the template check the [email delivery](/docs/platform-configuration/email-delivery) section for more information.
---
## Embed the reset form in a page
To embed the reset form in a page you can use the next steps.
Select **Add Custom Provider** option
Fill in the details as shown below and click on **Save**
Select **Add Custom Provider** option
Fill in the details as shown below and click on **Save**
In the above example, the system assigns different values for certain configurations for `customer1` tenant.
All other configurations inherit from the base configuration.
You can edit the values by clicking on the pencil icon and then specifying a new value.
:::caution
You cannot edit database connection settings directly from the Dashboard, and you may need to use the SDK or cURL to update them.
:::
If you want to customize the user interface experience the plugin also provides other options.
#### Tenant selection interface
You can use the tenant selection interface accessible at `/tenant-discovery/select`.
This page displays all available tenants and allows users to choose their organization before proceeding with authentication.
:::info
Keep in mind that you also need to enable the `tenant list` endpoint in your backend plugin configuration.
:::
####
## Customization
### Block emails from specific tenants
You can override the default tenant assignment logic to prevent certain emails from accessing specific tenants:
```typescript
TenantDiscoveryPlugin.init({
enableTenantListAPI: false,
override: (originalImplementation) => ({
...originalImplementation,
isTenantAllowedForEmail: (email: string, tenantId: string) => {
// Prevent routing to public tenant
return tenantId !== "public";
},
}),
});
```
### Add custom domain restrictions
Extend the list of restricted domains that should always use the `public` tenant:
```typescript
TenantDiscoveryPlugin.init({
override: (originalImplementation) => ({
...originalImplementation,
isRestrictedEmailDomain: (emailDomain: string) => {
return originalImplementation.isRestrictedEmailDomain(emailDomain) ||
emailDomain === "example.com";
},
}),
});
```
### Implement a custom user interface
To create a custom tenant discovery interface, use the `usePluginContext` hook:
```typescript
function CustomTenantDiscovery() {
const { api, functions } = usePluginContext();
const [email, setEmail] = useState("");
const [tenants, setTenants] = useState([]);
const handleEmailSubmit = async () => {
const result = await api.tenantIdFromEmail(email);
if (result.status === "OK") {
functions.setTenantId(result.tenant, email, true);
}
};
const loadTenants = async () => {
const response = await api.fetchTenants();
if (response.status === "OK") {
setTenants(response.tenants);
}
};
return (
In the above example, the system assigns different values for certain configurations for `customer1` tenant.
All other configurations inherit from the base configuration.
You can edit the values by clicking on the pencil icon and then specifying a new value.
:::caution
You cannot edit database connection settings directly from the Dashboard, and you may need to use the SDK or cURL to update them.
:::
Select **Add Custom Provider** option
Fill in the details as shown below and click on **Save**
Select **Add Custom Provider** option
Fill in the details as shown below and click on **Save**
### BoxyHQ
[BoxyHQ](https://boxyhq.com/) is a commercial open-source company that has a product called "SAML Jackson" which helps integrate `SAML` providers into your application.
`SAML` Jackson is a perfect fit with SuperTokens because:
- It's an OAuth provider and a `SAML` client.
This fits with the architecture.
- For self hosted, it supports PostgreSQL and MySQL amongst [other databases](https://boxyhq.com/docs/jackson/deploy/service#database).
Self hosted SuperTokens only supports PostgreSQL as a data source.
`SAML` Jackson provides an HTTP service that you can host yourself or let BoxyHQ manage.
The HTTP service uses NodeJS, and is embeddable within your NodeJS backend.
However, because SuperTokens supports multiple backends, the focus is on deploying `SAML` Jackson as a microservice.
1. The user clicks on the login button and redirects to `SAML` Jackson's microservice at `http://localhost:5225/api/oauth/authorize`
2. `SAML` Jackson redirects the user to the `SAML` provider's login page where the user needs to enter their credentials
3. After successfully authenticating the user, the `SAML` provider redirects the user to `SAML` Jackson. Step (2) and (3) follow the `SAML` protocol.
4. `SAML` Jackson redirects the user to the frontend app on the configured callback URL. The callback URL contains the one-time use auth code.
5. SuperTokens' frontend `SDK` passes the one-time use auth code to your app's backend.
6. SuperTokens' backend `SDK` verifies the auth code by querying `SAML` Jackson. On success, `SAML` Jackson returns the end user's information and access token.
7. SuperTokens' backend `SDK` creates a new user in the core associated with the end user's email. New session tokens are also created
8. A SuperTokens' session establishes between your app's backend and frontend - logging in the user.
:::info Example App
An [example app on GitHub](https://github.com/supertokens/jackson-supertokens-express) with SuperTokens + `SAML` Jackson, for React and NodeJS express apps, is available. This uses [mocksaml.com](https://mocksaml.com/) as a `SAML` provider
:::
# Authentication - Enterprise Login - SAML - Integration guide
Source: https://supertokens.com/docs/authentication/enterprise/saml/boxy-hq-guide
## Before you start
These instructions assume that you already are familiar with **SuperTokens** and you have configured a demo application.
If you have skipped those steps page please go through the main [quickstart guide](/docs/quickstart/introduction).
## Using the SuperTokens dashboard
:::caution
This is only available with Node and Python SDKs.
:::
### 1. Generate the XML metadata file from your SAML provider
Your SAML provider allows you to download a `.xml` file that you can upload to SAML Jackson. During this process, you need to provide it:
- the SSO URL and;
- the Entity ID.
You can learn more about these in the [SAML Jackson docs](https://boxyhq.com/docs/jackson/configure-saml-idp).
In the example app, [mocksaml.com](https://mocksaml.com/) serves as a free SAML provider for testing. When you navigate to the site, you see a "Download metadata" button which you should click on to get the `.xml` file.
### 2. Start the SAML Jackson service
You can run SAML Jackson [with or without Docker](https://boxyhq.com/docs/jackson/deploy/service).
```bash
docker run \
-p 5225:5225 \
-e JACKSON_API_KEYS="secret" \
-e DB_ENGINE="sql" \
-e DB_TYPE="postgres" \
-e DB_URL="postgres://postgres:postgres@postgres:5432/postgres" \
-d boxyhq/jackson
```
This starts the SAML Jackson server on `http://localhost:5225`.
:::important
If you are using the SuperTokens managed service, Boxy HQ hosts the server for you ([contact support](mailto:support@supertokens.com) to activate your instance).
:::
### 3. Create a new tenant in SuperTokens (if not done already)
### 4. Configure the SAML provider for the tenant
To configure SAML login with SuperTokens, ensure that you use the correct provider name in the third-party configuration.
Make sure to specify provider name with one of the following:
- Microsoft Entra ID
This flow is best suited for scenarios that involve **web applications**.
It consists of the following steps:
1. The **Client** redirects the **Resource Owner** to the **Authorization Server’s** authorization endpoint.
2. If the **Resource Owner** grants permission, the **Authorization Server** redirects their browser back to the specified **Redirect URI** and includes an **Authorization Code** as a query parameter.
3. The **Client** then sends a request to the **Authorization Server**’s token endpoint, including the **Authorization Code**.
4. The **Authorization Server** verifies the information sent by the **Client** and, if valid, issues an **OAuth2 Access Token**.
5. The token can make requests to the **Resource Server** to access the protected resources on behalf of the **Resource Owner**.
##### Authorization code
An **Authorization Code** is a short-lived code that the [**Authorization Server**](#authorization-server) provides to the [**Client**](#client), via a **Redirect URI**, after authorization approval.
This code then gets exchanged for an [**OAuth2 Access Token**](#oauth2-access-token).
The **Authorization Code** flow enhances security by keeping tokens out of the user-agent and letting the [**Client**](#client) manage the backend communication with the [**Authorization Server**](#authorization-server).
##### Proof key for code exchange (PKCE)
To prevent cross-site request forgery (CSRF) and code injection attacks, the **Authorization Code flow** can use [**PKCE**](https://oauth.net/2/pkce/).
At the beginning of the authentication flow the **Client** generates a random string called a *code verifier*.
This ensures that, even if the **Authorization Code** gets intercepted, it cannot be exchanged for a token without also including the initial code.
#### [Client credentials](https://oauth.net/2/grant-types/client-credentials/)
This flow is best suited for **machine-to-machine** (M2M) interactions where there is no end-user.
It consists of the following steps:
1. The **Client** authenticates with the **Authorization Server** using its own credentials.
2. The **Authorization Server** verifies the credentials.
3. The **Authorization Server** returns an **OAuth2 Access Token**.
4. The **Client** uses the **OAuth2 Access Token** to access protected resources.
5. The **Resource Server** validates the **OAuth2 Access Token**.
6. If the validation is successful, the **Resource Server** returns the requested resources.
# Authentication - Unified Login - Quickstart Guides - Multiple frontend domains with a common backend
Source: https://supertokens.com/docs/authentication/unified-login/quickstart-guides/multiple-frontends-with-a-single-backend
## Overview
You can implement the following guide if you have multiple **`frontend applications`** that use the same **`backend service`**.
The authentication flow works in the following way:
## Before you start
These instructions assume that you already have gone through the main [quickstart guide](/docs/quickstart/introduction).
If you have skipped that page, please follow the tutorial and return here once you're done.
:::info
If your frontend applications are on the same **domain**, but on different **sub-domains**, you can use [Session Sharing Across Subdomains](/docs/post-authentication/session-management/share-session-across-sub-domains).
:::
## Steps
### 1. Enable the Unified Login feature
Go to the [**SuperTokens.com SaaS Dashboard**](https://supertokens.com) and follow these instructions:
1. Click on the **Enabled Paid Features** button
2. Click on **Managed Service**
3. Check the **Unified Login / M2M** option
4. Click *Save*
### 2. Create the OAuth2 Clients
For each of your **`frontend`** applications create a separate [**OAuth2 client**](/docs/authentication/unified-login/oauth2-basics#client).
This can occur by directly calling the **SuperTokens Core** API.
## Before you start
These instructions assume that you already have gone through the main [quickstart guide](/docs/quickstart/introduction).
If you have skipped that page, please follow the tutorial and return here once you're done.
:::info
Note that, if the *frontends* and *backends* are in different *sub domains*, you don't need to use *OAuth* and can instead use [session sharing across sub domains](/docs/post-authentication/session-management/share-session-across-sub-domains).
:::
## Steps
### 1. Enable the Unified Login feature
Go to the [**SuperTokens.com SaaS Dashboard**](https://supertokens.com) and follow these instructions:
1. Click on the **Enabled Paid Features** button
2. Click on **Managed Service**
3. Check the **Unified Login / M2M** option
4. Click *Save*
### 2. Create the OAuth2 Clients
For each of your applications you need to create a separate [**OAuth2 client**](/docs/authentication/unified-login/oauth2-basics#client).
You can do this by directly calling the **SuperTokens Core** API.
## Before you start
These instructions assume that you already have gone through the main [quickstart guide](/docs/quickstart/introduction).
If you have skipped that page, please follow the tutorial and return here once you're done.
## Steps
### 1. Enable the Unified Login feature
Go to the [**SuperTokens.com SaaS Dashboard**](https://supertokens.com) and follow these instructions:
1. Click on the **Enabled Paid Features** button
2. Click on **Managed Service**
3. Check the **Unified Login / M2M** option
4. Click *Save*
### 2. Create the OAuth2 Clients
For each of your applications you need to create a separate [**OAuth2 client**](/docs/authentication/unified-login/oauth2-basics#client).
You can do this by directly calling the **SuperTokens Core** API.
Before going into the actual instructions, start by imagining a real life example that you can reference along the way.
This makes it easier to understand what is happening.
We are going to configure authentication for the following setup:
- A **Calendar Service** that exposes these actions: `event.view`, `event.create`, `event.update` and `event.delete`
- A **File Service** that exposes these actions: `file.view`, `file.create`, `file.update` and `file.delete`
- A **Task Service** that interacts with the **Calendar Service** and the **File Service** in the process of scheduling a task
The aim is to allow the **Task Service** to perform an authenticated action on the **Calendar Service**.
Proceed to the actual steps.
## Before you start
These instructions assume that you already have gone through the main [quickstart guide](/docs/quickstart/introduction).
If you have skipped that page, please follow the tutorial and return here once you're done.
## Steps
### 1. Enable the OAuth2 features from the Dashboard
You first have to enable the **OAuth2** features from the **SuperTokens.com Dashboard**.
1. Open the **SuperTokens.com Dashboard**
2. Click on the **Enabled Paid Features** button
3. Click on **Managed Service**
4. Check the **Unified Login / M2M** option
5. Click *Save*
You should be able to use the OAuth2 recipes in your applications.
### 2. Create the OAuth2 Clients
For each of your **`microservices`** you need to create a separate [**OAuth2 client**](/docs/authentication/unified-login/oauth2-basics#client).
This can occur by directly calling the **SuperTokens Core** API.
The first step is to create a JWT from the microservice that sends the request (refer to this microservice as `M1`).
Other microservices verify this JWT when `M1` sends them a request.
Since this JWT remains static per microservice, the best time to create this is on process starts - that is when `M1` starts.
The JWT can contain any information you like. At a minimum, it needs to contain information proving that it is a microservice allowed to query other microservices in your infrastructure.
This is necessary since you may issue a JWT to an end user as well, and they should not be able to query any microservice directly.
Add the following claim in the JWT to "mark" the JWT as one meant for microservice auth only:
```json
{..., "source": "microservice", ...}
```
In the receiving microservice (`M2`), verify the JWT and check that this claim is present before serving the request.
### Security considerations
#### Who can query the microservices?
Anyone or any service that has direct access to the SuperTokens core can produce a valid JWT and query your microservices.
If the core is open to the internet, you *must* add an API key to protect it.
Even though end users may receive a JWT for their session (that the core signs), they cannot query a microservice directly. Their JWT *should* not have the `source: "microservice"` claim in it.
#### What happens if someone compromises the core's API key?
Then the attacker can issue their own JWTs to be able to query your microservices. To limit this protection, you may want to add firewall rules to allow access to the core only from services on your backend.
You can also provide multiple API keys to the core and give a unique key to each microservice in your infrastructure. This way, it would be easier to track where a leak came from.
#### What happens if someone compromises the JWT signing key?
In this case, the attacker could fabricate their own JWT to be able to query your microservices.
To limit this risk, a JWT signing key rotation methodology is in place. Until then, you can limit the reachability of your microservices based on the request's IP address.
#### How to limit which microservice can query another one?
If an organisation has multiple teams and microservices, it is common to limit which other services a given microservice can query.
For example, if there exists `M1`, `M2` and `M3` microservices, there may be a situation in which `M1` should only be able to query `M2` and not `M3`.
With one SuperTokens core deployment, having this type of restriction is impossible. All the microservices create and verify their JWTs using the same public/private keys. Therefore `M3` receives a request, it has no way of reliably knowing if the request is from `M1` or `M2` (assuming that IP-based access control is not implemented).
This type of restriction can occur by deploying multiple cores connected to their own databases. In this example, a dedicated SuperTokens core can handle `M3`'s auth, such that only `M3` uses that to verify the incoming JWTs. Then, only other services that have access to that core can create JWTs that `M3` accepts. If `M1` doesn't have access to `M3`'s core's API key, it can be assured that successful requests to `M3` are not from `M1`.
## Steps
### 1. Create a JWT
In the above setting, Email Password is active in the **Login Methods** section. This means that users who login to this tenant can only use email password as the first factor. Later on, the configuration for passwordless as a second factor for this tenant appears.
By default, no login methods activate for a tenant.
As shown above, you turn on `OTP - Email` in the **Secondary Factors** section which means that all users who log into that tenant must complete `otp-email` as a second factor.
You can also turn off all factors to have no secondary factors required for the tenant.
If you turn on more than one factor, it means that the user must complete any one of factors that are active. If you want to have a different behavior for the tenant, you can achieve that by overriding the `getMFARequirementsForAuth` function as shown below:
As shown above, enable **Email Password** and **Third Party** in the Login methods section and enable **OTP - Email** in the Secondary Factors Section.
You can find the [source code of this template on GitHub](https://github.com/supertokens/email-sms-templates/blob/master/email-html/email-verification.html)
To understand more about how you can customize the check the [email delivery](/docs/platform-configuration/email-delivery) section.
### Verification link lifetime
By default, the email verification link's lifetime is **1 day**.
This can change via a core's configuration (time in milliseconds):
### Features
- **Brute Force Attack Detection**: Watches how many times someone tries to do a specific action (such as logging in, resetting password, etc.) within a certain time. If there are too many attempts, it stops them to prevent bad actors from compromising accounts.
- **Password Breach Detection**: Checks passwords against a database of leaked passwords to see if they have leaked before. This helps keep accounts safe by avoiding weak passwords.
- **Impossible Travel Detection**: Identifies fraudulent login attempts by detecting geographically impossible travel between user sessions in a short time.
- **Bot Detection**: Identifies and prevents automated scripts or bots from performing malicious activities such as credential stuffing, account takeover attempts, or scraping sensitive data. It uses advanced algorithms to analyze user behavior, request patterns, and other indicators to distinguish between human users and automated bots.
- **Suspicious IP Detection**: Detects suspicious IP addresses known for malicious activities. This includes detecting the use of VPNs, Tor, proxy servers, or other network configurations that may hide the user's true location or identity.
- **New Device Detection**: Recognizes when a user logs in from a new, previously unseen device. This helps find possible unauthorized logins.
- **Device Count Tracking**: Monitors the number of unique devices associated with a user account. This helps spot unusual account use.
- **Requester Detection**: Recognize and remember devices and requester details, even when they try to disguise themselves. This helps track and identify the same device or requester across multiple login attempts, improving security and user recognition.
## Getting started
To learn how to use the feature in your application open the [quickstart guide](/docs/additional-verification/attack-protection-suite/initial-setup).
:::info
Use the feature only with either the `Email Password` or `Passwordless` authentication recipes.
For social or enterprise login, it is not needed.
:::
# Additional Verification - Attack Protection Suite - Initial setup
Source: https://supertokens.com/docs/additional-verification/attack-protection-suite/initial-setup
## Overview
The following page shows you how to include the **Attack Protection Suite** feature in your **SuperTokens** integration.
## Before you start
This feature is **in beta**.
To get access to it, please [reach out](mailto:support@supertokens.com) to get it set up for you.
Once you have access to it, you receive:
- **Public API key** - use this on your frontend for generating request IDs
- **Secret API key** - use this on your backend for making requests to the anomaly detection API
- **Environment ID** - use this for identifying the environment you are using both on the backend and the frontend
You can use the feature with either the `Email Password` or the `Passwordless` authentication methods.
For social or enterprise login, it is not needed for multiple reasons:
- **Existing anomaly detection**: Most reputable third-party authentication providers (like Google, Facebook, Apple, etc.) have robust security measures in place, including their own anomaly detection systems. These systems are typically more comprehensive and tailored to their specific platforms.
- **Limited visibility**: When using third-party authentication, you have limited visibility into the authentication process. This makes it difficult to accurately detect anomalies or suspicious activities that occur on the third-party's side.
- **Potential false positives**: Applying anomaly detection to third-party logins might lead to an increase in false positives, as you don't have full context of the user's interactions with the third-party provider.
- **User experience**: Additional security checks on top of third-party authentication could negatively impact the user experience, defeating the purpose of offering third-party login as a convenient option.
## Steps
### 1. Attach request IDs to backend API calls
The **Attack Protection Suite** feature relies on identifying each request through a unique ID.
This way the fingerprinting process can determine if it's a potential threat or not.
:::info Important
This step applies only to bot detection and anomaly IP-based detection such as impossible travel detection.
Also, check for bot detection only on the email password login flows.
:::
#### 1.1 Generate a request ID
To generate a request ID, import, and initialize the SDK using your public API key.
This SDK generates a unique request ID for each authentication event attempt.
```tsx
const ENVIRONMENT_ID = "
## Customization
### Custom field components
To add custom rendering behavior for fields you have to pass an override during plugin initialization.
```typescript
SuperTokens.init({
// ... other config
experimental: {
plugins: [
ProfileDetailsPlugin.init({
override: (oI) => ({
...oI,
fieldInputComponentMap: (originalMap) => ({
...originalMap,
string: CustomStringInput,
}),
fieldViewComponentMap: (originalMap) => ({
...originalMap,
string: CustomStringView,
}),
}),
}),
],
},
});
```
### Custom user interface
To create your own UI you can use the `usePluginContext` hook.
It exposes an interface which you can use to call the endpoints exposed by the backend plugin.
```typescript
function CustomProfileComponent() {
const { api, t, fieldInputComponentMap } = usePluginContext();
const [profile, setProfile] = useState(null);
const handleGetDetails = async () => {
const result = await api.getDetails();
if (result.status === "OK") {
setProfile(result.profile);
}
};
const handleUpdateProfile = async (data) => {
const result = await api.updateProfile({ data });
if (result.status === "OK") {
console.log("Profile updated successfully");
}
};
return (
From the interface you can check the banning status of a user.
Based on that status, you can either ban or remove the ban for that account.
#### 3.2 Using direct API calls
You can also manage user bans programmatically using the exposed API endpoints.
##### Ban/unban user
```javascript
// Ban a user
const banResponse = await fetch("/plugin/supertokens-plugin-user-banning/ban?tenantId=public", {
method: "POST",
credentials: "include", // Include session cookies
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: "user@example.com",
// You can also pass the userId instead of the email
// userId: "user123",
isBanned: true, // true to ban, false to remove ban
}),
});
const banResult = await banResponse.json();
if (banResult.status === "OK") {
console.log("User banned successfully");
} else {
console.error("Failed to ban user:", banResult.message);
}
// Remove ban from a user
const unbanResponse = await fetch("/plugin/supertokens-plugin-user-banning/ban?tenantId=public", {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: "user@example.com",
isBanned: false,
}),
});
```
##### Check ban status
```javascript
// Check if a user is banned
const statusResponse = await fetch(
"/plugin/supertokens-plugin-user-banning/ban?tenantId=public&email=user@example.com",
{
method: "GET",
credentials: "include",
}
);
const status = await statusResponse.json();
if (status.status === "OK") {
console.log("User is banned:", status.banned);
} else {
console.error("Error checking ban status:", status.message);
}
```
## Customization
### Implement a custom user interface
To create a custom user interface you can use the `usePluginContext` hook.
It allows you to access the plugin's API methods and configuration in custom React components:
```typescript
function MyCustomAdminComponent() {
const { api, pluginConfig, t } = usePluginContext();
const handleBanUser = async (email: string) => {
try {
const result = await api.updateBanStatus("public", email, true);
if (result.status === "OK") {
console.log("User banned successfully");
} else {
console.error("Failed to ban user:", result.message);
}
} catch (error) {
console.error("Error:", error);
}
};
const handleCheckBanStatus = async (email: string) => {
try {
const result = await api.getBanStatus("public", email);
if (result.status === "OK") {
console.log("User has ban:", result.banned);
} else {
console.error("Error:", result.message);
}
} catch (error) {
console.error("Error:", error);
}
};
return (
## Customization
### Storage handlers
By default, the plugin stores profile data using the `User Metadata` recipe.
You can also implement your custom storage solution by overriding the `defaultStorageHandlerSetFields` and `defaultStorageHandlerGetFields` functions.
```typescript
SuperTokens.init({
supertokens: {
connectionURI: "...",
},
appInfo: {
// your app info
},
recipeList: [
// your recipes
],
experimental: {
plugins: [
ProgressiveProfilingPlugin.init({
sections: [
{
id: "basic-info",
label: "Basic Information",
description: "Tell us about yourself",
fields: [
{
id: "firstName",
label: "First Name",
type: "string",
required: true,
placeholder: "Enter your first name",
},
{
id: "lastName",
label: "Last Name",
type: "string",
required: true,
placeholder: "Enter your last name",
},
{
id: "company",
label: "Company",
type: "string",
required: false,
placeholder: "Enter your company name",
},
],
},
],
override: (oI) => ({
...oI,
defaultStorageHandlerSetFields: ({ pluginFormFields, data, session, userContext }) => {
const userId = session.getUserId(userContext);
const profile = pluginFormFields.reduce(
(acc, field) => {
const newValue = data.find((d) => d.fieldId === field.id)?.value;
const existingValue = existingProfile?.[field.id];
return {
...acc,
[field.id]: newValue ?? existingValue ?? field.defaultValue,
};
},
{ ...existingProfile }
);
// Implement your own logic for storing profile data
await customSetProfileData(userId, profile);
},
defaultStorageHandlerGetFields: ({ pluginFormFields, session, userContext }) => {
const userId = session.getUserId(userContext);
// Implement your own logic for fetching profile data
const existingProfile = await customGetProfileData(userId);
return pluginFormFields.map((field) => ({
sectionId: field.sectionId,
fieldId: field.id,
value: existingProfile[field.id] ?? field.defaultValue,
});
},
}),
}),
],
},
});
```
### User interface
To create your own UI you can use the `usePluginContext` hook.
It exposes an interface which you can use to interface with the endpoints exposed by the backend plugin.
```typescript
function CustomProfileComponent() {
const { api, t } = usePluginContext();
const [profile, setProfile] = useState([]);
const handleLoadProfile = async () => {
const result = await api.getProfile();
if (result.status === "OK") {
setProfile(result.data);
}
};
const handleUpdateProfile = async (data) => {
const result = await api.updateProfile({ data });
if (result.status === "OK") {
console.log("Profile updated successfully");
} else if (result.status === "INVALID_FIELDS") {
console.error("Validation errors:", result.errors);
}
};
return (
- Below is the scenario for when this status returns:
A malicious user, User A, which is a primary user, has login methods with email `e1` (social login) and email `e1` (`emailpassword` login). If user A changes their `emailpassword` email to `e2` (which is in unverified state), and the real user of `e2` (the victim) tries to sign up via email password, they see a message saying that the email already exists. The victim may then try to do a password reset (thinking they had previously signed up). If this happens, and the victim resets the password (since they are the real owner of the email), then they can login to the account, and the attacker can spy on what the user is doing via their third party login method.
To prevent this scenario, enforcement ensures that the password link is only generated if the primary user has at least one login method that has the input email ID and verifies it, or if not, checks that the primary user has no other login method with a different email, or phone number. If these cases are not satisfied, then the system returns the error code `ERR_CODE_001`.
- To resolve this, you would have to manually verify the user's identity and check that they own each of the emails / phone numbers associated with the primary user. Once verified, you can manually mark the email from the email password account as verified, and then ask them to go through the password reset flow once again. If they do not own each of the emails / phone numbers associated with the account, you can manually unlink the login methods which they do not own, and then ask them to go through the password reset flow once again. **You can do these actions using the user management dashboard.**
## `ERR_CODE_002`
- This can happen during the passwordless recipe's create or consume code API (during sign up):
- API path and method: `/signinup/code POST` or `/signinup/code/consume POST`
- Output JSON:
```json
{
"status": "SIGN_IN_UP_NOT_ALLOWED",
"reason": "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_002)"
}
```
- The pre-built UI on the frontend displays this error in the following way:
- Below is an example scenario for when this status returns (one amongst many):
A user is trying to sign up using passwordless login method with email `e1`. There exists an email password login method with `e1`, which remains unverified (owned by an attacker). If this scenario occurs, and then the attacker initiates the email verification flow for the email password method, the real user might click on the verification email (since they signed up, they do not get suspicious), and then the attacker's login method links to the passwordless login method. This way, the attacker gains access to the user's account.
To prevent this, sign up with passwordless login is not allowed in case there exists another account with the same email and remains unverified.
- To resolve this issue, you should ask the user to try another login method (which already has their email), or then mark their email as verified in the other account that has the same email, before asking them to retry passwordless login. **You can do these actions using the user management dashboard.**
## `ERR_CODE_003`
This used to be an error code which is no longer valid and you can ignore it.
## `ERR_CODE_004`
- This can happen during the third party recipe's `/signinup` API (during sign in):
- API path and method: `/signinup POST`
- Output JSON:
```json
{
"status": "SIGN_IN_UP_NOT_ALLOWED",
"reason": "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_004)"
}
```
- The pre-built UI on the frontend displays this error in the following way:
- Below is an example scenario for when this status returns (one amongst many):
There exists a `thirdparty` user with email `e1`, sign in with Google (owned by the victim, and the email is verified). There exists another `thirdparty` login method with email, `e2` (owned by an attacker), such as login with GitHub. The attacker then goes to their GitHub and changes their email to `e1` (which is in unverified state). The next time the attacker tries to login, via GitHub, they see this error code. Login is prevented, because if it wasn't, then the attacker might send an email verification link to `e1`, and if the victim clicks on it, then the attacker's account will link to the victim's account.
- To resolve this issue, you can delete the login method that has the unverified email, or if manually mark the unverified account as verified (if you confirm the identity of its owner). **You can do these actions using the user management dashboard.**
## `ERR_CODE_005`
- This can happen during the third party recipe's `signinup` API (during sign in):
- API path and method: `/signinup POST`
- Output JSON:
```json
{
"status": "SIGN_IN_UP_NOT_ALLOWED",
"reason": "Cannot sign in / up because new email cannot be applied to existing account. Please contact support. (ERR_CODE_005)"
}
```
- The pre-built UI on the frontend displays this error in the following way:
- Below is as example scenario for when this status returns (one amongst many):
There exists a primary, third party user with email `e1`, sign in with Google. There exists another email password user with email `e2`, which is a primary user. If the user changes their email on Google to `e2`, and then try logging in via Google, they see this error code. This occurs because if it wasn't, then it would result in two primary users having the same email, which violates one of the account linking rules.
- To resolve this issue, you can make one of the primary users as non primary (use the unlink button against the login method on the user management dashboard). Once the user is not a primary user, you can ask the user to re-login with that method, and it should auto link that account with the existing primary user.
## `ERR_CODE_006`
- This can happen during the third party recipe's `signinup` API (during sign up):
- API path and method: `/signinup POST`
- Output JSON:
```json
{
"status": "SIGN_IN_UP_NOT_ALLOWED",
"reason": "Cannot sign in / up because new email cannot be applied to existing account. Please contact support. (ERR_CODE_006)"
}
```
- The pre-built UI on the frontend displays this error in the following way:
- Below is as example scenario for when this status returns (one amongst many):
A user is trying to sign up using third party login method with email `e1`. There exists an email password login method with `e1`, which remains unverified (owned by an attacker). If the third party sign up is allowed, and then the attacker initiates the email verification flow for the email password method, the real user might click on the verification email (since they signed up, they do not get suspicious), and then the attacker's login method links to the third party login method. This way, the attacker has access to the user's account.
To prevent this, sign up with third party login is not allowed in case there exists another account with the same email and remains unverified.
- To resolve this issue, you should ask the user to try another login method (which already has their email), or then manually mark their email as verified in the other account that has the same email, before asking them to retry third party login. **You can do these actions using the user management dashboard.**
## `ERR_CODE_007`
- This can happen during the email password sign up API:
- API path and method: `/signup POST`
- Output JSON:
```json
{
"status": "SIGN_UP_NOT_ALLOWED",
"reason": "Cannot sign up due to security reasons. Please try logging in, use a different login method or contact support. (ERR_CODE_007)"
}
```
- The pre-built UI on the frontend displays this error in the following way:
- Below is as example scenario for when this status returns (one amongst many):
There exists a primary, social login account with email `e1`, sign in with Google. If an attacker tries to sign up with email password with email `e1`, the system sends an email verification email to the victim, and they may click it since they had previously signed up with Google. This links the attacker's account to the victim's account.
- To resolve this issue, you can ask the user to try and login, or go through the reset password flow.
## `ERR_CODE_008`
- This can happen during the email password sign in API:
- API path and method: `/signin POST`
- Output JSON:
```json
{
"status": "SIGN_IN_NOT_ALLOWED",
"reason": "Cannot sign in due to security reasons. Please try resetting your password, use a different login method or contact support. (ERR_CODE_008)"
}
```
- The pre-built UI on the frontend displays this error in the following way:
- Below is as example scenario for when this status returns (one amongst many):
There exists a primary, social login account with email `e1`, sign in with Google. There also exists an email password account (owned by the attacker) that remains unverified with the same email `e1` (this is not a primary user). If the attacker tries to sign in with email password, they see this error. This occurs because if it wasn't, then the attacker might send an email verification email on sign in, and the actual user may click on it (since they had previously signed up). Upon verifying that account, the system links the attacker's account to the victim's account.
- To resolve this issue, you can ask the user to try the reset password flow.
## `ERR_CODE_014`
- This can happen when adding a password to an existing session user:
- API Path is `/signup POST`.
- Output JSON:
```json
{
"status": "SIGN_UP_NOT_ALLOWED",
"reason": "Cannot sign up due to security reasons. Please contact support. (ERR_CODE_014)"
}
```
- An example scenario of when in the following scenario:
- Let's say that the app configures to not have automatic account linking during the first factor.
- A user creates an email password account with email `e1`, verifies it, and links social login account to it with email `e2`.
- The user logs out, and then creates a social login account with email `e1`. Then, they receive a request to add a password to this account. Since an email password account with `e1` already exists, SuperTokens tries and links that to this new account, but fails, since the email password account with `e1` is already a primary user.
- To resolve this, it is recommended to manually link the `e1` social login account with the `e1` email password account. Alternatively, enable automatic account linking for first factor to prevent the above scenario.
## `ERR_CODE_015`
- This can happen when adding a password to an existing session user:
- API Path is `/signup POST`.
- Output JSON:
```json
{
"status": "SIGN_UP_NOT_ALLOWED",
"reason": "Cannot sign up due to security reasons. Please contact support. (ERR_CODE_015)"
}
```
- An example scenario of when in the following scenario:
- A user creates a social login account with email `e1` which becomes a primary user.
- The user logs out, and creates another social login account with email `e2`, which also becomes a primary user.
- The user receives a request to add a password for the new account with an option to also specify an email with it (this is strange, but theoretically possible). They enter the email `e1` for the email password account.
- This causes this type of error since the linking of the new social login and email account fails since there already exists another primary user with the same (`e1`) email.
- To resolve this, it is recommended not allowing users to specify an email when asking them to add a password for their account.
## `ERR_CODE_016`
- This can happen when adding a password to an existing session user:
- API Path is `/signup POST`.
- Output JSON:
```json
{
"status": "SIGN_UP_NOT_ALLOWED",
"reason": "Cannot sign up due to security reasons. Please contact support. (ERR_CODE_016)"
}
```
- An example scenario of when in the following scenario:
- Let's say that the app is configured to not have automatic account linking during the first factor.
- A user signs up with a social login account using Google with email `e1`, and they add another social account, with Facebook, with the same email.
- The user logs out and creates another social login account with email `e1` (say GitHub), and then tries and adds a password to this account with email `e1`. Here, SuperTokens tries and makes the GitHub login a primary user, but fails, since the email `e1` is already a primary user (with Google login).
- To resolve this, it is recommended that you manually link the `e1` GitHub social login account with the `e1` Google social login account. Or you can enable automatic account linking for first factor and this way, the above scenario will not happen.
## `ERR_CODE_020`
- This can happen during association of a third party login to an existing session's account.
- API Path is `/signinup POST`.
- Output JSON:
```json
{
"status": "SIGN_IN_UP_NOT_ALLOWED",
"reason": "Cannot sign in / up due to security reasons. Please contact support. (ERR_CODE_020)"
}
```
- This can happen when the third party account that is trying to link to the session's account is not verified. It could happen when you are trying to associate a social login account to a user, but that social account's email is not verified (and if the email of that account is not the same as the current session's account's email).
- To resolve this, you can return `shouldRequireVerification` as `false` in the `shouldDoAutomaticAccountLinking` function implementation, or you can only allow users to link social login accounts that give verified accounts.
## `ERR_CODE_021`
- This can happen during association of a third party login to an existing session's account.
- API Path is `/signinup POST`.
- Output JSON:
```json
{
"status": "SIGN_IN_UP_NOT_ALLOWED",
"reason": "Cannot sign in / up due to security reasons. Please contact support. (ERR_CODE_021)"
}
```
- This can happen when the third party account that is trying to link to the session's account is already linked with another primary user.
## `ERR_CODE_022`
- This can happen during association of a third party login to an existing session's account.
- API Path is `/signinup POST`.
- Output JSON:
```json
{
"status": "SIGN_IN_UP_NOT_ALLOWED",
"reason": "Cannot sign in / up due to security reasons. Please contact support. (ERR_CODE_022)"
}
```
- This can happen when the third party account that is trying to link to the session's account has the same email as another primary user.
## `ERR_CODE_023`
- This can happen during association of a third party login to an existing session's account.
- API Path is `/signinup POST`.
- Output JSON:
```json
{
"status": "SIGN_IN_UP_NOT_ALLOWED",
"reason": "Cannot sign in / up due to security reasons. Please contact support. (ERR_CODE_023)"
}
```
- To link the third party user with the session user, we need to make sure that the session user is a primary user. However, that can fail if there exists another primary user with the same email as the session user, and in this case, this error returns to the frontend.
## `ERR_CODE_024`
- This happens during third party sign in, when the user is trying to sign in with a non-primary user, and the third party provider does not verify their email, and their exists a primary user with the same email. This can also happen the other way around wherein the user is trying to sign in with the primary user (unverified email), and there exists a non-primary user with the same email.
- API Path is `/signinup POST`.
- Output JSON:
```json
{
"status": "SIGN_IN_UP_NOT_ALLOWED",
"reason": "Cannot sign in / up due to security reasons. Please contact support. (ERR_CODE_024)"
}
```
- You can resolve this by deleting the (non primary) user that has the same email ID, or by manually marking the email of the user as verified for the login method that they are trying to sign in with.
### 3. Create dashboard credentials
:::info Paid Feature
You can create 3 dashboard users* for free.
If you need to create additional users:
- For self hosted users, please [sign up](https://supertokens.com/auth) to generate a license key and follow the instructions sent to you by email.
- For managed service users, you can click on the "enable paid features" button on [the dashboard](https://supertokens.com/dashboard-saas), and follow the steps from there on.
*: A dashboard user is a user that can log into and view the user management dashboard. These users are independent to the users of your application
:::
When you first set up SuperTokens, there are no credentials created for the dashboard. If you click the "Add a new user" button in the dashboard login screen you can see the command you need to execute to create credentials.
To create credentials you need to make a request to SuperTokens core.
- The example above uses the demo core `https://try.supertokens.com`, replace this with the connection URI you pass to the backend SDK when initialising SuperTokens.
- Replace `
To update credentials you need to make a request to SuperTokens core.
- The example above uses the demo core `https://try.supertokens.com`, replace this with the connection URI you pass to the backend SDK when initialising SuperTokens.
- Replace `
## List users
Navigate to your frontend app and create a user (via the sign-up flow). On creation, if you head back to the dashboard and refresh the page, you see that user:
---
## View user details
When you select a user you can view detailed information about the user such as email, phone number, user metadata, etc.
---
## Edit user details
You can edit user information and perform actions such as resetting a user's password or revoking sessions for a user.
:::info Note
Enable some features such as user metadata and email verification in your backend before you can use them in the user management dashboard.
:::
---
## Create user roles and permissions
:::caution no-title
This feature is only available through the Node.js SDK.
:::
When you first use the `UserRoles` recipe, the list of roles is empty. To create roles, click on the "Add Role" button.
This action opens a modal, enabling you to create a role along with its associated permissions. Permissions are essentially a list of strings assigned to a specific role.
---
## List user roles
:::caution no-title
This feature is only available through the Node.js SDK.
:::
After creating a role, the UI should display a list of all roles in your app.
You can preview the role you created by clicking on the role row. The modal provides options to edit or delete the role.
---
## Assign user roles
:::caution no-title
This feature is only available through the Node.js SDK.
:::
To assign a specific role to a user, start by finding the user in the dashboard. Upon clicking the user, navigate to the user details page where you find a section for user roles.
If the selected user has associations with multiple tenants, you can choose a `tenantId` from the dropdown menu to specify the tenant for which you'd like to assign roles.
Click the edit button to start assigning roles. Then, select the "Assign Role" button, and a modal appears with a list of available roles for assignment to this user.
---
## Remove user roles
:::caution no-title
This feature is only available through the Node.js SDK.
:::
To remove a role assigned to a user, click on the "X" icon next to that specific role.
# Post Authentication - Dashboard - Tenant management
Source: https://supertokens.com/docs/post-authentication/dashboard/tenant-management
## Overview
This page shows you what actions you can perform on tenants through the dashboard.
:::info Caution
This is only available with Node and Python SDKs.
:::
---
## Create a new tenant
Clicking on `Add Tenant` prompts you to enter the tenant id. Once you enter the tenant id, click on `Create Now` to create the tenant. You then proceed to the Tenant Details page where you can further manage the newly created tenant.
## View tenant details
Upon selection or creation of a tenant, the Tenant Details page appears. The sections appear below.
### Tenant ID and users
The first section shows the tenant ID and the number of users in that tenant. Clicking on `See Users` takes you to the [user management page](/docs/post-authentication/dashboard/user-management) where you can view and manage the users for the selected tenant.
### Enabled login methods
This section displays the login methods available for the tenant. By enabling these toggles, you can make the corresponding login methods accessible to the users within the tenant.
Appropriate recipes must be active to turn on the login methods. For example,
- to turn on `emailpassword`, initialize the EmailPassword recipe in the backend.
- to turn on `OTP Phone`, initialize the Passwordless recipe with `flowType` `USER_INPUT_CODE` and contactMethod `PHONE`
:::info
If you are using the Auth React SDK, make sure to enable [usesDynamicLoginMethods](/docs/authentication/enterprise/common-domain-login#3-tell-supertokens-about-the-saved-tenantid-from-the-previous-step) to ensure the frontend automatically shows the login methods based on the selection here.
:::
### Secondary factors
This section displays the secondary factors available for the tenant. By enabling these toggles, the corresponding factor becomes active for all users of the tenant. Refer to [MultiFactor Authentication docs](/docs/additional-verification/mfa/introduction) for more information.
[MultiFactorAuth](/docs/additional-verification/mfa/initial-setup) recipe must initialize to enable Secondary Factors.
Also, initialize appropriate recipes in the backend SDK to use a secondary factor. For example,
- to turn on TOTP, initialize the TOTP recipe in the backend.
- to turn on `OTP Phone`, initialize the Passwordless recipe with `flowType` `USER_INPUT_CODE` and contactMethod `PHONE`
### Core configuration
This section shows the current configuration values in core for the tenant. You can edit some of these settings by clicking the `pencil` icon next to the property.
:::caution
Some configuration values may not be editable since they inherit from the App. If using SuperTokens managed hosting, you can modify them in the SaaS Dashboard. Else, if you are self-hosting the SuperTokens core, edit them via Docker environment variables or the `configuration.yaml` file.
:::
---
## Manage `ThirdParty` providers
The Social/Enterprise providers section becomes available once `Third Party` login method is active for the tenant.
Initially, configure a new provider.
Later on, you can configure new or existing third-party providers from the **Social/Enterprise providers** section.
### Configure a new provider
When adding a new third-party provider, you receive a list of available options, including built-in enterprise and social providers, custom, and SAML.
Upon selection of the desired provider, provide further details such as `Client ID`, `Client Secret`, etc.
#### Enterprise providers
For the Enterprise providers, provide certain extra information before proceeding to the Provider details. For example, Active Directory provider requires a `Directory ID` before editing further details.
#### Custom providers
If a Social/Enterprise provider is not available in the list of built-in providers, you can still use them by selecting the `Add Custom Provider` option.
Start off by providing `ThirdParty ID`, `Name` and Client details such as `Client ID`, `Secret`, `Scope`, etc.
If using an OpenID compliant provider, you could add the `OIDC Discovery Endpoint`. Otherwise, configure the provider by manually providing `Authorization Endpoint`, `Token Endpoint`, `User Info Endpoint`, etc.
Finally, clicking on `Save` adds the Social/enterprise provider for the tenant.
#### SAML providers
To add a SAML provider, use the `Add SAML Provider` option. For more information on what is SAML and how it works with SuperTokens, refer [SAML docs](/docs/authentication/enterprise/saml/what-is-saml).
Upon selection, provide the `Boxy URL` and the `Boxy API Key`.
:::important
To use SAML providers, an additional Boxy HQ service is necessary. You can either self-host yourself or email for a managed instance. Details for them are also available on this page.
:::
On continuing, you are further asked for the SAML configuration. You have an option to either provide SAML XML directly or via the Metadata URL from the Provider. Also, fill in other details such as `Suffix`, `Name`, `Redirect URLs` and click on `Save` to add the SAML provider.
:::caution
Adding ThirdParty suffix is not compulsory, however if you wish to add multiple SAML providers for a tenant, you need to add unique suffixes for each of them.
:::
If you did not provide the `Boxy API Key`, you need to add the `Client ID` and `Secret` obtained by calling the Boxy APIs manually. More details are [available here](/docs/authentication/enterprise/saml/boxy-hq-guide#4-upload-the-base64-xml-string-to-saml-jackson).
# Deployment - Migrate from MySQL to PostgreSQL
Source: https://supertokens.com/docs/deployment/migrate-from-mysql
## Overview
This tutorial shows you how to migrate your **SuperTokens** database from **MySQL** to **PostgreSQL**.
The migration involves exporting data from MySQL, setting up a PostgreSQL database with the same schema version, and importing the data with proper format conversions.
## Before you start
The tutorial assumes the following:
- You have access to both your `MySQL` and `PostgreSQL` databases
- Both databases are running on the same version of **SuperTokens Core**
- You have administrative privileges on both databases
## Steps
### 1. Create a backup of your MySQL database
Create a final backup of your MySQL database.
The instructions for this step are specific to your database management system.
### 2. Prepare the PostgreSQL database
Start the same version of [`supertokens-postgresql`](https://hub.docker.com/r/supertokens/supertokens-postgresql) to initialize the schema in the database.
:::warning
Make sure to use the same version as the `supertokens-mysql` instance that you are currently running.
:::
### 3. Export data from MySQL
#### 3.1 Export standard tables
Run the following command to export most of your data:
```bash
mysqldump supertokens --fields-terminated-by ',' --fields-enclosed-by '"' --fields-escaped-by '\' --no-create-info --tab /var/lib/mysql-files/
```
:::info
If you do not have permissions to write to the database filesystem you can use the following python script to export tables one by one:
### Number of requests per minute over 1 day
### Performance tuning
If you are facing performance issues, here are some tips to help you tune the performance of your SuperTokens setup:
- If you are self-hosting the SuperTokens core, know that it is stateless and can scale horizontally. You can add more instances of the core service to handle more requests (behind a load balancer).
- Check which part of the request cycle is slow. Is it the SuperTokens core responding, or is it the backend SDK APIs responding? The performance of the backend SDK API depends mainly on how you have set up your API layer (that integrates with the backend SDK) to perform. You can check which is slow by enabling debug logs in the backend SDK, and then inspecting the timestamps around the core requests. If they sum up to be much less than the total time taken for the request (from the `frontend`'s point of view), then the bottleneck is likely in the backend SDK.
- If you are self-hosting the SuperTokens core, check if there are any database queries that are too slow. You can do this using debugging tools provided by the PostgreSQL database. If you find a query that's causing issues, please reach out to support.
- Check that the compute used to run the backend SDK, the SuperTokens core (in case you are self-hosting it), and the database is sufficient. Using a t3.micro EC2 instance for the core should work well for even 100,000 MAUs. You can check the `CPU` and memory usage of the instances to see if they have maxed out, or if you have run out of `CPU` credits. If they are, you can consider upgrading the instances to more powerful ones.
- In case you are self-hosting the SuperTokens core, you can tune its performance by setting different values for the following configurations in the configuration.yaml file, or docker `env`:
- `max_server_pool_size`: Sets the max thread pool size for incoming `http` server requests. Default value is 10.
- `postgresql_connection_pool_size` (if using psql): Defines the connection pool size to PostgreSQL. Default value is 10.
- `postgresql_minimum_idle_connections` (if using psql): Minimum number of idle connections to remain active. If not set, minimum idle connections are the same as the connection pool size. By default, this is not set.
- `postgresql_idle_connection_timeout`: (if using psql): Timeout in milliseconds for the idle connections to close. Default is 60000 MS.
- Check if you have access token blacklisting enabled in the backend SDK. The default is `false`, but if you have it enabled, then it means that every session verification attempt queries the SuperTokens core to check the database. This adds latency to the session verification process and increases the load on the core. If you want to keep this to `true`, consider making it only for non `GET` APIs for your application.
- You can increase the value of `access_token_validity` in the SuperTokens core. It sets the validity of the access token. Default value is 3,600 seconds (1 hour). The lower this value, the more often the refresh API calls the core, increasing the load on the core.
---
## Database
SuperTokens works with PostgreSQL databases, and one instance of the database is enough to handle tens of millions of MAUs.
For example, a database with 1 million users would occupy ~ 1.5 GB of disk space (assuming you add minimal custom metadata to the user object).
---
## Backend SDK
The backend SDK does not store any information on its own.
It's a "big middleware" between the frontend requests and the SuperTokens core.
As such, its scalability depends entirely on the scalability of your API layer into which the backend SDK integrates.
---
## Session verification
The access token is a JWT, and the backend SDK verifies them without any network requests, making them fast and scalable.
The core service verifies the refresh token, and the scalability of session refresh requests depends on the core service's scalability. However, session refreshes are rare compared to access token verification.
# Deployment - OpenTelemetry Integration
Source: https://supertokens.com/docs/deployment/telemetry
## Overview
This tutorial shows you how to add **OpenTelemetry** logging to all the **SuperTokens** APIs and function calls using the **OpenTelemetry plugin**. The guide makes use of the plugins functionality to automatically instrument your authentication flows with distributed tracing.
## How it works
The plugin manually adds traces to all overridable functions and APIs in SuperTokens. When you initialize the OpenTelemetry SDK alongside this plugin, you automatically get comprehensive tracing at the API level. The plugin provides built-in data protection by automatically removing sensitive fields from traces.
## Before you start
The OpenTelemetry plugin supports only the `NodeJS` SDK. Support for other platforms is under active development.
Make sure you have the OpenTelemetry SDK installed and configured in your application. For detailed instructions, see the [OpenTelemetry Node.js Getting Started Guide](https://opentelemetry.io/docs/languages/js/getting-started/nodejs/#instrumentation).
The implementation is in early stages and APIs might change. For more information on how plugins work, refer to the [references page](/docs/references/plugins/introduction).
## Steps
### 1. Install the plugin
```bash
npm install @supertokens-plugins/opentelemetry-nodejs
```
### 2. Configure the OpenTelemetry SDK
Set up the OpenTelemetry SDK in your application.
Here's a basic configuration:
```typescript
/*instrumentation.ts*/
const sdk = new NodeSDK({
traceExporter: new ConsoleSpanExporter(),
metricReader: new PeriodicExportingMetricReader({
exporter: new ConsoleMetricExporter(),
}),
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
```
:::note no-title
For a more thorough explanation on how to setup OpenTelemetry please refer to the [official documentation](https://opentelemetry.io/docs/languages/js/getting-started/nodejs).
:::
### 3. Update your backend SDK configuration
Initialize the **SuperTokens** plugin inside your SDK configuration file.
```typescript
SuperTokens.init({
supertokens: {
connectionURI: "...",
},
appInfo: {
// your app info
},
recipeList: [
// your recipes
],
experimental: {
plugins: [
OpenTelemetryPlugin.init(),
],
}
});
```
### 4. Test your setup
Inspect your traces and look for **SuperTokens** specific spans.
You should be able to identify them based on the following naming schemes:
- `
## Steps
### 1. Add the session migration endpoint
Create a new endpoint on your backend that will generate a new **SuperTokens Session** based on the current authentication token.
This will be called by the frontend if a user is still logged in through your previous authentication provider.
```tsx title="Backend changes"
let app = express();
app.post("/migrate-session", async (req, res) => {
// extract the access token from the request object
if(req.headers.authorization !== undefined){
let access_token = req.headers.authorization.split("Bearer ")[1];
// verify the access token and retrieve the old userId
let customUserId = await verifyAccessTokenAndRetriveUserId(access_token);
// create a new SuperTokens session using the customUserId
// the createNewSession function will attach the SuperTokens session tokens to the response object.
// @ts-ignore
await Session.createNewSession(req, res, customUserId)
res.send({
status: "OK"
})
}
// handle access_token not present in request
})
async function verifyAccessTokenAndRetriveUserId(access_token: string): Promise
#### Step 2: Update the SuperTokens core to use the `base64_signer_key`
- ** For Managed Service **
- Edit the core configuration in the SuperTokens Managed Service Dashboard.
- Set the `firebase_password_hashing_signer_key` field in the config to the `base64_signer_key` retrieved from your firebase hashing parameters.
### Backend Changes:
- Create an API on your backend, this will be called by the frontend to migrate a user's existing session to a SuperTokens session:
```tsx title="Backend changes"
let app = express();
app.post("/migrate-session", async (req, res) => {
// extract the access token from the request object
if(req.headers.authorization !== undefined){
let access_token = req.headers.authorization.split("Bearer ")[1];
// verify the access token and retrieve the old userId
let customUserId = await verifyAccessTokenAndRetriveUserId(access_token);
// create a new SuperTokens session using the customUserId
// the createNewSession function will attach the SuperTokens session tokens to the response object.
// @ts-ignore
await Session.createNewSession(req, res, customUserId)
res.send({
status: "OK"
})
}
// handle access_token not present in request
})
async function verifyAccessTokenAndRetriveUserId(access_token: string): Promise