Protecting frontend routes
#
Requiring a session to access a route- ReactJS
- Angular
- Vue
You can use the doesSessionExist
function to check if a session exists in all your routes.
import Session from 'supertokens-web-js/recipe/session';
async function doesSessionExist() {
if (await Session.doesSessionExist()) {
// user is logged in
} else {
// user has not logged in yet
}
}
You can wrap your components with the <SessionAuth>
react component. This will ensure that your component renders only if the user is logged in. If they are not logged in, the user will be redirected to the login page.
import React from "react";
import {
BrowserRouter,
Routes,
Route,
} from "react-router-dom";
import { SuperTokensWrapper } from "supertokens-auth-react";
import { SessionAuth } from "supertokens-auth-react/recipe/session";
import MyDashboardComponent from "./dashboard";
class App extends React.Component {
render() {
return (
<SuperTokensWrapper>
<BrowserRouter>
<Routes>
<Route path="/dashboard" element={
<SessionAuth>
{/*Components that require to be protected by authentication*/}
<MyDashboardComponent />
</SessionAuth>
} />
</Routes>
</BrowserRouter>
</SuperTokensWrapper>
);
}
}
#
Optional session on a routeYou can provide the requireAuth={false}
prop when using <SessionAuth>
as shown below:
import React from "react";
import {
BrowserRouter,
Routes,
Route,
} from "react-router-dom";
import { SuperTokensWrapper } from "supertokens-auth-react";
import Session, { SessionAuth } from "supertokens-auth-react/recipe/session";
class App extends React.Component {
render() {
return (
<SuperTokensWrapper>
<BrowserRouter>
<Routes>
<Route path="/dashboard" element={
<SessionAuth requireAuth={false}>
<MyDashboardComponent />
</SessionAuth>
} />
</Routes>
</BrowserRouter>
</SuperTokensWrapper>
);
}
}
function MyDashboardComponent(props: any) {
let sessionContext = Session.useSessionContext();
if (sessionContext.loading) {
return null;
}
if (sessionContext.doesSessionExist) {
// TODO:
} else {
// TODO:
}
return null;
}
You can use the doesSessionExist
function to check if a session exists in all your routes.
import Session from 'supertokens-web-js/recipe/session';
async function doesSessionExist() {
if (await Session.doesSessionExist()) {
// user is logged in
} else {
// user has not logged in yet
}
}
#
Verifying the claims of a sessionSometimes, you may also want to check if there are certain claims in the session before granting access to a route. For example, you may want to check that the session has the admin role claim for certain APIs, or that the user has completed 2FA.
This can be done using our session claims validator feature. Let's take an example of using the user roles claim to check if the session has the admin claim:
- ReactJS
- Angular
- Vue
import Session from "supertokens-web-js/recipe/session";
import { UserRoleClaim, /*PermissionClaim*/ } from "supertokens-web-js/recipe/userroles";
async function shouldLoadRoute(): Promise<boolean> {
if (await Session.doesSessionExist()) {
let validationErrors = await Session.validateClaims({
overrideGlobalClaimValidators: (globalValidators) =>
[...globalValidators,
UserRoleClaim.validators.includes("admin"),
/* PermissionClaim.validators.includes("modify") */
]
});
if (validationErrors.length === 0) {
// user is an admin
return true;
}
for (const err of validationErrors) {
if (err.id === UserRoleClaim.id) {
// user roles claim check failed
} else {
// some other claim check failed (from the global validators list)
}
}
}
// either a session does not exist, or one of the validators failed.
// so we do not allow access to this page.
return false
}
- We call the
validateClaims
function with theUserRoleClaim
validator which makes sure that the user has anadmin
role. - The
globalValidators
represents other validators that apply to all calls to thevalidateClaims
function. 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.
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-web-js/recipe/session";
import { UserRoleClaim } from "supertokens-web-js/recipe/userroles";
async function shouldLoadRoute(): Promise<boolean> {
if (await Session.doesSessionExist()) {
let roles = await Session.getClaimValue({claim: UserRoleClaim});
if (Array.isArray(roles) && roles.includes("admin")) {
// User is an admin
return true;
}
}
// either a session does not exist, or the user is not an admin
return false
}
import React from "react";
import { SessionAuth } from 'supertokens-auth-react/recipe/session';
import { AccessDeniedScreen } from 'supertokens-auth-react/recipe/session/prebuiltui';
import { UserRoleClaim, /*PermissionClaim*/ } from 'supertokens-auth-react/recipe/userroles';
const AdminRoute = (props: React.PropsWithChildren<any>) => {
return (
<SessionAuth
accessDeniedScreen={AccessDeniedScreen}
overrideGlobalClaimValidators={(globalValidators) => [
...globalValidators, UserRoleClaim.validators.includes("admin"),
]
}>
{props.children}
</SessionAuth>
);
}
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. If all validation passes, we render the props.children
component. If the claim validation has failed, it will display the AccessDeniedScreen
component instead of rendering the children. You can also pass your own custom component to the accessDeniedScreen
prop.
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
).
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 (Array.isArray(roles) && roles.includes("admin")) {
// User is an admin
} else {
// User doesn't have any roles, or is not an admin..
}
}
import Session from "supertokens-web-js/recipe/session";
import { UserRoleClaim, /*PermissionClaim*/ } from "supertokens-web-js/recipe/userroles";
async function shouldLoadRoute(): Promise<boolean> {
if (await Session.doesSessionExist()) {
let validationErrors = await Session.validateClaims({
overrideGlobalClaimValidators: (globalValidators) =>
[...globalValidators,
UserRoleClaim.validators.includes("admin"),
/* PermissionClaim.validators.includes("modify") */
]
});
if (validationErrors.length === 0) {
// user is an admin
return true;
}
for (const err of validationErrors) {
if (err.id === UserRoleClaim.id) {
// user roles claim check failed
} else {
// some other claim check failed (from the global validators list)
}
}
}
// either a session does not exist, or one of the validators failed.
// so we do not allow access to this page.
return false
}
- We call the
validateClaims
function with theUserRoleClaim
validator which makes sure that the user has anadmin
role. - The
globalValidators
represents other validators that apply to all calls to thevalidateClaims
function. 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.
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-web-js/recipe/session";
import { UserRoleClaim } from "supertokens-web-js/recipe/userroles";
async function shouldLoadRoute(): Promise<boolean> {
if (await Session.doesSessionExist()) {
let roles = await Session.getClaimValue({claim: UserRoleClaim});
if (Array.isArray(roles) && roles.includes("admin")) {
// User is an admin
return true;
}
}
// either a session does not exist, or the user is not an admin
return false
}
feature
You can also build your own custom claim validators based on your app's requirements.