What is the preferred/recommended way to implement protected routes?
I gave https://tanstack.com/router/latest/docs/framework/react/guide/authenticated-routes a read and was still unsure what the preferred way would be, using Tanstack Router.
The _authenticated.tsx is rather simple but fits really well. And I'm still unsure what the approach would be if I had a RBAC requirement for my routes. In a way that people without the expected claims/roles would not be able to view these routes.
Authenticated Routes | TanStack Router React Docs
Authentication is an extremely common requirement for web applications. In this guide, we'll walk through how to use TanStack Router to build protected routes, and how to redirect users to login if they try to access them.
The route.beforeLoad Option
15 Replies
like-gold•17mo ago
Could you just throw a not found error for unauthenticated users?
quickest-silverOP•17mo ago
what
like-gold•17mo ago
You can have a layout route that will check the user has the necessary roles to access any child routes. You can use the
notFound()
function to show a 404 page for anyone without the necessary roles. https://tanstack.com/router/latest/docs/framework/react/api/router/notFoundFunction#notfound-functionnotFound function | TanStack Router React Docs
The notFound function returns a new NotFoundError object that can be either returned or thrown from places like a Route's beforeLoad or loader callbacks to trigger the notFoundComponent.
notFound options
like-gold•17mo ago
If you have multiple sets of roles, you could create multiple layout routes for each set of roles.
quickest-silverOP•17mo ago
Oh yeah sure
But then how would I check what are the required roles for the given route?
Without having to hardcode everything in the layout route
any suggestions @camburris ?
ratty-blush•17mo ago
You can setup your auth context to store the user if they are logged in (null otherwise) and store the user roles as part of that user object. Then in the route you can do something like
or at least thats how I've been doing it
quickest-silverOP•17mo ago
My problem is that I have really granular permissions
so it'd be your scenario but with kind of with one role per page
and I don't want to have these permissions hardcoded in the layout
yappiest-sapphire•17mo ago
Why hardcoding in the layout? Inside
beforeLoad
you have access to the context, you can move all your logic inside a hook and just call something like auth.isAuthorized(user, location.href)
in the route as in the example abovequickest-silverOP•17mo ago
Doesn't this still imply I'll have it hardcoded somewhere? All of them, together.
I was hoping to be able to declare each required claim or role in the specific route file.
ambitious-aqua•17mo ago
https://discord.com/channels/719702312431386674/1237722729973678191
@sns you can check what i did, its working without problem so mb you can get something from it for your project ; )
quickest-silverOP•17mo ago
I'll take a look thanks
Nah it still doesn't solve my issue sadly
I suppose I could use some "reflection" to load the permissions from each route dynamically and aggregate them into a map. Either that or writing a build script and I'm not a fan of this idea.
yappiest-sapphire•17mo ago
Why you can't just write the rules in a map directly?
Can you share how the definition of permissions for a single route looks like? I have the feeling you're overcomplicating it
quickest-silverOP•17mo ago
I can. I just wanted to have each route containing the permission they need. And aggregate it all automatically.
It's just claims
yappiest-sapphire•17mo ago
Ah ok, got it! I don't know if maybe you can append some kind of metadata to routes and try to grab them all from the generated routes 🤔
quickest-silverOP•17mo ago
btw apparently not even this is working for some reason
gave this a quick try and it appears as if it's not going through my _authenticated.tsx
Nothing really happens
This is my root.tsx:
And this is the generated
routeTree
```ts
import { createFileRoute } from '@tanstack/react-router'
// Import Routes
import { Route as rootRoute } from './routes/root'
import { Route as AuthenticatedImport } from './routes/_authenticated'
// Create Virtual Routes
const LoginLazyImport = createFileRoute('/login')()
const AboutLazyImport = createFileRoute('/about')()
const IndexLazyImport = createFileRoute('/')()
// Create/Update Routes
const LoginLazyRoute = LoginLazyImport.update({
path: '/login',
getParentRoute: () => rootRoute,
} as any).lazy(() => import('./routes/login.lazy').then((d) => d.Route))
const AboutLazyRoute = AboutLazyImport.update({
path: '/about',
getParentRoute: () => rootRoute,
} as any).lazy(() => import('./routes/about.lazy').then((d) => d.Route))
const AuthenticatedRoute = AuthenticatedImport.update({
id: '/_authenticated',
getParentRoute: () => rootRoute,
} as any)
const IndexLazyRoute = IndexLazyImport.update({
path: '/',
getParentRoute: () => rootRoute,
} as any).lazy(() => import('./routes/index.lazy').then((d) => d.Route))
// Populate the FileRoutesByPath interface
declare module '@tanstack/react-router' {
interface FileRoutesByPath {
'/': {
preLoaderRoute: typeof IndexLazyImport
parentRoute: typeof rootRoute
}
'/_authenticated': {
preLoaderRoute: typeof AuthenticatedImport
parentRoute: typeof rootRoute
}
'/about': {
preLoaderRoute: typeof AboutLazyImport
parentRoute: typeof rootRoute
}
'/login': {
preLoaderRoute: typeof LoginLazyImport
parentRoute: typeof rootRoute
}
}
}
// Create and export the route tree
export const routeTree = rootRoute.addChildren([
IndexLazyRoute,
AboutLazyRoute,
LoginLazyRoute,
])
``
Wtf is happening
oh yeah it's not going through
_authenticated.tsx's
beforeLoad at all
yeah idk what is happening
huh so my routes would need to be
_authenticated.XXX.tsx`?