React-Native Authentication with Firebase

Gaurav Rizal
11 min readSep 9, 2023

--

Firebase, a set of back-end cloud computing services provided by Google, has made it incredibly easy to host databases, services, analytics, authentication, and much more. In this walk-through, I will guide you through the process of integrating Firebase Authentication into your React-Native projects.

Firebase Authentication is a significant breakthrough, especially for front-end developers, as it provides the easiest approach to authenticate users without requiring an in-depth understanding of back-end services and code. With Firebase, you can start building authentication features without worrying about the complexities of traditional authentication systems. Let’s dive right in.

Project Setup

Lets simply create a react-native app either from CLI or expo environment. For simplicity, I am going to use expo.

lets setup our project.

npx create-expo-app LoginFirebaseAuth

Also, lets install require packages and libraries for navigation.

npm install @react-navigation/native
npx expo install react-native-screens react-native-safe-area-context
npm install @react-navigation/native-stack

Now ,we are all set to setup our project Structure.

create a main folder “src” under which we will create folders

  1. assets

2. screens

3. navigation

4. contexts

5. firebase

Under Navigation, lets create two file AppStack for the logged in Users stack and GuestStack for guest User stack.

import React from "react";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import HomeScreen from "../screens/HomeScreen";

const Stack = createNativeStackNavigator();

const AppStack = () => {
return (
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ headerShown: false }}
/>
</Stack.Navigator>
);
};

export default AppStack;

In this Stack, we have used createNativeStackNavigator to create a stack under which for now we have placed a normal Screen i.e HomeScreen.

Likewise, also create GuestStack for guest users, under which we will place two login and signup screen.

import React from "react";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import LoginScreen from "../screens/LoginScreen";
import WelcomeScreen from "../screens/WelcomeScreen";
import SignUpScreen from "../screens/SignUpScreen";

const Stack = createNativeStackNavigator();

const GuestStack = () => {
return (
<Stack.Navigator>
<Stack.Screen
name="Welcome"
component={WelcomeScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="Login"
component={LoginScreen}
options={{ headerShown: true }}
/>
<Stack.Screen
name="SignUp"
component={SignUpScreen}
options={{ headerShown: true }}
/>
</Stack.Navigator>
);
};

export default GuestStack;

Our Navigation Part is done for now.

Context in React is a way to share data between components without having to explicitly pass props through each level of the component tree.
Here, we are using this for to share our state, loggedInUser so that in the root file, we will know whether or not user is logged In or not.

import React from "react";

const AuthContext = React.createContext();

export const AuthProvider = ({ children }) => {
const [loggedInUser, setLoggedInUser] = React.useState(null);

return (
<AuthContext.Provider value={{ loggedInUser, setLoggedInUser }}>
{children}
</AuthContext.Provider>
);
};

export const useAuth = () => React.useContext(AuthContext);

export default AuthContext;

You can simply create a simple UI design for HomeScreen, WelcomeScreen, SignUpScreen and LoginScreen.

Now, lets setup out root file. (App.js)

import React from "react";
import { LogBox } from "react-native";
LogBox.ignoreLogs(["Warning: ..."]); // Ignore log notification by message
LogBox.ignoreAllLogs(); //Ignore all log notifications

import { NavigationContainer } from "@react-navigation/native";

import { AuthProvider, useAuth } from "./src/contexts/AuthContext";
import GuestStack from "./src/navigation/GuestStack";
import AppStack from "./src/navigation/AppStack";

const AppContent = () => {
const { loggedInUser } = useAuth();
return (
<NavigationContainer>
{loggedInUser ? <AppStack /> : <GuestStack />}
</NavigationContainer>
);
};

export default function App() {
return (
<AuthProvider>
<AppContent />
</AuthProvider>
);
}

Here, we are extracting the value of loggedInUser from that AuthContext and based on it, we will either transfer to AppStack or to GuestStack.

Now lets Setup Firebase.

But at first install this firebase package in our project.

npm install firebase

Lets Setup Firebase Project

Go to https://console.firebase.google.com/

  1. Create A project
  2. Enter your project name. (LoginFireBaseAuth)
  3. Press continue( You can also disable google analytics as for now we will not be using that part. Also enabling it will not affect you)
  4. If you have pressed enable Google Analytivs then it may ask you about Analytics location and to accept Analytics term. Accept that and create a project.

Now as you will be redirected here, press that </> to add firebase to your web app.

Provide a name and press register App.Now it will provide you with your project credentials. Your credentials are very confidential part of your project so do not share that credentials to unknown people.

Few things have been added in this config, to export firebase and authentication. you can copy this code and replace it with the provided credentials

// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";

import firebase from "firebase/compat/app";
import "firebase/compat/auth";
import "firebase/compat/firestore";

const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "YOUR-AUTH-DOMAIN",
projectId: "YOUR PROJECT ID",
storageBucket: "YOUR_STORAGE-PROJECT",
messagingSenderId: "YOUR MESSENGING_SENDER_ID",
appId: "YOUR_APP_ID",
measurementId: "YOUR_MEASUREMENT_ID"
};


// Initialize Firebase (

firebase.initializeApp(firebaseConfig);
const app = initializeApp(firebaseConfig);
const authentication = getAuth(app);
export { firebase, authentication };

Add this file “config.js” in the folder firebase folder in your src folder.

Now, re Open your project in firebase console. and go to Authentication which you can find uner Build in Product categories and click Get Started.

You can find number of Auth providers:Email/Password, Phone Number, Facebook, Google, Twitter, GitHub, Anonymous and even integration with custom authentication providers are all supported which is one of the key advantage of using Firebase.

For now, we will go with Email/Password under Native providers and enable it as per your requirements.

Now add a user just for future use.

I have added one email: admin@gmail.com with password: ******** (: )

Lets Setup our Welcome Screen.

import React from "react";
import {
SafeAreaView,
StyleSheet,
Text,
TouchableOpacity,
View,
Image,
} from "react-native";

const WelcomeScreen = ({ navigation }) => {
return (
<SafeAreaView style={styles.container}>
<Text style={styles.title}>Welcome to Firebase : )</Text>

<TouchableOpacity
style={styles.button}
onPress={() => {
navigation.navigate("Login");
}}
>
<Text style={styles.buttonText}>Sign In</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={() => {
navigation.navigate("SignUp");
}}
>
<Text style={styles.buttonText}>Sign Up</Text>
</TouchableOpacity>
</SafeAreaView>
);
};

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#ffffff",
paddingHorizontal: 20,
},
logo: {
width: 150,
height: 150,
marginBottom: 20,
},
title: {
fontSize: 24,
fontWeight: "bold",
marginBottom: 30,
},
subtitle: {
fontSize: 16,
marginBottom: 30,
textAlign: "center",
},
button: {
backgroundColor: "#007BFF",
width: "90%",
paddingVertical: 15,
marginHorizontal: 15,
borderRadius: 8,
marginBottom: 20,
},
buttonText: {
color: "#ffffff",
fontSize: 18,
fontWeight: "bold",
textAlign: "center",
},
});

export default WelcomeScreen;

Now lets create a minimal Login Screen.

At first lets import authentication, signInWithEmailAndPassword which is be default given by firebase/auth and useAuth to setLoggedInUser.

import { authentication } from "../firebase/config";
import { signInWithEmailAndPassword } from "firebase/auth";
import { useAuth } from "../contexts/AuthContext";

now add these necesaary states that will be needed for email, password, error Text, isLoading flag ans setLoggedInUser.

  const [email, setEmail] = React.useState("");
const [password, setPassword] = React.useState("");
const [error, setError] = React.useState(null);

const inputRef = React.useRef();
const passwordRef = React.useRef();

const [isLoading, setIsLoading] = useState(false);

const { setLoggedInUser } = useAuth();

now lets Add two TextInput for email and password.

     <TextInput
ref={inputRef}
style={styles.input}
placeholder="Enter your email"
keyboardType="email-address"
autoCapitalize="none"
placeholderTextColor="#003f5c"
value={email}
onChangeText={(email) => setEmail(email)}
/>

<TextInput
ref={passwordRef}
style={styles.input}
placeholder="Enter your password"
placeholderTextColor="#003f5c"
value={password}
secureTextEntry
onChangeText={(text) => setPassword(text)}
/>

now add a button to trigger and action

  <TouchableOpacity onPress={handleSignIn} style={styles.button}>
<Text style={styles.loginText}>Login</Text>
{isLoading && (
<ActivityIndicator
size="small"
color="white"
style={{
alignSelf: "center",
justifyContent: "center",
paddingLeft: 10,
}}
/>
)}
</TouchableOpacity>

Now, lets define handleSignIn action

  const handleSignIn = async () => {
setIsLoading(true);

signInWithEmailAndPassword(authentication, email, password)
.then((res) => {
console.log("successful");
setLoggedInUser(res.user);
})

.catch((err) => {
console.log(err);
setError("Incorrect Email/Password");
})

.finally(() => setIsLoading(false));
};

Here Using Firebase’s signInWithEmailAndPassword method, it attempts to authenticate the user with the provided email and password. and if the attempt is successful it setLoggedInUser(res.user) and if not it will set a static error message.

Full code for Login Page.

import React, { useState } from "react";
import {
View,
Text,
TextInput,
Button,
StyleSheet,
Image,
TouchableOpacity,
ActivityIndicator,
} from "react-native";

import { authentication } from "../firebase/config";
import { signInWithEmailAndPassword } from "firebase/auth";
import { useAuth } from "../contexts/AuthContext";

const LoginScreen = ({ navigation }) => {
const [email, setEmail] = React.useState("");
const [password, setPassword] = React.useState("");
const [error, setError] = React.useState(null);

const inputRef = React.useRef();
const passwordRef = React.useRef();

const [isLoading, setIsLoading] = useState(false);

const { setLoggedInUser } = useAuth();

const handleSignIn = async () => {
setIsLoading(true);

signInWithEmailAndPassword(authentication, email, password)
.then((res) => {
console.log("successful");
setLoggedInUser(res.user);
})

.catch((err) => {
console.log(err);
setError("Incorrect Email/Password");
})

.finally(() => setIsLoading(false));
};

return (
<View style={styles.container}>
<Text style={styles.welcomeText}>Welcome!</Text>
<Image
source={{
uri: "https://ouch-cdn2.icons8.com/teMbWzQG6l5J7CQqv4TiWL2pvjv9-A1IUmfuhymu3zw/rs:fit:608:456/extend:false/wm:1:re:0:0:0.8/wmid:ouch/czM6Ly9pY29uczgu/b3VjaC1wcm9kLmFz/c2V0cy9zdmcvMzIy/LzEzODJjMmMwLThj/M2YtNGQ4Yy1iODk0/LWRkYTRhMDI3ZGFl/OS5zdmc.png",
}}
style={styles.logo}
/>

<TextInput
ref={inputRef}
style={styles.input}
placeholder="Enter your email"
keyboardType="email-address"
autoCapitalize="none"
placeholderTextColor="#003f5c"
value={email}
onChangeText={(email) => setEmail(email)}
/>

<TextInput
ref={passwordRef}
style={styles.input}
placeholder="Enter your password"
placeholderTextColor="#003f5c"
value={password}
secureTextEntry
onChangeText={(text) => setPassword(text)}
/>
{error && <Text style={styles.errorText}>{error}</Text>}

<TouchableOpacity onPress={handleSignIn} style={styles.button}>
<Text style={styles.loginText}>Login</Text>
{isLoading && (
<ActivityIndicator
size="small"
color="white"
style={{
alignSelf: "center",
justifyContent: "center",
paddingLeft: 10,
}}
/>
)}
</TouchableOpacity>
<View
style={{
flexDirection: "row",
}}
>
<Text style={styles.downText}>Don't have an account?</Text>
<TouchableOpacity onPress={() => navigation.navigate("signup")}>
<Text style={styles.signup}>Sign Up</Text>
</TouchableOpacity>
</View>
</View>
);
};

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
padding: 20,
},
label: {
fontSize: 16,
marginBottom: 8,
},
input: {
width: "100%",
height: 40,
borderColor: "gray",
borderWidth: 1,
marginBottom: 16,
paddingLeft: 8,
paddingRight: 8,
},
button: {
backgroundColor: "#302298",
borderRadius: 20,
padding: 10,
margin: 14,
width: "78%",
height: 50,
alignItems: "center",
justifyContent: "center",
flexDirection: "row",
},
loginText: {
color: "white",
fontWeight: "bold",
textAlign: "center",
fontSize: 16,
alignSelf: "center",
},
welcomeText: {
fontSize: 24,
fontWeight: "bold",
marginBottom: 16,
textAlign: "center",
},
logo: {
width: 150,
height: 150,
marginBottom: 20,
},
downText: {
color: "#331ece",
fontSize: 16,
fontWeight: "400",
marginTop: 10,
},
signup: {
alignSelf: "flex-start",
textDecorationLine: "underline",
color: "#331ece",
fontSize: 16,
fontWeight: "500",
marginLeft: 5,
marginTop: 10,
},
});

export default LoginScreen;

here, now try with incorrect email/password, it will show you message Incorrect Email/Password. and again try with the email that we added n the user (admin@gmail.com). upon that you will be navigated to HomeScreen.

Now lets add signout function as well in HomeScreen.

First import these:

import { useAuth } from "../contexts/AuthContext";
import { authentication } from "../firebase/config";
import { signOut } from "firebase/auth";

Now lets create a signOut function

  const { loggedInUser, setLoggedInUser } = useAuth();

const signOutUser = () => {
signOut(authentication)
.then((res) => {
console.log(res);
setLoggedInUser(null);
})
.catch((err) => {
console.log(err);
});
};

Now trigger this funcion with a button

  <TouchableOpacity onPress={signOutUser} style={styles.button}>
<Text style={styles.signOutText}>Sign Out</Text>
</TouchableOpacity>

Full HomeScreen code

import {
SafeAreaView,
StyleSheet,
Text,
TouchableOpacity,
View,
} from "react-native";
import React from "react";

import { useAuth } from "../contexts/AuthContext";
import { authentication } from "../firebase/config";
import { signOut } from "firebase/auth";

const HomeScreen = () => {
const { loggedInUser, setLoggedInUser } = useAuth();

const signOutUser = () => {
signOut(authentication)
.then((res) => {
console.log(res);
setLoggedInUser(null);
})
.catch((err) => {
console.log(err);
});
};

return (
<SafeAreaView
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<Text>You have successfully learned Firebase Login.</Text>
<TouchableOpacity onPress={signOutUser} style={styles.button}>
<Text style={styles.signOutText}>Sign Out</Text>
</TouchableOpacity>
</SafeAreaView>
);
};

export default HomeScreen;

const styles = StyleSheet.create({
button: {
backgroundColor: "#302298",
borderRadius: 20,
padding: 10,
margin: 14,
width: "78%",
height: 50,
alignItems: "center",
justifyContent: "center",
flexDirection: "row",
},
signOutText: {
color: "white",
fontWeight: "bold",
textAlign: "center",
fontSize: 16,
alignSelf: "center",
},
});

Now, lets create a minimal signUp page.

First import authentication and createUserWithEmailAndPassword from firebase ad useAuth from AuthContext

import { authentication } from "../firebase/config";
import { createUserWithEmailAndPassword } from "firebase/auth";
import { useAuth } from "../contexts/AuthContext";

Create normal useState to save email, password, confirm password and create their UI.

  const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");

<TextInput
style={styles.input}
placeholder="Email"
keyboardType="email-address"
autoCapitalize="none"
value={email}
onChangeText={(text) => setEmail(text)}
/>
<TextInput
style={styles.input}
placeholder="Password"
secureTextEntry
value={password}
onChangeText={(text) => setPassword(text)}
/>
<TextInput
style={styles.input}
placeholder="Confirm Password"
secureTextEntry
value={confirmPassword}
onChangeText={(text) => setConfirmPassword(text)}
/>

now create a button to create a new User.

   <TouchableOpacity onPress={handleSignUp} style={styles.button}>
<Text style={styles.buttonText}>Sign Up</Text>
{isLoading && (
<ActivityIndicator
size="small"
color="white"
style={{
alignSelf: "center",
justifyContent: "center",
paddingLeft: 10,
}}
/>
)}
</TouchableOpacity>

Now lets create a signUp function

  const [isLoading, setIsLoading] = useState(false);
const { setLoggedInUser } = useAuth();

const handleSignUp = () => {
setIsLoading(true);
createUserWithEmailAndPassword(authentication, email, password)
.then((res) => {
console.log(res.user);
setLoggedInUser(res.user);
})
.catch((re) => {
console.log(re);
})
.finally(() => setIsLoading(false));
};

now, here it create a new email password and will change the state of LoggedInUser, due to which you will be automatically loggedin.
Note that: you password and confirmPassword are not validate here as of now and we are using the password state to create your password.

Now again you will be loggedIn and will be navigated to HomeScreen.

full code for SignUp screen

import React, { useState } from "react";
import {
StyleSheet,
Text,
View,
TextInput,
TouchableOpacity,
ActivityIndicator,
} from "react-native";

import { authentication } from "../firebase/config";
import { createUserWithEmailAndPassword } from "firebase/auth";
import { useAuth } from "../contexts/AuthContext";

const SignUpScreen = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");

const [isLoading, setIsLoading] = useState(false);
const { setLoggedInUser } = useAuth();

const handleSignUp = () => {
setIsLoading(true);
createUserWithEmailAndPassword(authentication, email, password)
.then((res) => {
console.log(res.user);
setLoggedInUser(res.user);
})
.catch((re) => {
console.log(re);
})
.finally(() => setIsLoading(false));
};

return (
<View style={styles.container}>
<Text style={styles.title}>Sign Up</Text>
<TextInput
style={styles.input}
placeholder="Email"
keyboardType="email-address"
autoCapitalize="none"
value={email}
onChangeText={(text) => setEmail(text)}
/>
<TextInput
style={styles.input}
placeholder="Password"
secureTextEntry
value={password}
onChangeText={(text) => setPassword(text)}
/>
<TextInput
style={styles.input}
placeholder="Confirm Password"
secureTextEntry
value={confirmPassword}
onChangeText={(text) => setConfirmPassword(text)}
/>
<TouchableOpacity onPress={handleSignUp} style={styles.button}>
<Text style={styles.buttonText}>Sign Up</Text>
{isLoading && (
<ActivityIndicator
size="small"
color="white"
style={{
alignSelf: "center",
justifyContent: "center",
paddingLeft: 10,
}}
/>
)}
</TouchableOpacity>
</View>
);
};

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#ffffff",
paddingHorizontal: 20,
},
title: {
fontSize: 24,
fontWeight: "bold",
marginBottom: 20,
},
input: {
width: "100%",
height: 40,
borderColor: "#ccc",
borderWidth: 1,
borderRadius: 5,
marginBottom: 16,
paddingLeft: 8,
},
button: {
backgroundColor: "#007BFF",
width: "100%",
paddingVertical: 15,
borderRadius: 10,
marginTop: 10,
},
buttonText: {
color: "#ffffff",
fontSize: 18,
fontWeight: "bold",
textAlign: "center",
},
});

export default SignUpScreen;

Here, you can see that test@gmail.com was the account I used for creating a new user.

In this way, you can use firebase authentication in your mobile app.

Here, I have tried to demonstrate you the implementation of firebase authentication with email and password, and have not much focused on UI design. You can implement your own UI based on this functionality.

If you liked my article and want to stay tuned,

Follow me:

Github: https://github.com/physicistgaurav

LinkedIn: https://www.linkedin.com/in/gaurav-rizal-a37917183/

Medium: https://medium.com/@gauravrijal03

Twitter: https://twitter.com/rijalgaurav

Have a great day!

--

--