top

React and Firebase Authentication Using Email and Password

Authentication in React can be a complex feature to put in place. If you are building a complex application you will need a REST API to function as the back-end while your React application acts as the front-end. A bulk of the authentication work will happen server side. How does Firebase fit into this? Firebase provides you with an easy way to authenticate users, along with a host of other features.The source code for this tutorial is available at Github.Firebase ConsoleLet’s get started with Firebase console to create a new project.Enter the name for your project in the pop-up that appears and submit. You’ll need to enable the authentication type that we’ll be making use of, which is Email and Password. Follow the directions shown in the image below.Application ScaffoldWe will generate our application using create-react-app. If you do not have that installed on your machine already, you can run the command below:npm install create-react-app -gNow you can generate the applicationcreate-react-app react-firebase cd react-firebase/We’ll be making use of the following packages:React Router — for routingFirebase — to connect to our project instance on Firebase consoleRebass — to make the application look betterLet’s install themyarn add react-router-dom firebase rebassFirebase Set UpWe need to create a configuration file that will enable the application to connect to our Firebase instance. First, get your config from your Firebase console.Create a new file in your src directory, import firebase and paste the config from Firebase console. Here is a sample of how the file should look like:#src/firebase.js import firebase from 'firebase'; const config = {  apiKey: 'xxxxxx',  authDomain: 'xxxxxx.firebaseapp.com',  databaseURL: 'https://xxxxxx.firebaseio.com',  projectId: 'xxxxxx',  storageBucket: '',  messagingSenderId: 'xxxxxx', }; firebase.initializeApp(config); export default firebase;Public RoutesReact and Firebase authentication using Email and Password includes two types of routes: private and public. The Home, Login and Register routes will be public. While the Dashboard route will be private. Let’s create those.The Home component will be a simple component like this:import React from 'react'; import { Container, Row, Column, Heading } from 'rebass'; const Home = () => {   return (     <Container>       <Row>         <Column>           <Heading>This is home</Heading>         </Column>       </Row>     </Container>   ); }; export default Home;In the Home component, we are only rendering a text.The Register component will contain two input fields for email and password, along with a submit button. The state of the email and password field will be changed as values are typed in. When the button is clicked, we want to trigger a method that submits the form value and creates a new account for the user. Let’s see that in the code.import React, { Component } from 'react'; import { withRouter } from 'react-router-dom'; import { Container, Flex, Box, Input, Button, Subhead, Text } from 'rebass'; import firebase from './firebase'; class Register extends Component {  state = {    email: '',    password: '',    error: null,  }; handleInputChange = (event) => {    this.setState({ [event.target.name]: event.target.value });  }; handleSubmit = (event) => {    event.preventDefault();    const { email, password } = this.state; firebase      .auth()      .createUserWithEmailAndPassword(email, password)      .then((user) => {        this.props.history.push('/');      })      .catch((error) => {        this.setState({ error: error });      });  };  render() {    const { email, password, error } = this.state;    return (      <Container>        <Flex>          <Box>            <Subhead>Register</Subhead>          </Box>        </Flex>        {error ? (          <Flex>            <Box>              <Text>{error.message}</Text>            </Box>          </Flex>        ) : null}        <Flex>          <Box>            <form onSubmit={this.handleSubmit}>              <Input type="text" name="email" placeholder="Email" value={email} onChange={this.handleInputChange} />              <Input                type="password"                name="password"                placeholder="Password"                value={password}                onChange={this.handleInputChange}              />              <Button children="Register" />            </form>          </Box>        </Flex>      </Container>    );  } } export default withRouter(Register);The initial state of email and password is an empty string. There are possibilities of our users making mistakes which will result in errors. So, we need to handle this — that’s why we have a const variable for this. The handleInputChange() method is called whenever a value is entered in any of the form input fields. It updates the state of either the email and password with the entered value. The handleSubmit() method is called when the user clicks the submit button. We use ES6 destructuring to get the values for email and password. Next, we use the Firebase createUserWithEmailAndPassword()method which is available in auth() to create the user using the email and password we obtained. Upon authentication, the user can then access the dashboard.The Login component will look like the Register component.import React, { Component } from 'react'; import { withRouter } from 'react-router-dom'; import { Container, Flex, Box, Input, Button, Subhead, Text } from 'rebass'; import firebase from './firebase'; class Login extends Component {  state = {    email: '',    password: '',    error: null,  }; handleInputChange = (event) => {    this.setState({ [event.target.name]: event.target.value });  }; handleSubmit = (event) => {    event.preventDefault();    const { email, password } = this.state; firebase      .auth()      .signInWithEmailAndPassword(email, password)      .then((user) => {        this.props.history.push('/');      })      .catch((error) => {        this.setState({ error: error });      });  };  render() {    const { email, password, error } = this.state;    return (      <Container>        <Flex>          <Box>            <Subhead>Log In</Subhead>          </Box>        </Flex>        {error ? (          <Flex>            <Box>              <Text>{error.message}</Text>            </Box>          </Flex>        ) : null}        <Flex>          <Box>            <form onSubmit={this.handleSubmit}>              <Input type="text" name="email" placeholder="Email" value={email} onChange={this.handleInputChange} />              <Input                type="password"                name="password"                placeholder="Password"                value={password}                onChange={this.handleInputChange}              />              <Button children="Log In" />            </form>          </Box>        </Flex>      </Container>    );  } } export default withRouter(Login);The main difference is the use of signInWithEmailAndPassword() method which is provided to us by Firebase.If you look at the export line of both files you will see that the exported component is wrapped as a value passed to withRouter. We are using it to access the history object. Without it, we will not be able to direct the registered or logged in users.The Logout feature will be a component that renders a button.import React from 'react'; import { Button } from 'rebass'; import firebase from 'firebase'; const logOutUser = () => {  firebase.auth().signOut(); }; const LogOut = () => {  return <Button onClick={logOutUser} children="Log Out" />; }; export default LogOut;When the button is clicked it will call a method which is wired to call Firebase’s signOut() method.Protected RouteThe /dashboard route has to be accessible to only authenticated users. For that, to work, we need to create a special kind of route that checks whether the user is authenticated or not. First, we need to create an authenticated, which will be passed down the component tree. This state will be created in the App component.import React, { Component } from 'react'; import Navigation from './Navigation'; import firebase from './firebase'; class App extends Component {  state = {    authenticated: false,  };  componentDidMount() {    firebase.auth().onAuthStateChanged((authenticated) => {      authenticated        ? this.setState(() => ({            authenticated: true,          }))        : this.setState(() => ({            authenticated: false,          }));    });  }  render() {    return <Navigation authenticated={this.state.authenticated} />;  } } export default App;componentDidMount() is a lifecycle method that is executed after the first render. In the lifecycle method we have onAuthStateChanged(). This is a Firebase function that receives an anonymous function as an input. The anonymous function has access to authenticated. This function is called whenever the state of authenticated changes.The state is then passed down to the Navigation component as authenticated props. You will see how we make use of it there.Let’s create the ProtectedRoute component.import React from 'react'; import { Route, Redirect } from 'react-router-dom'; const ProtectedRoute = ({ component: Component, ...rest, authenticated }) => {  return <Route render={(props) => (authenticated ? <Component {...props} /> : <Redirect to="/login" />)} {...rest} />; }; export default ProtectedRoute;The ProtectedRoute component makes use of the same API as Route. It renders a Route which will match depending on the value of authenticated since no path was supplied. If the value of authenticated is true, the component which will be passed when ProtectedRoute component is used in the Navigation component will be rendered. Else the user will be redirected to the login page.Dashboard Component and NavigationThe Dashboard component is going to be visible for only authenticated users. For now, we’ll point users there, after they are logged in or registered. It will be as simple as the Home component.import React from 'react'; import { Container, Flex, Box, Heading } from 'rebass'; const Dashboard = () => {  return (    <Container>      <Flex>        <Box>          <Heading>Welcome!</Heading>        </Box>      </Flex>    </Container>  ); }; export default Dashboard;Next, let’s create the Navigationimport React, { Component } from 'react'; import { Row, Column } from 'rebass'; import { BrowserRouter as Router, Route, Switch, NavLink } from 'react-router-dom'; import Home from './Home'; import Login from './Login'; import Register from './Register'; import Dashboard from './Dashboard'; import ProtectedRoute from './ProtectedRoute'; import LogOut from './LogOut'; class Navigation extends Component {  render() {    return (      <Router>        <div>          <Row>            <Column>              <NavLink to="/">Home</NavLink>              {this.props.authenticated ? (                <span>                  <NavLink to="/dashboard">Dashboard</NavLink>                  <LogOut />                </span>              ) : (                <span>                  <NavLink to="/login">Login</NavLink>                  <NavLink to="/register">Register</NavLink>                </span>              )}            </Column>          </Row> <Switch>            <Route exact path="/" component={Home} />            <Route authenticated={this.props.authenticated} path="/login" component={Login} />            <Route path="/register" component={Register} />            <ProtectedRoute authenticated={this.props.authenticated} path="/dashboard" component={Dashboard} />          </Switch>        </div>      </Router>    );  } } export default Navigation;The links that will be displayed on the navigation depends on the authenticated state of the user — when authenticated is true, the link dashboard and the logout button will be shown, else the register and login links will be shown. When a user who is not authenticated tries to access the /dashboard route through the browser’s address bar, the user will be redirected to /login.Remember we passed authenticated from the App component to the Navigation component as props. It is the value of this props that we use to determine if a user is authenticated or not. The props are also passed down to the ProtectedRoute component. Now start up your server to see this in action.ConclusionDepending on how complex your application is, you can harness the power of Firebase. Firebase also provides you with other sign-in methods such as Facebook, Google, e.t.c. From your Firebase console, you can be able to manage users who are registered on your application.
Rated 4.0/5 based on 24 customer reviews
Normal Mode Dark Mode

