T
TanStack7mo ago
passive-yellow

Can I redirect from the index route?

In nextjs, I can do this to not allow the user to load the index route.
import { redirect } from 'next/navigation';

export default function HomePage() {
redirect('/dashboard');
}
import { redirect } from 'next/navigation';

export default function HomePage() {
redirect('/dashboard');
}
This causes my auth context provider to fire which force-redirects the user back to dashboard or login screen. Perhaps there is a better way? The use case I'm trying to solve... User comes to site for the first time - localhost:3000/ gets presented the 'sales' page. User logs in, gets routed to /dashboard User logs out, gets routed to /login At any point, if the user is logged in, and tries to hit localhost:3000/ I want the user redirected to /dashboard. I'm trying to do this, but it doesn't seem to be redirecting me.
export const Route = createFileRoute("/")({
beforeLoad: ({ context }) => {
// Log for debugging
console.log("Auth check with context:", context);
// Check if user is authenticated
if (context.auth.user) {
console.log("User authenticated, proceeding...");
throw redirect({
to: "/dashboard",
search: {
redirect: location.href,
},
});
}
},
component: HomeComponent,
});
export const Route = createFileRoute("/")({
beforeLoad: ({ context }) => {
// Log for debugging
console.log("Auth check with context:", context);
// Check if user is authenticated
if (context.auth.user) {
console.log("User authenticated, proceeding...");
throw redirect({
to: "/dashboard",
search: {
redirect: location.href,
},
});
}
},
component: HomeComponent,
});
43 Replies
rival-black
rival-black7mo ago
but it doesn't seem to be redirecting me.
it should. does it throw the redirect? can you please provide a complete repo?
passive-yellow
passive-yellowOP7mo ago
adding in some logs it seems that the beforeLoad on the index root doesn't see the context like my other routes 😮 on /dashboard and / it's giving two different context results, the auth object itself is there, just all nulls on / root
passive-yellow
passive-yellowOP7mo ago
here's some logs, the multiple _auth.tsx calls is from prefetching on link hover.. once I finally click the link I see _auth.tsx:13 and the user is there.
No description
passive-yellow
passive-yellowOP7mo ago
if I reload index route, it seems to completely kill my console logs and the auth object is lost I can try and create a small reproduction today if you don't see anything fishy from the screen grab 😛
rival-black
rival-black7mo ago
yeah please create an example
passive-yellow
passive-yellowOP7mo ago
finally get to my PC for the night, seems I can't reproduce it on the stackblitz version you all have that uses localstorage, so let me do some debugging.. it seems to be like it's just losing context to the auth provider or something for me. wait this might be a dumb question - do I have to use localstorage to achieve this? Here's my auth providers, it's damn similar to the one in the example.
import {
type AuthProvider,
type User,
onAuthStateChanged,
signInWithPopup,
signOut,
} from "firebase/auth";
import { createContext, useContext, useEffect, useState } from "react";
import { auth } from "../firebase/config";

export type AuthContextType = {
user: User | null;
isAuthenticated: boolean;
signIn: (provider: AuthProvider) => Promise<void>;
logOut: () => Promise<void>;
};

const AuthContext = createContext<AuthContextType | null>(null);

export function AuthContextProvider({
children,
}: {
children: React.ReactNode;
}) {
console.log("Setting up auth context provider");
const [user, setUser] = useState<User | null>(null);
const isAuthenticated = !!user;

useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
setUser(user);
});
return () => unsubscribe();
}, []);

const signIn = async (provider: AuthProvider) => {
const result = await signInWithPopup(auth, provider);
setUser(result.user);
};

const logOut = async () => {
console.log("Logging out...");
await signOut(auth);
setUser(null);
};

return (
<AuthContext.Provider value={{ user, isAuthenticated, signIn, logOut }}>
{children}
</AuthContext.Provider>
);
}

