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
vicious-gold•2y ago
Could you just throw a not found error for unauthenticated users?
optimistic-goldOP•2y ago
what
vicious-gold•2y 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
vicious-gold•2y ago
If you have multiple sets of roles, you could create multiple layout routes for each set of roles.
optimistic-goldOP•2y 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 ?
deep-jade•2y 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
optimistic-goldOP•2y 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
fascinating-indigo•2y 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 aboveoptimistic-goldOP•2y 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.
conscious-sapphire•2y 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 ; )
optimistic-goldOP•2y 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.
fascinating-indigo•2y 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
optimistic-goldOP•2y ago
I can. I just wanted to have each route containing the permission they need. And aggregate it all automatically.
It's just claims
fascinating-indigo•2y 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 🤔
optimistic-goldOP•2y 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`?