Capítulo 17 de 24
This example guards a group of routes behind login using a pathless layout route (_auth.tsx) whose beforeLoad checks auth context and throws a redirect to /login (carrying the original URL) when the user isn't authenticated. The login route mirrors this by redirecting already-authenticated users away from itself.
createFileRoute)@tanstack/react-router (beforeLoad, redirect, useRouterState), @tanstack/router-plugin, zod (search param validation), @tanstack/react-router-devtoolssrc/auth.tsx defines a AuthProvider/useAuth context backed by localStorage; src/routes/_auth.tsx is a pathless layout route that gates its children (/dashboard, /invoices in this example's tree) behind context.auth.isAuthenticated; src/routes/login.tsx handles the credential form and redirect-back flow.// src/auth.tsx
export function useAuth() {
const context = React.useContext(AuthContext)
if (!context) {
throw new Error('useAuth must be used within an AuthProvider')
}
return context
}
// src/routes/_auth.tsx
export const Route = createFileRoute('/_auth')({
beforeLoad: ({ context, location }) => {
if (!context.auth.isAuthenticated) {
throw redirect({
to: '/login',
search: {
redirect: location.href,
},
})
}
},
component: AuthLayout,
})
The login route reverses the check (bounce authenticated users away) and returns to the originally requested page on success:
// src/routes/login.tsx
export const Route = createFileRoute('/login')({
validateSearch: z.object({
redirect: z.string().optional().catch(''),
}),
beforeLoad: ({ context, search }) => {
if (context.auth.isAuthenticated) {
throw redirect({ to: search.redirect || fallback })
}
},
component: LoginComponent,
})
// inside the form submit handler:
await auth.login(username)
await router.invalidate()
await sleep(1) // wait for auth state to propagate before navigating
await navigate({ to: search.redirect || fallback })
beforeLoad runs before a route (and its children) load, and throw redirect(...) there aborts the pending navigation and redirects instead of rendering; context.auth is supplied to the router at creation time so every route's beforeLoad/loader can read auth state without prop drilling._auth.tsx, no path segment of its own) so every nested route under it inherits the same beforeLoad check without repeating it per-route.search: { redirect: location.href } on the redirect to /login, then read it back in login.tsx's validateSearch/beforeLoad to bounce the user to where they meant to go after signing in.router.invalidate() before navigating so route loaders (and other beforeLoad checks) re-run against the fresh auth context instead of stale cached state.beforeLoad redirects away from /login when already authenticated, preventing a logged-in user from seeing the login form again via back-navigation or a stale link.beforeLoad vs useBlocker) to stop or redirect a navigation before it completes.utils/auth.tsx login/auth utility used across a broader multi-feature app; this chapter's _auth.tsx pattern is the minimal, focused version of the same idea.