T
TanStack6mo ago
unwilling-turquoise

using better-auth to protect the entire route

I have implemented better-auth for tanstack start (https://www.better-auth.com/docs/integrations/tanstack) and I want to protect all pages in the route, how can I do that?
TanStack Start Integration | Better Auth
Integrate Better Auth with TanStack Start.
6 Replies
metropolitan-bronze
metropolitan-bronze6mo ago
I do this in an _auth.tsx file in the beforeload function
export const Route = createFileRoute("/_auth")({
component: AuthLayout,
beforeLoad: async ({ context: { user } }) => {
if (user) {
throw redirect({
to: "/",
});
}
},
});
export const Route = createFileRoute("/_auth")({
component: AuthLayout,
beforeLoad: async ({ context: { user } }) => {
if (user) {
throw redirect({
to: "/",
});
}
},
});
in my _root.tsx:
beforeLoad: async () => {
try {
const session = await fetchSessionFn();
return session;
} catch (error) {
console.error("Failed to fetch session:", error);
// You can return a default session object or null
return null;
}
},
beforeLoad: async () => {
try {
const session = await fetchSessionFn();
return session;
} catch (error) {
console.error("Failed to fetch session:", error);
// You can return a default session object or null
return null;
}
},
where fetchsession:
export const fetchSessionFn = createServerFn({ method: "GET" }).handler(
async () => {
const res = await fetch(`${MERCURY_URL}/api/auth/get-session`, {
headers: {
//get the cookie from the request
cookie: getHeader("cookie") || "",
},
});

if (!res.ok) {
throw new Error("Not authenticated");
}

const session = (await res.json()) as Session;

return session;
},
);
export const fetchSessionFn = createServerFn({ method: "GET" }).handler(
async () => {
const res = await fetch(`${MERCURY_URL}/api/auth/get-session`, {
headers: {
//get the cookie from the request
cookie: getHeader("cookie") || "",
},
});

if (!res.ok) {
throw new Error("Not authenticated");
}

const session = (await res.json()) as Session;

return session;
},
);
you can probably use the better auth client instead to return the session authClient.getSession()
fascinating-indigo
fascinating-indigo6mo ago
You can also cache it with tanstack query
unwilling-turquoise
unwilling-turquoiseOP6mo ago
@bxr getSession with Auth client always returns null, even when cookie is set , not sure why Do you have an example of this? I recently started using tanstack start
fascinating-indigo
fascinating-indigo6mo ago
Something like this (mind you I have never used better auth)
const getUser = createServerFn({ method: "GET" }).handler(async () => {
const { headers } = getWebRequest()!;
const session = await auth.api.getSession({ headers });

return session?.user || null;
});

export const Route = createRootRouteWithContext<{
queryClient: QueryClient;
user: Awaited<ReturnType<typeof getUser>>;
}>()({
beforeLoad: async ({ context }) => {
const user = await context.queryClient.fetchQuery({
queryKey: ["user"],
queryFn: ({ signal }) => getUser({ signal }),
}); // we're using react-query for caching, see router.tsx
return { user };
},
const getUser = createServerFn({ method: "GET" }).handler(async () => {
const { headers } = getWebRequest()!;
const session = await auth.api.getSession({ headers });

return session?.user || null;
});

export const Route = createRootRouteWithContext<{
queryClient: QueryClient;
user: Awaited<ReturnType<typeof getUser>>;
}>()({
beforeLoad: async ({ context }) => {
const user = await context.queryClient.fetchQuery({
queryKey: ["user"],
queryFn: ({ signal }) => getUser({ signal }),
}); // we're using react-query for caching, see router.tsx
return { user };
},
fascinating-indigo
fascinating-indigo6mo ago
The above is copied from this repo: https://github.com/dotnize/react-tanstarter
GitHub
GitHub - dotnize/react-tanstarter: minimal TanStack Start template ...
minimal TanStack Start template with React 19, Better Auth, Drizzle ORM, shadcn/ui - dotnize/react-tanstarter
fascinating-indigo
fascinating-indigo6mo ago
All credit of course to dotnize

Did you find this page helpful?