I am using React Native / Expo to build an app with auth. I can log in fine but when I refresh the app, the auth is lost and I need to log in again.
My firebase config looks like this:
import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
const firebaseConfig = {
apiKey: "<key>",
authDomain: "<name>.firebaseapp",
projectId: "<id>",
storageBucket: "<id>.appspot",
messagingSenderId: "<sender_id>",
appId: "<app_id>",
};
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
export { auth };
I have a self hosted log in form in my app that is as so
import { getAuth, signInWithEmailAndPassword } from 'firebase/auth';
const LoginScreen = () => {
const auth = getAuth();
const handleLogin = useCallback(async (email: string, password: string) => {
const user = await signInWithEmailAndPassword(auth, email, password);
}, [auth]);
return (
<LoginForm onLogin={handleLogin} />
)
}
The log in works fine and I can retrieve the users details and even see auth state change in this useEffect
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
console.log("Auth state changed:", user);
});
return unsubscribe;
}, [auth]);
But when I refresh the app, auth is === null and I need to log in again.
Apparently as of firebase >v9 it should auto persist the auth so I shouldn't need to configure anything else?
How can I make my RN app have persisted log in using Firebase?
Package versions:
"firebase": "^11.3.1",
"react": "18.3.1",
"expo": "~52.0.31"
I am using React Native / Expo to build an app with auth. I can log in fine but when I refresh the app, the auth is lost and I need to log in again.
My firebase config looks like this:
import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
const firebaseConfig = {
apiKey: "<key>",
authDomain: "<name>.firebaseapp",
projectId: "<id>",
storageBucket: "<id>.appspot",
messagingSenderId: "<sender_id>",
appId: "<app_id>",
};
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
export { auth };
I have a self hosted log in form in my app that is as so
import { getAuth, signInWithEmailAndPassword } from 'firebase/auth';
const LoginScreen = () => {
const auth = getAuth();
const handleLogin = useCallback(async (email: string, password: string) => {
const user = await signInWithEmailAndPassword(auth, email, password);
}, [auth]);
return (
<LoginForm onLogin={handleLogin} />
)
}
The log in works fine and I can retrieve the users details and even see auth state change in this useEffect
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
console.log("Auth state changed:", user);
});
return unsubscribe;
}, [auth]);
But when I refresh the app, auth is === null and I need to log in again.
Apparently as of firebase >v9 it should auto persist the auth so I shouldn't need to configure anything else?
How can I make my RN app have persisted log in using Firebase?
Package versions:
"firebase": "^11.3.1",
"react": "18.3.1",
"expo": "~52.0.31"
Share
Improve this question
edited Feb 15 at 18:21
Frank van Puffelen
600k85 gold badges889 silver badges859 bronze badges
Recognized by Mobile Development Collective and Google Cloud Collective
asked Feb 15 at 16:13
Stretch0Stretch0
9,26315 gold badges92 silver badges157 bronze badges
9
|
Show 4 more comments
1 Answer
Reset to default 0I hope the method below will work.
You can persist the user across states using useContext
and/or Async Storage
.
Here, I have used Appwrite, but I think Firebase offers a similar method like this.
1. First, you must create a context to provide the user to the entire app. Here, I have used the getCurrentUser() method in Appwrite. I think FIREBASE will also provide a similar method (I think auth.currentUser is the method,but please check this).
import { createContext, useContext, useState, useEffect } from "react";
import { getCurrentUser } from "../lib/appwrite";
const GlobalContext = createContext();
export const useGlobalContext = () => useContext(GlobalContext);
export const GlobalProvider = ({ children }) => {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [user, setUser] = useState(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
getCurrentUser()
.then((res) => {
if (res) {
setIsLoggedIn(true);
setUser(res);
} else {
setIsLoggedIn(false);
setUser(null);
}
})
.catch((err) => {
console.error(err);
})
.finally(() => {
setIsLoading(false);
});
}, []);
return (
<GlobalContext.Provider
value={{ isLoggedIn, setIsLoggedIn, user, setUser, isLoading }}
>
{children}
</GlobalContext.Provider>
);
};
- As an alternative, you can use AsyncStorage in React Native(If you don't have a built-in method to get the logged-in user)(this is similar to localStorage). So, at the first login, If the user logs in successfully, you can save the user state and other important details (username, token, etc.) in AsyncStorage. When the page refreshes, you have to call AsyncStorage to retrieve that data.
By using the above methods, we can get the logged-in user when the page refreshes.
2. The next thing we must do is ensure that this user state is available throughout our React Native app.
So, in _layout.jsx
, we should wrap our app using this global provider.
return (
<GlobalProvider>
<Stack>
<Stack.Screen name="index" options={{ headerShown: false }} />
<Stack.Screen name="(auth)" options={{ headerShown: false }} />
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
</Stack>
</GlobalProvider>
);
};
3. The next thing is, you should ensure that your app does not navigate to the login page/splash page when the page refreshes. Instead, it should go to the home page or any other desired page.
index.jsx
is the entry point of a React Native app. Here, at first, you just check whether a user is logged in (using our global provider and context). If there is a user, they will be directly navigated to the home page.
import { StatusBar } from "expo-status-bar";
import { Image, ScrollView, StyleSheet, Text, View } from "react-native";
import { Redirect, router } from "expo-router";
import React from "react";
import { SafeAreaView } from "react-native-safe-area-context";
import { images } from "../constants";
import CustomButton from "../components/CustomButton";
import { useGlobalContext } from "../context/GlobalProvider";
export default function App() {
const { isLoading, isLoggedIn } = useGlobalContext();
if (!isLoading && isLoggedIn) return <Redirect href="/home" />;
return (
<SafeAreaView className="bg-primary h-full">
<ScrollView contentContainerStyle={{ height: "100%" }}>
<View className="w-full items-center justify-center h-full px-4">
<Image
source={images.logo}
className="w-[130px] h-[84px]"
resizeMode="contain"
/>
<Image
source={images.cards}
className="max-w-[300px] h-[300px]"
resizeMode="contain"
/>
<View className="relative mt-5">
<Text className="text-3xl text-white font-bold text-center">
Discover Endless{"\n"}
Possibilities with{" "}
<Text className="text-secondary-200">Aora</Text>
</Text>
I think by using the above method, you can persist the user when the page refreshes, as well as ensure that the user only need to log in if he log out from the device(Don't need to log in everytime he opens the app ).
getAuth()
inLoginScreen
, can you try importingauth
exported from the Firebase config file and use it in theonAuthStateChanged
anduseEffect
calls? – Dharmaraj Commented Feb 15 at 16:29getAuth
any way so would effectively be the same thing – Stretch0 Commented Feb 15 at 16:38initializeApp
from being called. Doing so ensures it the Firebase app is initialized before Login screen is mounted. If that does not work, please share a MVP on Github. – Dharmaraj Commented Feb 15 at 16:40