React and Firebase Authentication Using Email and Password

kingsley Silaschijiok
Blog
14th Jul, 2018
React and Firebase Authentication Using Email and Password

Authentication in React can be a complex feature to put in place. If you are building a complex application you will need a REST API to function as the back-end while your React application acts as the front-end. A bulk of the authentication work will happen server side. How does Firebase fit into this? Firebase provides you with an easy way to authenticate users, along with a host of other features.

The source code for this tutorial is available at Github.


Firebase Console

Let’s get started with Firebase console to create a new project.


Firebase Console

Enter the name for your project in the pop-up that appears and submit. You’ll need to enable the authentication type that we’ll be making use of, which is Email and Password. Follow the directions shown in the image below.


authentication



Application Scaffold

We will generate our application using create-react-app. If you do not have that installed on your machine already, you can run the command below:

npm install create-react-app -g

Now you can generate the application

create-react-app react-firebase
cd react-firebase/

We’ll be making use of the following packages:

React Router — for routing

Firebase — to connect to our project instance on Firebase console

Rebass — to make the application look better

Let’s install them

yarn add react-router-dom firebase rebass


Firebase Set Up

We need to create a configuration file that will enable the application to connect to our Firebase instance. First, get your config from your Firebase console.

Firebase Set Up

Create a new file in your src directory, import firebase and paste the config from Firebase console. Here is a sample of how the file should look like:

#src/firebase.js
import firebase from 'firebase';
const config = {
 apiKey: 'xxxxxx',
 authDomain: 'xxxxxx.firebaseapp.com',
 databaseURL: 'https://xxxxxx.firebaseio.com',
 projectId: 'xxxxxx',
 storageBucket: '',
 messagingSenderId: 'xxxxxx',
};
firebase.initializeApp(config);
export default firebase;


Public Routes

React and Firebase authentication using Email and Password includes two types of routes: private and public. The Home, Login and Register routes will be public. While the Dashboard route will be private. Let’s create those.

The Home component will be a simple component like this:

import React from 'react'; 
import { Container, Row, Column, Heading } from 'rebass'; 
const Home = () => { 
  return ( 
    <Container> 
      <Row> 
        <Column> 
          <Heading>This is home</Heading> 
        </Column> 
      </Row> 
    </Container> 
  ); 
}; 
export default Home;

In the Home component, we are only rendering a text.

The Register component will contain two input fields for email and password, along with a submit button. The state of the email and password field will be changed as values are typed in. When the button is clicked, we want to trigger a method that submits the form value and creates a new account for the user. Let’s see that in the code.

import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import { Container, Flex, Box, Input, Button, Subhead, Text } from 'rebass';
import firebase from './firebase';
class Register extends Component {
 state = {
   email: '',
   password: '',
   error: null,
 };
handleInputChange = (event) => {
   this.setState({ [event.target.name]: event.target.value });
 };
handleSubmit = (event) => {
   event.preventDefault();
   const { email, password } = this.state;
firebase
     .auth()
     .createUserWithEmailAndPassword(email, password)
     .then((user) => {
       this.props.history.push('/');
     })
     .catch((error) => {
       this.setState({ error: error });
     });
 };
 render() {
   const { email, password, error } = this.state;
   return (
     <Container>
       <Flex>
         <Box>
           <Subhead>Register</Subhead>
         </Box>
       </Flex>
       {error ? (
         <Flex>
           <Box>
             <Text>{error.message}</Text>
           </Box>
         </Flex>
       ) : null}
       <Flex>
         <Box>
           <form onSubmit={this.handleSubmit}>
             <Input type="text" name="email" placeholder="Email" value={email} onChange={this.handleInputChange} />
             <Input
               type="password"
               name="password"
               placeholder="Password"
               value={password}
               onChange={this.handleInputChange}
             />
             <Button children="Register" />
           </form>
         </Box>
       </Flex>
     </Container>
   );
 }
}
export default withRouter(Register);