export function useAuth() {
return useContext(AuthContext);
}
import {
type AuthProvider,
type User,
onAuthStateChanged,
signInWithPopup,
signOut,
} from "firebase/auth";
import { createContext, useContext, useEffect, useState } from "react";
import { auth } from "../firebase/config";

export type AuthContextType = {
user: User | null;
isAuthenticated: boolean;
signIn: (provider: AuthProvider) => Promise<void>;
logOut: () => Promise<void>;
};

const AuthContext = createContext<AuthContextType | null>(null);

export function AuthContextProvider({
children,
}: {
children: React.ReactNode;
}) {
console.log("Setting up auth context provider");
const [user, setUser] = useState<User | null>(null);
const isAuthenticated = !!user;

useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
setUser(user);
});
return () => unsubscribe();
}, []);

const signIn = async (provider: AuthProvider) => {
const result = await signInWithPopup(auth, provider);
setUser(result.user);
};

const logOut = async () => {
console.log("Logging out...");
await signOut(auth);
setUser(null);
};

return (
<AuthContext.Provider value={{ user, isAuthenticated, signIn, logOut }}>
{children}
</AuthContext.Provider>
);
}

export function useAuth() {
return useContext(AuthContext);
}
okay, I reproduced it.
passive-yellow
passive-yellowOP7mo ago
Andrew Peacock
StackBlitz
Router Authenticated Routes Example (forked) - StackBlitz
Run official live example code for Router Authenticated Routes, created by Tanstack on StackBlitz
passive-yellow
passive-yellowOP7mo ago
On index, click the "go to dashboard" link, sign in. Get routed successfully to dashboard. Modify the url to remove /dashboard. expectation is that you'd get routed back to /dashboard because you're still authenticated...but instead you see the index route.
rival-black
rival-black7mo ago
looks like in your auth provider you asynchronously set the user router does not observe react state changes
passive-yellow
passive-yellowOP7mo ago
Any suggestions on the way forward? I suppose I could pull signing in and logging out of this context object and simply rely on the firebase callback to set the user... let me try that That didn't work either - seems to blank out the entire router context whenever index page is loaded again
rival-black
rival-black7mo ago
usually when you update state in react that you want to see updated in router you need to router.invalidate() you need to be aware that react does not by default update state synchronously
passive-yellow
passive-yellowOP7mo ago
const user = await signInWithPopup(auth, typedProvider);

if (!user) {
throw new Error("User not found");
}

console.log("User signed in:", user);
router.invalidate();
router.navigate({ to: "/dashboard" });
const user = await signInWithPopup(auth, typedProvider);

if (!user) {
throw new Error("User not found");
}

