Protecting backend APIs and website routes
CAUTION
This information only applies to scenarios in which you are using SuperTokens Session Access Tokens.
If you are implementing Unified Login you will have to manually check the email_verified
claim on the OAuth2 Access Tokens. Please read the separate page that shows you how to verify the token.
Protecting backend API routes
Add email verification checks to all API routes
If you want to protect all your backend API routes with email verification checks, set the mode
to REQUIRED
in the EmailVerification
config. Routes protected with the verifySession
middleware will now additionally check for email verification status.
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()
]
});
In case you have set the email verification mode to REQUIRED
but want to disable the check for a specific route, you can make the following changes to the verifySession
middleware:
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 email verification checks to specific API routes
If you want to protect specific backend API routes with email verification checks, set the mode
to OPTIONAL
in the EmailVerification
config. You will then override the verifySession
middleware protecting the route to check for email verification status.
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
}
);
What type of UI are you using?
Protecting frontend routes
Protect all frontend routes
Set the email verification mode to REQUIRED
and wrap your website routes using <SessionAuth />
. If the user's email is not verified, SuperTokens will automatically redirect the user to the email verification screen.
Protect specific frontend routes
Set the email verification mode to OPTIONAL
. We will create a generic component called VerifiedRoute
which enforces that its child components can only be rendered if the user has a verified email address.
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.id === EmailVerificationClaim.id)) {
// Alternatively you could redirect the user to the email verification screen to trigger the verification email
// Note: /auth/verify-email is the default email verification path
// window.location.assign("/auth/verify-email")
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>;
}
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. Alternatively you could also redirect the user to the default email verification path to trigger the sending of the verification email.
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 {
// Redirect the user the email verification path to send the verification email
// Note: /auth/verify-email is the default email verification path
window.location.assign("/auth/verify-email")
}
}