The initial state of email and password is an empty string. There are possibilities of our users making mistakes which will result in errors. So, we need to handle this — that’s why we have a const variable for this. The handleInputChange() method is called whenever a value is entered in any of the form input fields. It updates the state of either the email and password with the entered value. The handleSubmit() method is called when the user clicks the submit button. We use ES6 destructuring to get the values for email and password. Next, we use the Firebase createUserWithEmailAndPassword()method which is available in auth() to create the user using the email and password we obtained. Upon authentication, the user can then access the dashboard.

The Login component will look like the Register component.

import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import { Container, Flex, Box, Input, Button, Subhead, Text } from 'rebass';
import firebase from './firebase';
class Login extends Component {
 state = {
   email: '',
   password: '',
   error: null,
 };
handleInputChange = (event) => {
   this.setState({ [event.target.name]: event.target.value });
 };
handleSubmit = (event) => {
   event.preventDefault();
   const { email, password } = this.state;
firebase
     .auth()
     .signInWithEmailAndPassword(email, password)
     .then((user) => {
       this.props.history.push('/');
     })
     .catch((error) => {
       this.setState({ error: error });
     });
 };
 render() {
   const { email, password, error } = this.state;
   return (
     <Container>
       <Flex>
         <Box>
           <Subhead>Log In</Subhead>
         </Box>
       </Flex>
       {error ? (
         <Flex>
           <Box>
             <Text>{error.message}</Text>
           </Box>
         </Flex>
       ) : null}
       <Flex>
         <Box>
           <form onSubmit={this.handleSubmit}>
             <Input type="text" name="email" placeholder="Email" value={email} onChange={this.handleInputChange} />
             <Input
               type="password"
               name="password"
               placeholder="Password"
               value={password}
               onChange={this.handleInputChange}
             />
             <Button children="Log In" />
           </form>
         </Box>
       </Flex>
     </Container>
   );
 }
}
export default withRouter(Login);

The main difference is the use of signInWithEmailAndPassword() method which is provided to us by Firebase.

If you look at the export line of both files you will see that the exported component is wrapped as a value passed to withRouter. We are using it to access the history object. Without it, we will not be able to direct the registered or logged in users.

The Logout feature will be a component that renders a button.

import React from 'react';
import { Button } from 'rebass';
import firebase from 'firebase';
const logOutUser = () => {
 firebase.auth().signOut();
};
const LogOut = () => {
 return <Button onClick={logOutUser} children="Log Out" />;
};
export default LogOut;

When the button is clicked it will call a method which is wired to call Firebase’s signOut() method.


Protected Route

The /dashboard route has to be accessible to only authenticated users. For that, to work, we need to create a special kind of route that checks whether the user is authenticated or not. First, we need to create an authenticated, which will be passed down the component tree. This state will be created in the App component.