console.log("User signed in:", user);
router.invalidate();
router.navigate({ to: "/dashboard" });
I'm doing that :/
rival-black
rival-black7mo ago
so you might need to flushSync
passive-yellow
passive-yellowOP7mo ago
oooh
passive-yellow
passive-yellowOP7mo ago
I was wondering if I was hitting this issue - https://github.com/TanStack/router/issues/2072
GitHub
Router context invalidate Promise resolve does not invalidate conte...
Describe the bug In the code below, which was suppose to invalidate the context and navigate to the following route. for context i'm following the example given in tanstack authenticated routes...
passive-yellow
passive-yellowOP7mo ago
FlushSync sounds like a solution in there too
rival-black
rival-black7mo ago
yes. it's how react works, so nothing you can do about it other than that
passive-yellow
passive-yellowOP7mo ago
Would love to see the docs grow with some more auth examples that don't use fake local storage or clerk TBH Seems like auth is a common 'complaint' I'm seeing on Threads, Bluesky, and github. This exact flow took ~ 5 minutes in next and worked, but is quite a PITA on router 😄 If I get this working with firebase, i'll throw some code folks can use.
rival-black
rival-black7mo ago
would appreciate update to the docs! and examples!
passive-yellow
passive-yellowOP7mo ago
if I can untangle my order of ops here, I should have a working example for everyone
No description
passive-yellow
passive-yellowOP7mo ago
I think I got it!
passive-yellow
passive-yellowOP7mo ago
Here was the linchpin of what I was missing..
No description
passive-yellow
passive-yellowOP7mo ago
This impl, does leverage zustand though. I'll see if I can negate that and see what happens.
passive-yellow
passive-yellowOP7mo ago
@Manuel Schiller Here it is 🙂 https://github.com/downright-development/tanstack-router-firebase-auth/ I'd love some feedback there and if you think it looks good and don't see any major security issues - feel free to take it and run with it in y'alls docs.
GitHub
GitHub - downright-development/tanstack-router-firebase-auth
Contribute to downright-development/tanstack-router-firebase-auth development by creating an account on GitHub.
passive-yellow
passive-yellowOP7mo ago
Just trying to show my appreciate back for all your help ❤️
rival-black
rival-black7mo ago
ideally create a PR directly to add a ln example in style of the other examples then we can review
passive-yellow
passive-yellowOP7mo ago
GitHub
Functional example of firebase client-side auth and protected route...
I struggled greatly getting firebase client-side authentication to play nicely inside TSR. This is a quick example on setting up your project. In this example, I&#39;m using firebase oauth with...
rival-black
rival-black7mo ago
For this example you work you MUST create a firebase project and setup github oauth. can we provide instructions for that? I suppose we can't mock them out ?
passive-yellow
passive-yellowOP7mo ago
Lowkey, defeats the purpse IMHO. There were other examples that mocked out the firebase calls and they all sucked I'll get some links to the firebase setup
passive-yellow
passive-yellowOP7mo ago
GitHub
Functional example of firebase client-side auth and protected route...
I struggled greatly getting firebase client-side authentication to play nicely inside TSR. This is a quick example on setting up your project. In this example, I&#39;m using firebase oauth with...
rival-black
rival-black7mo ago
cc @Sean Cassiere would be nice if you could review as well
passive-yellow
passive-yellowOP7mo ago
ABout to make an update, I found out how to remove zustand compeltely Update pushed, removed need for zustand 🙂
typical-coral
typical-coral7mo ago
@Manuel Schiller could you add me as a reviewer please? I'm going to be out for the next 8 hours or so, but once I'm back I can review. Edit: I've added myself on as a reviewer. @Peacock overall, it looks pretty good and will be a good addition to our examples. I've left feedback on the PR. Also, I fixed up the lockfile, so you'll need to pull down those changes before acting upon the feedback.
passive-yellow
passive-yellowOP7mo ago
@Sean Cassiere Just pushed all requested changes up - I also tidied up the login screen so the content rendered in the middle. Just a bit prettier.
typical-coral
typical-coral7mo ago
Thank you. @Manuel Schiller I'm happy with the PR. You have anything you want to add?
rival-black
rival-black7mo ago
if you are happy I am happy
typical-coral
typical-coral7mo ago
Mergin!
passive-yellow
passive-yellowOP7mo ago
boom! 🙂 Thanks gents
rival-black
rival-black7mo ago
thank you!
passive-yellow
passive-yellowOP7mo ago
Hey fellas, just realized I don't see this new example on the https://tanstack.com/router/v1/docs/ docs, should I?
Overview | TanStack Router React Docs
TanStack Router is a router for building React and Solid applications. Some of its features include: 100% inferred TypeScript support Typesafe navigation Nested Routing and layout routes (with pathles...
passive-yellow
passive-yellowOP7mo ago
Not sure if I missed an udpate somewhere
rival-black
rival-black7mo ago
we don't link to all examples on the website that must be done explicitly as this example is not runnable directly in a stackblitz/ codesandbox env, i would not link to it on the website
passive-yellow
passive-yellowOP7mo ago
Might be nice to consider a more explicit 'directory' of examples, one that links to otehr pages or github fallback otherwise you can't really find it unless you venture out to github.. which I'd imagine most users aren't gonna do tbh

Did you find this page helpful?