Eva
Eva•4mo ago

Redirecting unauthenticated users? Convex Auth + TanStack Router

Hi! Hopefully this is an easy one, but I'm new to both Convex, TanStack, and this is my first time ever setting up authentication! So trying to follow best pratices and reading but getting a little lost. I have a /settings route and I want to redirect unauthenticated users away to /signin. I found the docs in TanStack Router for how to set up a redirect on beforeLoad but I don't know how to check for isAuthenticated() using Convex Auth. Help? https://tanstack.com/router/latest/docs/framework/react/guide/authenticated-routes#redirecting
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
3 Replies
Eva
EvaOP•4mo ago
Would love to see a best-practice example of managing authentication and loading state for a page Ah, I was able to get this set up. In main.tsx:
import { ConvexAuthProvider } from "@convex-dev/auth/react";
import { RouterProvider, createRouter } from "@tanstack/react-router";
import { ConvexReactClient, useConvexAuth } from "convex/react";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { routeTree } from "./routeTree.gen";

const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL);

const router = createRouter({
routeTree,
context: {
auth: undefined!,
},
});

declare module "@tanstack/react-router" {
interface Register {
router: typeof router;
}
}

const InnerApp = () => {
const auth = useConvexAuth();
return <RouterProvider router={router} context={{ auth }} />;
};

const rootElement = document.getElementById("root")!;
if (!rootElement.innerHTML) {
const root = createRoot(rootElement);
root.render(
<StrictMode>
<ConvexAuthProvider client={convex}>
<InnerApp />
</ConvexAuthProvider>
</StrictMode>,
);
}
import { ConvexAuthProvider } from "@convex-dev/auth/react";
import { RouterProvider, createRouter } from "@tanstack/react-router";
import { ConvexReactClient, useConvexAuth } from "convex/react";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { routeTree } from "./routeTree.gen";

const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL);

const router = createRouter({
routeTree,
context: {
auth: undefined!,
},
});

declare module "@tanstack/react-router" {
interface Register {
router: typeof router;
}
}

const InnerApp = () => {
const auth = useConvexAuth();
return <RouterProvider router={router} context={{ auth }} />;
};

const rootElement = document.getElementById("root")!;
if (!rootElement.innerHTML) {
const root = createRoot(rootElement);
root.render(
<StrictMode>
<ConvexAuthProvider client={convex}>
<InnerApp />
</ConvexAuthProvider>
</StrictMode>,
);
}
In routes/__root.tsx:
import {
Outlet,
createRootRouteWithContext,
} from "@tanstack/react-router";
import { TanStackRouterDevtools } from "@tanstack/router-devtools";
// ConvexAuthState keeps everything typesafe
import type { ConvexAuthState } from "convex/react";
import { RouterProvider } from "react-aria-components";

// Pass down type definitions
interface RouterContext {
auth: ConvexAuthState;
}

export const Route = createRootRouteWithContext<RouterContext>()({
component: Root,
});

function Root() {
return (
<>
<Outlet />
<TanStackRouterDevtools />
</>
);
}
import {
Outlet,
createRootRouteWithContext,
} from "@tanstack/react-router";
import { TanStackRouterDevtools } from "@tanstack/router-devtools";
// ConvexAuthState keeps everything typesafe
import type { ConvexAuthState } from "convex/react";
import { RouterProvider } from "react-aria-components";

// Pass down type definitions
interface RouterContext {
auth: ConvexAuthState;
}

export const Route = createRootRouteWithContext<RouterContext>()({
component: Root,
});

function Root() {
return (
<>
<Outlet />
<TanStackRouterDevtools />
</>
);
}
On routes/settings.tsx:
import { createFileRoute, redirect } from "@tanstack/react-router";

export const Route = createFileRoute("/settings")({
beforeLoad: ({ context }) => {
// context.auth includes type safety and Intellisense
if (!context.auth.isAuthenticated) {
throw redirect({
to: "/signin",
});
}
},
component: SettingsRoute,
});

function SettingsRoute() {
// ...
}
import { createFileRoute, redirect } from "@tanstack/react-router";

export const Route = createFileRoute("/settings")({
beforeLoad: ({ context }) => {
// context.auth includes type safety and Intellisense
if (!context.auth.isAuthenticated) {
throw redirect({
to: "/signin",
});
}
},
component: SettingsRoute,
});

function SettingsRoute() {
// ...
}
ballingt
ballingt•4mo ago
Thanks for sharing this @Eva! This is helpful for providing instructions about this, which hopefully get up this week.
Eva
EvaOP•4mo ago
Awesome! Convex Auth (and Convex generally) have been amazing so far. Was able to set up magic links without any prior knowledge of auth 🤩