Skip to main content

Protecting API and website routes

Protecting API routes#

In your API routes you:

  1. Verify that a session exists
  2. Validate that the roles/permissions saved in the access token payload have the appropriate value
import { verifySession } from "supertokens-node/recipe/session/framework/express";import express from "express";import { SessionRequest } from "supertokens-node/framework/express";import UserRoles from "supertokens-node/recipe/userroles";
let app = express();
app.post(    "/update-blog",    verifySession({        overrideGlobalClaimValidators: async (globalValidators) => [            ...globalValidators,            UserRoles.UserRoleClaim.validators.includes("admin"),            // UserRoles.PermissionClaim.validators.includes("edit")        ],    }),    async (req: SessionRequest, res) => {        // All validator checks have passed and the user is an admin.    });
  • We add the UserRoleClaim validator to the verifySession function which makes sure that the user has an admin role.
  • The globalValidators represents other validators that apply to all API routes by default. This may include a validator that enforces that the user's email is verified (if enabled by you).
  • We can also add a PermissionClaim validator to enforce a permission.
Manually checking rolesIf you want to have more complex access control, you can either create your own validator, or you can get the roles list from the session as follows, and check the list yourself:
import express from "express";import { verifySession } from "supertokens-node/recipe/session/framework/express";import { SessionRequest } from "supertokens-node/framework/express";import UserRoles from "supertokens-node/recipe/userroles";import { Error as STError } from "supertokens-node/recipe/session"
let app = express();
app.post("/update-blog", verifySession(), async (req: SessionRequest, res) => {    const roles = await req.session!.getClaimValue(UserRoles.UserRoleClaim);        if (roles === undefined || !roles.includes("admin")) {        // this error tells SuperTokens to return a 403 to the frontend.        throw new STError({            type: "INVALID_CLAIMS",            message: "User is not an admin",            payload: [{                id: UserRoles.UserRoleClaim.key            }]        })    }    // user is an admin..});

Protecting website routes#

On your frontend:

  1. Verify that a session exists
  2. Use the roles / permissions claim validators to enforce certain roles and permissions.
  3. If the user doesn't have the right roles, we show them an error message indicating they don't have access.
import React from "react";import { SessionAuth, useSessionContext } from 'supertokens-auth-react/recipe/session';import { UserRoleClaim, /*PermissionClaim*/ } from 'supertokens-auth-react/recipe/userroles';
const AdminRoute = (props: React.PropsWithChildren<any>) => {    return (        <SessionAuth            overrideGlobalClaimValidators={(globalValidators) =>                [...globalValidators,                UserRoleClaim.validators.includes("admin"),                    /* PermissionClaim.validators.includes("modify") */                ]            }        >            <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 === UserRoleClaim.id)) {        return <div>You cannot access this page because you are not an admin.</div>    }
    // We show the protected route since all claims validators have    // passed implying that the user is an admin.    return <div>{props.children}</div>;}

Above we are creating a generic component called AdminRoute which enforces that its child components can only be rendered if the user has the admin role.

In the AdminRoute component, we use the SessionAuth wrapper to ensure that the session exists. We also add the UserRoleClaim validator to the <SessionAuth> component which checks if the validators pass or not.

Finally, we check the result of the validation in the InvalidClaimHandler component which displays "You cannot access this page because you are not an admin." if the UserRoleClaim claim failed.

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

note

You can extend the AdminRoute 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 roles

If you want to have more complex access control, you can get the roles list from the session as follows, and check the list yourself:

import Session from "supertokens-auth-react/recipe/session";import {UserRoleClaim} from "supertokens-auth-react/recipe/userroles"
function ProtectedComponent() {    let claimValue = Session.useClaimValue(UserRoleClaim)    if (claimValue.loading || !claimValue.doesSessionExist) {        return null;    }    let roles = claimValue.value;    if (roles !== undefined && roles.includes("admin")) {        // User is an admin    } else {        // User doesn't have any roles, or is not an admin..    }}
Which frontend SDK do you use?
supertokens-web-js / mobile
supertokens-auth-react