Implementing a ‘Forgot Password’ feature in React Native with Firebase

In a few of my previous posts, you’ve built a React Native app using Firebase as the backend service provider for email authentication, storing a user’s data upon successful signup.

Let’s add another common yet useful and necessary feature in our current app structure: Forgot Password. This feature will require another screen in the current React Native app. To follow this tutorial, you can work through any of the previous posts if you’re a beginner in the React Native world:

Or if you’re already comfortable in understanding React Native code, dive deep into the source code or download it from the GitHub repo release here.

After downloading the source code, please navigate inside the project directory and install dependencies by running the command npm install or yarn install.

Table of Contents

  • Requirements
  • Add Forgot Password Screen
  • Add a method to send a password reset email
  • Create a Form
  • Handle Password Reset

Requirements

To follow this tutorial, please make sure the following libraries are installed on your local development environment and you can access the services mentioned below.

  • Nodejs (>= 10.x.x) with npm/yarn installed
  • expo-cli (>= 3.x.x) (previously known as create-react-native-app)
  • Firebase account (free tier will do)

Add Forgot Password Screen

Let’s start with a basic screen and hook it up with our current navigation flow so that an app user will be able to navigate to this new screen from the Login screen.

Create a new file screens/ForgotPassword.js with some dummy text.

import React, { Component } from 'react'
import { Text, View } from 'react-native'

class ForgotPassword extends Component {
  render() {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <Text>Forgot Password Screen</Text>
      </View>
    )
  }
}

export default ForgotPassword

Open the AuthNavigation.js file and this new class component as show below.

import { createStackNavigator } from 'react-navigation-stack'
import Login from '../screens/Login'
import Signup from '../screens/Signup'
import ForgotPassword from '../screens/ForgotPassword'

const AuthNavigation = createStackNavigator(
  {
    Login: { screen: Login },
    Signup: { screen: Signup },
    ForgotPassword: { screen: ForgotPassword }
  },
  {
    initialRouteName: 'Login',
    headerMode: 'none'
  }
)

export default AuthNavigation

Lastly, open the Login.js file. Logically, this is where a button to navigate to this new ForgotPassword component should exist. First, add the handler method goToForgotPassword inside the Login class component with the other handler methods.

goToForgotPassword = () => this.props.navigation.navigate('ForgotPassword')

Passing the name of the route as the first parameter to navigation.navigate() is how you navigate from one screen to the other using the react-navigation library. In this case, the name of the route is going to be ForgotPassword.

Next, add a Button component after the Signup button. The value of the onPress prop of this button is going to be the handler method.

<Button
  title='Forgot Password?'
  onPress={this.goToForgotPassword}
  titleStyle={{
    color: '#039BE5'
  }}
  type='clear'
/>

Now, open a simulator or a real device with an Expo client installed and run the command expo start from a terminal window. You’ll be welcomed by the following screen.

Clicking on the button that says Forgot Password? will lead you to the new screen.

Add a method to send a password reset email

The Firebase authentication module provides a method that you can use in React Native apps to send a link to the app user’s registered email address. Users can click the link to reset their password. Firebase does this on its own. You don’t have to write the server code to add this functionality to your app.

To start, open the config/Firebase/firebase.js file and add the following method. You’ll use this method inside the ForgotPassword component by providing the user’s email as input.

passwordReset: email => {
  return firebase.auth().sendPasswordResetEmail(email)
},

That’s all you need to configure the Firebase app to make sure it sends the email to the registered email id.

To extend this further, you can try and customize the email template that Firebase uses to send the reset password link here.

Create a Form

Using the previously obtained knowledge of Formik and Yup, let’s add an input field and a button. The input field will take in the email and the button will be responsible for performing the form submission. In other words, it will trigger the network to reset the user’s email in a handler method.

Open the ForgotPassword.js file and add the following import statements:

import React, { Component, Fragment } from 'react'
import { Text, SafeAreaView, View, StyleSheet } from 'react-native'
import { Formik } from 'formik'
import * as Yup from 'yup'
import FormInput from '../components/FormInput'
import FormButton from '../components/FormButton'
import ErrorMessage from '../components/ErrorMessage'
import { withFirebaseHOC } from '../config/Firebase'

