T
TanStack9mo ago
vicious-gold

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
conscious-sapphire
conscious-sapphire9mo ago
but it doesn't seem to be redirecting me.
it should. does it throw the redirect? can you please provide a complete repo?
vicious-gold
vicious-goldOP9mo 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
vicious-gold
vicious-goldOP9mo 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
vicious-gold
vicious-goldOP9mo 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 😛
conscious-sapphire
conscious-sapphire9mo ago
yeah please create an example
vicious-gold
vicious-goldOP9mo 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.
vicious-gold
vicious-goldOP9mo ago
Andrew Peacock
StackBlitz
Router Authenticated Routes Example (forked) - StackBlitz
Run official live example code for Router Authenticated Routes, created by Tanstack on StackBlitz
vicious-gold
vicious-goldOP9mo 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.
conscious-sapphire
conscious-sapphire9mo ago
looks like in your auth provider you asynchronously set the user router does not observe react state changes
vicious-gold
vicious-goldOP9mo 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
conscious-sapphire
conscious-sapphire9mo 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
vicious-gold
vicious-goldOP9mo 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 :/
conscious-sapphire
conscious-sapphire9mo ago
so you might need to flushSync
vicious-gold
vicious-goldOP9mo ago
oooh
vicious-gold
vicious-goldOP9mo 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...
vicious-gold
vicious-goldOP9mo ago
FlushSync sounds like a solution in there too
conscious-sapphire
conscious-sapphire9mo ago
yes. it's how react works, so nothing you can do about it other than that
vicious-gold
vicious-goldOP9mo 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.
conscious-sapphire
conscious-sapphire9mo ago
would appreciate update to the docs! and examples!
vicious-gold
vicious-goldOP9mo ago
if I can untangle my order of ops here, I should have a working example for everyone
No description
vicious-gold
vicious-goldOP9mo ago
I think I got it!
vicious-gold
vicious-goldOP9mo ago
Here was the linchpin of what I was missing..
No description
vicious-gold
vicious-goldOP9mo ago
This impl, does leverage zustand though. I'll see if I can negate that and see what happens.
vicious-gold
vicious-goldOP9mo 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.
vicious-gold
vicious-goldOP9mo ago
Just trying to show my appreciate back for all your help ❤️
conscious-sapphire
conscious-sapphire9mo ago
ideally create a PR directly to add a ln example in style of the other examples then we can review
vicious-gold
vicious-goldOP9mo 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...
conscious-sapphire
conscious-sapphire9mo 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 ?
vicious-gold
vicious-goldOP9mo 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
vicious-gold
vicious-goldOP9mo 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...
conscious-sapphire
conscious-sapphire9mo ago
cc @Sean Cassiere would be nice if you could review as well
vicious-gold
vicious-goldOP9mo ago
ABout to make an update, I found out how to remove zustand compeltely Update pushed, removed need for zustand 🙂
equal-jade
equal-jade9mo 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.
vicious-gold
vicious-goldOP9mo 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.
equal-jade
equal-jade9mo ago
Thank you. @Manuel Schiller I'm happy with the PR. You have anything you want to add?
conscious-sapphire
conscious-sapphire9mo ago
if you are happy I am happy
equal-jade
equal-jade9mo ago
Mergin!
vicious-gold
vicious-goldOP9mo ago
boom! 🙂 Thanks gents
conscious-sapphire
conscious-sapphire9mo ago
thank you!
vicious-gold
vicious-goldOP9mo 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...
vicious-gold
vicious-goldOP9mo ago
Not sure if I missed an udpate somewhere
conscious-sapphire
conscious-sapphire9mo 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
vicious-gold
vicious-goldOP9mo 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?