import React, { Component } from 'react';
import Navigation from './Navigation';
import firebase from './firebase';
class App extends Component {
 state = {
   authenticated: false,
 };
 componentDidMount() {
   firebase.auth().onAuthStateChanged((authenticated) => {
     authenticated
       ? this.setState(() => ({
           authenticated: true,
         }))
       : this.setState(() => ({
           authenticated: false,
         }));
   });
 }
 render() {
   return <Navigation authenticated={this.state.authenticated} />;
 }
}
export default App;

componentDidMount() is a lifecycle method that is executed after the first render. In the lifecycle method we have onAuthStateChanged(). This is a Firebase function that receives an anonymous function as an input. The anonymous function has access to authenticated. This function is called whenever the state of authenticated changes.

The state is then passed down to the Navigation component as authenticated props. You will see how we make use of it there.

Let’s create the ProtectedRoute component.

import React from 'react';
import { Route, Redirect } from 'react-router-dom';
const ProtectedRoute = ({ component: Component, ...rest, authenticated }) => {
 return <Route render={(props) => (authenticated ? <Component {...props} /> : <Redirect to="/login" />)} {...rest} />;
};
export default ProtectedRoute;

The ProtectedRoute component makes use of the same API as Route. It renders a Route which will match depending on the value of authenticated since no path was supplied. If the value of authenticated is true, the component which will be passed when ProtectedRoute component is used in the Navigation component will be rendered. Else the user will be redirected to the login page.


Dashboard Component and Navigation

The Dashboard component is going to be visible for only authenticated users. For now, we’ll point users there, after they are logged in or registered. It will be as simple as the Home component.

import React from 'react';
import { Container, Flex, Box, Heading } from 'rebass';
const Dashboard = () => {
 return (
   <Container>
     <Flex>
       <Box>
         <Heading>Welcome!</Heading>
       </Box>
     </Flex>
   </Container>
 );
};
export default Dashboard;

Next, let’s create the Navigation

import React, { Component } from 'react';
import { Row, Column } from 'rebass';
import { BrowserRouter as Router, Route, Switch, NavLink } from 'react-router-dom';
import Home from './Home';
import Login from './Login';
import Register from './Register';
import Dashboard from './Dashboard';
import ProtectedRoute from './ProtectedRoute';
import LogOut from './LogOut';
class Navigation extends Component {
 render() {
   return (
     <Router>
       <div>
         <Row>
           <Column>
             <NavLink to="/">Home</NavLink>
             {this.props.authenticated ? (
               <span>
                 <NavLink to="/dashboard">Dashboard</NavLink>
                 <LogOut />
               </span>
             ) : (
               <span>
                 <NavLink to="/login">Login</NavLink>
                 <NavLink to="/register">Register</NavLink>
               </span>
             )}
           </Column>
         </Row>
<Switch>
           <Route exact path="/" component={Home} />
           <Route authenticated={this.props.authenticated} path="/login" component={Login} />
           <Route path="/register" component={Register} />
           <ProtectedRoute authenticated={this.props.authenticated} path="/dashboard" component={Dashboard} />
         </Switch>
       </div>
     </Router>
   );
 }
}
export default Navigation;

The links that will be displayed on the navigation depends on the authenticated state of the user — when authenticated is true, the link dashboard and the logout button will be shown, else the register and login links will be shown. When a user who is not authenticated tries to access the /dashboard route through the browser’s address bar, the user will be redirected to /login.

Remember we passed authenticated from the App component to the Navigation component as props. It is the value of this props that we use to determine if a user is authenticated or not. The props are also passed down to the ProtectedRoute component. Now start up your server to see this in action.


Conclusion

Depending on how complex your application is, you can harness the power of Firebase. Firebase also provides you with other sign-in methods such as Facebook, Google, e.t.c. From your Firebase console, you can be able to manage users who are registered on your application.

kingsley

kingsley Silaschijiok

Author

Kingsley Silas Chijiok is working as a Software Engineer Intern at Qeturah Dot Com. He is an expert in  Web Development, JavaScript, and CSS.


Website : https://www.github.com/kinsomicrote

Leave a Reply

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

Top comments

James Maria

30 November 2018 at 3:39pm
Excellent web site you got here difficult to find high quality writing like yours nowadays,I honestly appreciate people like you! Take care

SUBSCRIBE OUR BLOG

Follow Us On

Share on

other Blogs

20% Discount