After the import statements, adda validationSchema object. This object is similar to the one used in the Login component and will help determine whether the input provided already exists as a registered email or not.

const validationSchema = Yup.object().shape({
  email: Yup.string()
    .label('Email')
    .email('Enter a valid email')
    .required('Please enter a registered email')
})

Next, go to the render function and replace its existing content with the form below:

render() {
    return (
      <SafeAreaView style={styles.container}>
        <Text style={styles.text}>Forgot Password?</Text>
        <Formik
          initialValues={{ email: '' }}
          onSubmit={(values, actions) => {
            this.handlePasswordReset(values, actions)
          }}
          validationSchema={validationSchema}>
          {({
            handleChange,
            values,
            handleSubmit,
            errors,
            isValid,
            touched,
            handleBlur,
            isSubmitting
          }) => (
            <Fragment>
              <FormInput
                name='email'
                value={values.email}
                onChangeText={handleChange('email')}
                placeholder='Enter email'
                autoCapitalize='none'
                iconName='ios-mail'
                iconColor='#2C384A'
                onBlur={handleBlur('email')}
              />
              <ErrorMessage errorValue={touched.email && errors.email} />
              <View style={styles.buttonContainer}>
                <FormButton
                  buttonType='outline'
                  onPress={handleSubmit}
                  title='Send Email'
                  buttonColor='#039BE5'
                  disabled={!isValid || isSubmitting}
                />
              </View>
              <ErrorMessage errorValue={errors.general} />
            </Fragment>
          )}
        </Formik>
      </SafeAreaView>
    )
  }

In the above code snippet, the elements such as FormInput, FormButton, and ErrorMessage are some re-usable custom presentational components that you can find inside components/ directory. this.handlePasswordReset(values, actions) is the handler method that accepts two parameters. You’ll write the logic behind this method in the next section.

The corresponding styles to the component are as follows:

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    marginTop: 150
  },
  text: {
    color: '#333',
    fontSize: 24,
    marginLeft: 25
  },
  buttonContainer: {
    margin: 25
  }
})

Lastly, don’t forget to wrap the ForgotPassword method with the Firebase High Order Component withFirebaseHOC to use the passwordReset method as props.

export default withFirebaseHOC(ForgotPassword)

Now if we go back to the simulator, we’ll seethe following screen:

Handle Password Reset

Inside the ForgotPassword component create a new handler method called handlePasswordReset. This is going to be an asynchronous function that will accept the user’s email as the parameter from Formik’s values.

Also, pass the actions from Formik as the second parameter. Instead of just console logging the error values, to display the error on the screen, Formik provides setFieldError.

handlePasswordReset = async (values, actions) => {
  const { email } = values

  try {
    await this.props.firebase.passwordReset(email)
    console.log('Password reset email sent successfully')
    this.props.navigation.navigate('Login')
  } catch (error) {
    actions.setFieldError('general', error.message)
  }
}

The above snippet signifies that if the email provided as the input is valid, it will send the request to reset the password. On success, a message on Expo’s console will be displayed, as shown below:

Also, on success, it will navigate the user back to the login screen. On errors, the code inside the catch block will be triggered.

To try it out, register a user with a valid email address so that you can receive an email. On registering a new user, the app will log you in. Sign out of the app, which will take you back to the login screen. Next, go the Forgot Password screen and enter the valid email.

You’ll receive an email like the one below. It uses the default Firebase template. To demonstrate, I’m using my personal Gmail address.

Click on the link and it will redirect you to a webpage.

Upon a successful password change, it will prompt the following message to the user.

Conclusion

That’s it! It’s really that simple. With a new password, you can try to login to the app now, and it should work. If you’ve come this far, I hope you enjoyed reading this post. These are some of the strategies I try to follow with any Firebase + React Native projects.

I hope any part of the codebase used in this tutorial helps you. To find the complete code, you will have to visit this GitHub repo release.

I often write on Nodejs, Reactjs, and React Native. You can subscribe to my weekly newsletter to receive all updates on new posts straight in your inbox 💌

Fritz

Author

Comments 0 Responses

Leave a Reply

Your email address will not be published. Required fields are marked *