A signed-out user must not reach screens that need an account, and after signing out, Back must not lead into them again. Both libraries solve this by defining different screens for different states rather than by redirecting. In React Navigation 407,918 you render the screens conditionally:
const [user, setUser] = useState<string | null>(null);
return (
<NavigationContainer onStateChange={(s) =>
console.log('screens:', s?.routes.map((r) => r.name).join(' > '))}>
<Stack.Navigator>
{user ? (
<>
<Stack.Screen name="Catalog">{/* ...a "My account" button */}</Stack.Screen>
<Stack.Screen name="Account">
{() => <Button label={`Sign out ${user}`} onPress={() => setUser(null)} />}
</Stack.Screen>
</>
) : (
<Stack.Screen name="SignIn" options={{ title: 'Sign in' }}>Signing in, opening the account and signing out:
LOG screens: Catalog LOG screens: Catalog > Account LOG screens: SignIn
Nothing called navigate to leave SignIn: it stopped existing when user changed, and the navigator showed the first screen of the new set. Signing out removed Catalog and Account, history included.
Expo Router 6,418 expresses the same idea with Stack.Protected (Layouts and Nested Navigators): checkout exists only while guard={user !== null} holds. BookNest's cart sends signed-out users to /sign-in, whose button calls setUser('Ana') (Authentication replaces this with a real sign-in) and then router.replace('/checkout'), which swaps the sign-in screen for the checkout so Back skips it. Tapping Checkout, Sign in as Ana, then Sign out on the checkout screen logged these paths:
LOG path: /cart LOG path: /sign-in LOG path: /checkout LOG path: /cart
Signing out flipped the guard, and the router dropped /checkout and its history, landing on the cart. Before Checkout linked to /sign-in, a tap while signed out did nothing: navigation to a guarded route is ignored without an error, so give signed-out users a visible way forward. The server must still check every request.