Skip to main content

Protecting API and website routes

Protecting API routes#

Add checking to all API routes#

Set mode to REQUIRED in the EmailVerification config#

import SuperTokens from 'supertokens-node';
import EmailVerification from "supertokens-node/recipe/emailverification";
import Session from "supertokens-node/recipe/session";

SuperTokens.init({
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "..."
},
recipeList: [
EmailVerification.init({
// This means that verifySession will now only allow calls if the user has verified their email
mode: "REQUIRED",
}),
Session.init()
]
});

Disable email verification for specific routes (for REQUIRED mode)#

import { verifySession } from "supertokens-node/recipe/session/framework/express";
import express from "express";
import { SessionRequest } from "supertokens-node/framework/express";
import { EmailVerificationClaim } from "supertokens-node/recipe/emailverification";

let app = express();

app.post(
"/update-blog",
verifySession({
overrideGlobalClaimValidators: async (globalValidators) => globalValidators.filter(v => v.id !== EmailVerificationClaim.key),
}),
async (req: SessionRequest, res) => {
// All validator checks have passed and the user has a verified email address
}
);

Add checking to a single route (for OPTIONAL mode)#

import { verifySession } from "supertokens-node/recipe/session/framework/express";
import express from "express";
import { SessionRequest } from "supertokens-node/framework/express";
import { EmailVerificationClaim } from "supertokens-node/recipe/emailverification";

let app = express();

app.post(
"/update-blog",
verifySession({
overrideGlobalClaimValidators: async (globalValidators) => [...globalValidators, EmailVerificationClaim.validators.isVerified()],
}),
async (req: SessionRequest, res) => {
// All validator checks have passed and the user has a verified email address
}
);

Protecting frontend routes#

If using REQUIRED mode#

Wrapping your website routes using <SessionAuth /> should be enough for this to work. If the user's email is not verified, SuperTokens will automatically redirect the user to the email verification screen.

If using OPTIONAL mode#

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

const VerifiedRoute = (props: React.PropsWithChildren<any>) => {
return (
<SessionAuth>
<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 === EmailVerificationClaim.id)) {
return <div>You cannot access this page because your email address is not verified.</div>
}

// We show the protected route since all claims validators have
// passed implying that the user has verified their email.
return <div>{props.children}</div>;
}

Above we are creating a generic component called VerifiedRoute which enforces that its child components can only be rendered if the user has a verified email address.

In the VerifiedRoute component, we use the SessionAuth wrapper to ensure that the session exists. The EmailVerificationClaim validator is automatically added to the <SessionAuth> component if the EmailVerification recipe has been initialized.

Finally, we check the result of the validation in the InvalidClaimHandler component which displays "You cannot access this page because your email address is not verified." if the EmailVerificationClaim validator failed.

If all validation passes, we render the props.children component.

note

You can extend the VerifiedRoute component to check for other types of validators as well. This component can then be reused to protect all of your app's components (In this case, you may want to rename this component to something more appropriate, like ProtectedRoute).

Manually checking verification status

If you want to have more complex access control, you can either create your own validator, or you can get the boolean from the session as follows, and check it yourself:

import Session from "supertokens-auth-react/recipe/session";
import {EmailVerificationClaim} from "supertokens-auth-react/recipe/emailverification"

function ProtectedComponent() {
let claimValue = Session.useClaimValue(EmailVerificationClaim)
if (claimValue.loading || !claimValue.doesSessionExist) {
return null;
}
let isEmailVerified = claimValue.value;
if (isEmailVerified !== undefined && isEmailVerified) {
//...
} else {
//...
}
}