Skip to main content
Which UI do you use?
Custom UI
Pre built UI
Paid Feature

This is a paid feature.

For self hosted users, Sign up to get a license key and follow the instructions sent to you by email. Using the dev license key is free. We only start charging you once you enable the feature in production using the provided production license key.

For managed service users, you can click on the "enable paid features" button on our dashboard, and follow the steps from there on. Once enabled, this feature is free on the provided development environment.

Using MFA with email verification

To start off, you need to add the email verification recipe to your SuperTokens setup as usual. Here are the links to the email verification recipe setup depending for each of the auth recipes we offer (The content is the same for all, it's just repeated in the individual auth recipe docs for convenience):


This guide is only applicable for when the email verifcation mode is REQUIRED because for OPTIONAL mode, the email verification challenge is not asked by the pre built Ui during the sign up process anyway.

The default behaviour of is that for REQUIRED mode of email verification, the user will be asked to complete the email verification challenge first, and then all of the MFA challenges. For example, if the user has emailpassword as the first factor, and then TOTP as a second factor, then SuperTokens will ask the user to do email password login, followed by email verification, followed by TOTP.

If you want to switch the order where email verification happens after the secondary factors of MFA, then you should do the following:

import supertokens from "supertokens-auth-react"
import EmailVerification from "supertokens-auth-react/recipe/emailverification";
import Session from "supertokens-auth-react/recipe/session";

appInfo: {
appName: "...",
apiDomain: "...",
websiteDomain: "...",
recipeList: [
// other recipes...
mode: "REQUIRED",
override: {
functions: (originalImplementation) => {
return {
getGlobalClaimValidators: (input) => {
let emailVerificationClaimValidator = input.claimValidatorsAddedByOtherRecipes.find(v => ===!;
let filteredValidators = input.claimValidatorsAddedByOtherRecipes.filter(v => !==;
return [...filteredValidators, emailVerificationClaimValidator];

In the snippet above, we override the getGlobalClaimValidators function in the Session recipe to add the email verification validator at the end of the returned validators array. This ensures that post the first factor sign up, the first validator that fails is the MFA one which will redirect the user to complete the MFA factors.


If you are using otp-email MFA factor as a form of email verification, you should also have emailverification recipe initialised in REQUIRED mode on the backend (no need to add it on the frontend since users won't see that UI). This is for security reasons wherein during the sign up process, when asking for the otp-email challenge, the email the OTP is sent to is decided on the frontend (automatically). In this case, the following scenario is possible:

  • User signs up with email A
  • An email OTP challenge is shown to the user, and an OTP to email A is sent automatically.
  • The user manually calls the OTP create code API with email B and their session token, and verifies the OTP via a call to the consume code API.
  • The user refreshes the page and the otp-email challenge is completed.

Now of course, this is not the desired flow when you want to use otp-email as a form of email verification. To prevent this, you should have the emailverification recipe initialised in REQUIRED mode on the backend. This will ensure that the email verification claim validator will only pass if the email that's verified is the one from the first factor (email A).

The above case is only possible during sign up, and not sign in.

Looking for older versions of the documentation?
Which UI do you use?
Custom UI
Pre built UI