Protect frontend routes
Protect frontend routes by requiring user sessions and verifying session claims for access control.
Before you start
This guide only applies to scenarios which involve SuperTokens Session Access Tokens.
What type of UI are you using?
Protect a route
You can wrap your components with the <SessionAuth>
react component.
This ensures that your component renders only if the user has logged in.
If they are not logged in, the user gets 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 requirement
You 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;
}
Check the claims of a session
Sometimes, 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.
You can achieve this using the session claims validator feature. Let's take an example of using the user roles claim to check if the session has the admin claim:
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, you create a generic component called AdminRoute
, which enforces that its child components render only if the user has the admin role.
In the AdminRoute
component, the SessionAuth
wrapper ensures that the session exists.
The UserRoleClaim
validator is also added to the <SessionAuth>
component, which checks if the validators pass or not.
If all validation passes, the props.children
component renders.
If the claim validation has failed, it displays the AccessDeniedScreen
component instead of rendering the children.
You can also pass your own custom component to the accessDeniedScreen
prop.
You can extend the AdminRoute
component to check for other types of validators as well.
You can then reuse this component to protect all 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..
}
}
You can also build your own custom claim validators based on your app's requirements.