-
Notifications
You must be signed in to change notification settings - Fork 113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to handle auth #14
Comments
Same question! |
I think you have to handle it how you handle routes in nextjs or svelteKit project on the web. Just navigate to another page based on the state |
Would be nice to have something like middle wares in next js. So with one file we could check if user is authenticated or not and based on that filter routes |
Can't we just check auth in layouts and navigate somwhere else if not authorized? |
No docs or built-in solution for this yet. If anyone wants to propose a solution for protected routes I can start building off it. There probably won't be anything like middleware in the short term so redirecting is probably the way to go. |
We probably can still use something like this. Or will other routes still be accessible?
import { NativeStack } from "expo-router";
export default function Layout() {
return (
<NativeStack>
{isLoggedIn ? (
<NativeStack.Screen
name="(tab)"
options={{
headerShown: false,
}}
/>
) : isLoggedOut ? (
<NativeStack.Screen
name="modal"
options={{
presentation: "modal",
}}
/>
) : (
<NativeStack.Screen
name="modal"
options={{
presentation: "modal",
}}
/>
)}
</NativeStack>
);
}
|
i have a web version of this component here : #20 almost working, just not working for accessing directly from browser URL |
@fristyr this doesn't work because all the routes are accessible by virtue of the files existing, so it doesn't matter if we only render them declaratively depending on some variable/state. What I've done now (as suggested by @rohid2d and @EvanBacon) is implement navigation depending on auth state: export default function Layout() {
const { isSignedIn, isSignedOut } = useAuth();
const link = useLink();
useEffect(() => {
const targetRoute = isSignedIn ? "/" : isSignedOut ? "/signIn" : "/loading";
link.push(targetRoute);
}, [isSignedIn, isSignedOut, link]);
return (
<NativeStack
screenOptions={{ headerShown: false }}
initialRouteName="loading"
/>
);
} But I still think it would be better to somehow only render routes that are valid depending on nav state instead of just navigating away. This is also what's recommended by React Navigation (https://reactnavigation.org/docs/auth-flow/), but so far, I don't have any idea how to achieve this with file system based routing. One option would be to explicitly disable routes, but React Navigation doesn't seem to have a provision for this. |
@bndkt agree with you here |
Ideally, when you use file-based navigation, the folder structure could match your application state for a visually reasoning you can have this (auth) and (non-auth) fragment for wrapping the logic for auth and non-auth state, this is the layer where you put the < Providers> and < Protected> as shown in the image, the only additional wrapper in the (auth) is the < Protected> component, and the < AfterAuthLayout> so instead of doing the usual react-navigation way, to swap out the whole navigation stack, you simply just list all routes in the app folder, and protect the part that needs to be protected. have a quick example here: currently built for web, but i believe it works on mobile as well (you just have to add the < Stack> wrapper to the layout component). (https://github.com/Albert-Gao/expo-router-web-try-out/tree/web-auth-flow) I found this is easy to reason about in 1sec about which route is protected in scale Evan just added the which through my testing, is not working, or maybe i am missing something here, but for the mobile app,it should be already WORKING since you do not have that user-can-access-any-page-by-url problem. |
@EvanBacon I thought about this some more. The solution I described above does work, but it still throws an error because I try to route before the nav is ready ("The 'navigation' object hasn't been initialized yet. This might happen if you don't have a navigator mounted, or if the navigator hasn't finished mounting."). I could use navigationRef.isReady(), but I can't access the navigationRef (https://reactnavigation.org/docs/navigating-without-navigation-prop/). I supposed this could be solved somehow (e.g. by Expo Router creating a navigationRef by default and exposing it), but the more I think about it, the more I'm convinced that there should be a way to opt out of creating routes automatically for use cases such as auth where I want to determine which routes are available based on state. What do you think about a convention like prefixing file names with "." or "_" so that for those files, routes are not created automatically and have to be handled by the developer. Then I could have a layout route (auth) that renders a stack, and within that I'd have ".loading.js", ".signIn.js" and ".(tab).js" but in this case, I'm handling the route creation myself based on auth state: <NativeStack>
{isLoggedIn ? (
<NativeStack.Screen name=".(tab)" />
) : isLoggedOut ? (
<NativeStack.Screen name=".signIn" />
) : (
<NativeStack.Screen name=".loading" />
)}
</NativeStack> |
@bndkt I like this idea of a file decorator, but in my mind it could be used as a way to not have to add extra logic for a route within code. For example a route like I suppose one downside here is that if you are working on an app where most views require auth you are having to decorate basically every route name, but it still seems more dev friendly than having to add screens to a stack and then adding options to each of the screens. You could swap that paradigm, but then those creating open webapps without much or any auth are having to decorate a lot of views… |
Hi Evan,
as I said on Twitter already, awesome work on the router! I've started implementing it today and have removed sooo much code. My app has gotten a 100% more declarative. One thing I struggle wrapping my head around is auth. And I think it's such an important part of almost every app that it's worth having a best practice in the docs. I'm happy to contribute a PR for that once I've figured it out for myself. Before Expo Router, I was basically doing the following:
This way, only the relevant screens (and dependents) were mounted based on the auth state. Now with file-based routing, the files will always be there. I'm sure you have thought about auth already, any best practice you have in mind?
The text was updated successfully, but these errors were encountered: