Authentication in React Native using Firebase part 2

Obinna Okwuolisa
Backticks & Tildes
Published in
6 min readOct 18, 2018

In the last part of this tutorial, we created the component for a login display. In this part, we are going to make the login work.

First, we register the project on Firebase.

NB: You need a google account to sign in

Locate and click the Go to console button on the upper-right corner of the screen.

Click on Add project Give the name of the project Authenticator, accept terms and create the project.

In the project dashboard, click on Authentication

Click on set up sign-in method

Click on the authentication method you want for your app. In our case, we chose Email/Password

Click on enable and save

Go to your development environment, open a terminal and install firebase client

npm install -- save firebase

import firebase to the project. On App.js add

import firebase from 'firebase'

Then we are going to set up a configuration for the firebase. To get the configuration, we head over to firebase console.

Click on Web setup and copy the config object.

On our project, go to App.jsand add the code below in the App class just before the rendermethod.

componentDidMount() {
let config = {
apiKey: "**********************",
authDomain: "******************",
databaseURL: "*****************",
projectId: "*******************",
storageBucket: "***************",
messagingSenderId: "***********"
};
firebase.initializeApp(config);
}

The code above initializes Firebase with the config we just copied from the Firebase console anytime the app loads. componentDidMount is a lifecycle method that always runs anytime the app loads.

We will also keep track of the error in the state. Update the constructor like so

constructor(props) {
super(props);
this.state = { email: '', password: '', error: ''};
}

Next, we add a function to sign the user in or create an account if the user does not exist in the database. In the LoginForm.js add the following method before the render method.

onButtonPress() {
this.setState({ error: '', loading: true })
const { email, password } = this.state;
firebase.auth().signInWithEmailAndPassword(email, password)
.then(this.onLoginSuccess.bind(this))
.catch(() => {
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(this.onLoginSuccess.bind(this))
.catch((error) => {
let errorCode = error.code
let errorMessage = error.message;
if (errorCode == 'auth/weak-password') {
this.onLoginFailure.bind(this)('Weak password!')
} else {
this.onLoginFailure.bind(this)(errorMessage)
}
});
});
}
onLoginSuccess() {
this.setState({
email: '', password: '', error: '', loading: false
})
}
onLoginFailure(errorMessage) {
this.setState({ error: errorMessage, loading: false })
}

So here is what is going on, when a user signs in, the method firebase.auth().signInWithEmail() is called, and on a successful sign in, we call the onLoginSuccess function. However, if the user does not exist in our database, it tries to create a new account for the user by calling the firebase.auth().createUserWithEmailAndPassword() . When it creates the user account, it calls the onLoginSuccess else it calls onLoginFailure with the respective error message.

On the render method, update the Button tag with onButtonPress callback function like so

<Button title="Sign in" onPress={this.onButtonPress.bind(this)} />

Anytime the button is clicked, it calls the onButtonPress

When a sign-in is unsuccessful, we display a nice error message. Add the following code to the last part of the render method before the </View> tag

<Text style={styles.errorTextStyle}>
{this.state.error}
</Text>

Add the styling

const styles = {
errorTextStyle: {
fontSize: 18,
alignSelf: 'center',
color: 'red'
}
}

We need a nice little spinner to show the app is processing the sign-in. To do that we import the ActivityIndicator from react-native like so

import { View, Button, Text, ActivityIndicator } from 'react-native';

Then render the spinner when loading is true. To do this, we create a new function that will render the Button component and the spinner conditionally.

renderButton() {
if (this.state.loading) {
return(
<View style={styles.spinnerStyle}>
<ActivityIndicator size={"small"} />
</View>
);
}
return (
<Button
title="Sign in"
onPress={this.onButtonPress.bind(this)}
/>
);
}

Add the renderButton in place of the <Button/>tag. The render method should look like

render() {
return (
<View>
<Input label="Email"
placeholder="user@mail.com"
value={this.state.email}
secureTextEntry={false}
onChangeText={email => this.setState({ email })}
/>
<Input label="Password"
placeholder="password"
value={this.state.password}
secureTextEntry={true}
onChangeText={password => this.setState({ password })}
/>
{this.renderButton()}

<Text style={styles.errorTextStyle}>
{this.state.error}
</Text>
</View>
);
}

When you reload the simulator, you should be able to sign in or see a nice error message when the sign-in is unsuccessful.

Now we can sign the user in. But there is more to be done. We need to hide the login form on a successful sign in and display a button for sign out. Let us tweak our code for sign out.

On App.js we need to monitor the state when a sign in is successful and when it's not. To do that, add a state just before componentDidMount like so

state = {loggedIn: null };

In the componentDidMount add the following code after firebase.initializeApp(config)

firebase.auth().onAuthStateChanged((user) => {
if(user){
this.setState({ loggedIn: true})
} else {
this.setState({loggedIn: false})
}
})

The firebase.auth()onAuthStateChanged() monitors the state of the authentication. If the user is signed in, we set the loggedIn state to true, if the user signs out, we set state to false. Next, we do a conditional rendering of the login form and update the render method like so

renderComponent() {
if (this.state.loggedIn) {
return (
<Button
title="Sign out"
onPress={() => firebase.auth().signOut()}
/>
);
}
return (
<LoginForm />
);
}
render() {
return (
<View>
<Header title='Authenticator' />
{this.renderComponent()}
</View>
);
}

We added a button to sign out the user after a successful login. When the button is clicked, it calls the firebase.auth().signout() method which signs out the user.

Your App.js file should look like this

import React, { Component } from 'react';
import { View, Button} from 'react-native';
import firebase from 'firebase'
import Header from './src/components/Header'
import LoginForm from './src/components/LoginForm'
export default class App extends Component {
state = { loggedIn: null };
componentDidMount() {
let config = {
apiKey: "**********************",
authDomain: "******************",
databaseURL: "*****************",
projectId: "*******************",
storageBucket: "***************",
messagingSenderId: "***********"
};
firebase.initializeApp(config);
firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.setState({ loggedIn: true })
} else {
this.setState({ loggedIn: false })
}
})
}
renderComponent() {
if (this.state.loggedIn) {
return (
<Button
title="Sign out"
onPress={() => firebase.auth().signOut()}
/>
);
} else {
return (
<LoginForm />
);
}
}
render() {
return (
<View>
<Header title='Authenticator' />
{this.renderComponent()}
</View>
);
}
}

Now when a user signs in, the login form is cleared.

When you sign in with a wrong password, you get an error message

The complete code for this project can be found here

Suggestions, questions and comments are welcome. Thanks for reading.

The end!

--

--