Is there a recommended way to implement Authenticated Routes? #364
Replies: 3 comments 4 replies
-
This has the 2nd most upvotes of all time with no response so here is a gentle bump in case it was forgotten about 😄 |
Beta Was this translation helpful? Give feedback.
-
After some more testing, I think using a config-based router is making is harder than it needs to be. I switch over to non-config-based and was able to do this: An AuthGuard component to wrap private routes function AuthGuard(props: ParentProps): JSX.Element {
const [isAuthenticated, setIsAuthenticated] = createSignal(false);
const navigate = useNavigate();
const location = useLocation();
async function performAuthCheck() {
setIsAuthenticated(false);
const auth = await wait(3000);
if (auth) {
setIsAuthenticated(true);
console.log(`Authenticated: ${new Date()}`);
} else {
navigate("/login");
}
}
createRenderEffect(on(() => location.pathname, performAuthCheck));
return (
<>
<Show when={isAuthenticated()} fallback={<div>FALLLBACK</div>}>
{props.children}
</Show>
</>
);
} Routes definition export function Router(props: RouterProps) {
return (
<SolidRouter {...props}>
{/* Public pages */}
<Route path="/" component={lazy(() => import("./pages/Home"))} />
<Route path="/login" component={() => <div>Login Page</div>} />
<Route path="/*404" component={lazy(() => import("./pages/NotFound"))} />
{/* Private / Authenticated pages */}
<Route path="/" component={AuthGuard}>
<Route path="/:entity">
<Route path="/" component={lazy(() => import("./pages/Profile"))} />
<Route
path="/reports"
component={lazy(() => import("./pages/Profile/UserReports"))}
/>
<Route
path="/projects"
component={lazy(() => import("./pages/Profile/UserProjects"))}
/>
</Route>
</Route>
</SolidRouter>
);
} |
Beta Was this translation helpful? Give feedback.
-
This is a setup that I use. AuthGuard is a layout component which does not affect the url. export default function AuthGuard(props: ParentProps) {
// will return true if authenticated, false if not, undefined when not fetched yet
const isAuthenticated = createAsync(() => getIsAuthenticated(), {
deferStream: true,
});
const location = useLocation();
onMount(() => {
function refreshWhenVisible() {
if (!document.hidden && isAuthenticated()) {
revalidate(getIsAuthenticated.key);
}
}
//revalidate after focus comes back to app's browser tab
document.addEventListener('visibilitychange', refreshWhenVisible);
//refresh the token before it expires
const interval = setInterval(refreshWhenVisible, 1000 * 60 * 15);
onCleanup(() => {
document.addEventListener('visibilitychange', refreshWhenVisible);
clearInterval(interval);
});
});
return (
<Suspense>
<Switch fallback={'checking auth...'}>
<Match when={isAuthenticated()}>{props.children}</Match>
<Match when={isAuthenticated() === false}>
{/* You could also render your Login component instead of redirecting */}
<Navigate href={`/login?redirectTo=${location.pathname}`} />
</Match>
</Switch>
</Suspense>
);
} Here's a stackblitz if you want to see it in action: |
Beta Was this translation helpful? Give feedback.
-
Assume you have a SPA that includes several public
Routes
and several privateRoutes
that require an authenticated user. Ideally, I'd like to wrap all of those protectedRoutes
under a single component that can validate the user every time the page/route is changed.Route
offersload:RouteLoadFunc
:But this implies I need to add some sort of "
verifyUser()
" to every singleRoute
I define. Is there a more canonical way to implement this in the latest version of solidjs-router? For a small number of routes this is manageable, but for a complicated or deeply nested route configuration, having to add that prop to everyRoute
isn't ideal.The goal is to verify the authentication status of the user on every route load, redirect or navigation.
Beta Was this translation helpful? Give feedback.
All reactions