Protected Routes and Authorisation
IntermediateA route guard is a UX affordance, not a security boundary. It hides what the user cannot use and sends them somewhere sensible — the server still decides what they may actually do.
Overview
Every application eventually needs pages only some people can see, and the React part is a wrapper route that checks the session and redirects. The important framing is that this is not security: the bundle ships to everyone, any user can call your API directly, and a route guard is trivially bypassed. It exists so authorised users are not shown doors they cannot open and unauthorised users get a sensible redirect. Every protected route must correspond to an endpoint that enforces the same rule server-side.
The Guard
A wrapper route, using the three-state auth from the Data category.
function RequireAuth() {
const { user, isChecking } = useAuth()
const location = useLocation()
if (isChecking) return <FullPageSpinner /> // not signed out — unknown
if (!user) {
return <Navigate to="/login" replace state={{ from: location }} />
}
return <Outlet />
}
// Wrap the protected subtree
{
element: <RequireAuth />,
children: [
{ path: 'dashboard', element: <Dashboard /> },
{ path: 'account', element: <Account /> },
],
}
// Return the user where they were going after sign-in
const from = location.state?.from?.pathname ?? '/dashboard'
navigate(from, { replace: true })
// replace on the redirect, or back returns them to the guard,
// which redirects again — a loop the user cannot escape.Roles and Subscription Tiers
The same shape, with a capability check instead of a presence check.
function RequireRole({ roles }) {
const { user, isChecking } = useAuth()
if (isChecking) return <FullPageSpinner />
if (!user) return <Navigate to="/login" replace />
if (!roles.includes(user.role)) return <Forbidden /> // 403, not a redirect
return <Outlet />
}
<Route element={<RequireRole roles={['admin']} />}>
// Signed out -> send them to sign in.
// Signed in but not permitted -> tell them, do not bounce them.
// A silent redirect looks like a broken link.
// For a paid tier, an upgrade prompt beats a wall
if (!isPro) return <UpgradePrompt feature="Solutions" />
// Hide the navigation too, or users click into a 403 repeatedly
{user?.role === 'admin' && <NavLink to="/admin">Admin</NavLink>}
// And the point that must be stated in an interview: the API
// enforces the same rule. Hiding the link does not protect the data —
// the bundle is public and the endpoint is reachable with curl.Not Losing the User's Work
Guards that fire mid-session, and blocking navigation away from unsaved changes.
// A session can expire while the user is typing. Do not redirect
// them off a form with unsaved input — prompt instead.
{sessionExpired && <ReauthDialog onSuccess={retry} />}
// Blocking navigation away from a dirty form
const blocker = useBlocker(
({ currentLocation, nextLocation }) =>
isDirty && currentLocation.pathname !== nextLocation.pathname,
)
{blocker.state === 'blocked' && (
<ConfirmDialog
message="You have unsaved changes."
onConfirm={blocker.proceed}
onCancel={blocker.reset}
/>
)}
// beforeunload covers closing the tab; useBlocker covers in-app
// navigation. You need both for full coverage.Key Points to Remember
- 1A route guard is a UX affordance — the API must enforce the same rule, because the bundle is public
- 2Check the auth "checking" state first, or the guard redirects signed-in users on every reload
- 3Redirect with replace and carry the intended destination so sign-in returns the user where they were going
- 4Signed out means redirect to sign in; signed in but not permitted means show a forbidden or upgrade screen
- 5Prompt to reauthenticate in place rather than navigating away from a form with unsaved input
Interview Questions
Sign in to ask AriaIs a protected route in React a security measure? Explain.
Why should a redirect after sign-in use replace?
How do you handle a session expiring while the user is filling in a long form?
Ask Aria about Protected Routes and Authorisation
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.