Sometimes you just need to make a fast prototype and you don’t want to mess with backend, authentication, authorization and all of that. Here is where Google’s firebase can help you. In this tutorial I’ll show you haw to connect your react app with Firebase authentication module.

What Are We Going To Build

Super simple app. Just 3 screens: Sign up, Log in and Home screen.

We’ll use Firebase Authentication module to handle login/signup and React router to manage routing.

Make sure to read till the end, I’ll post a link to github repo with example code there.

Set Up Firebase

Create New Firebase App

First go to firebase console and create new app.

New firebase app

Add Auth Method

Click Authentication and then SET UP SIGN-IN METHOD.

New sign in method

Enable Email/Password authentication.

Get Firebase Credentials

Go to project settings:

New sign in method

And select Add firebase to your web app. Copy your credentials from there and save them to .env file in your project’s root.

REACTAPPFIREBASEKEY=yourkey 
REACTAPPFIREBASEDOMAIN=yourappid.firebaseapp.com
REACT
APPFIREBASEDATABASE=https://yourappid.firebaseio.com
REACTAPPFIREBASEPROJECTID=yourappid
REACTAPPFIREBASESTORAGEBUCKET=yourstoragebucket
REACTAPPFIREBASESENDERID=senderid

create-react-app webpack config automatically loads environment variables that start with REACTAPP, so we can reference them.

Read more about it in create-react-app documentation

Set Up The Frontend

We will set up the application using create-react-app. I assume that you have modern verion of npm so I’m going to use npx to run the script.

npx create-react-app firebase-auth-tutorial 

Also we’ll need routing so install React Router as well:

Also remove src/index.css, src/App.css and src/App.test.js files. We won’t need them now.

Connect App To Firebase

First install firebase package:

Now create file src/base.js with following contents:

import firebase from "firebase"; const app = firebase.initializeApp({ apiKey: process.env.REACTAPPFIREBASEKEY, authDomain: process.env.REACTAPPFIREBASEDOMAIN, databaseURL: process.env.REACTAPPFIREBASEDATABASE, projectId: process.env.REACTAPPFIREBASEPROJECTID, storageBucket: process.env.REACTAPPFIREBASESTORAGEBUCKET, messagingSenderId: process.env.REACTAPPFIREBASESENDER_ID 
}); export default app;

Add Routing

Open src/App.js and make it look like this:

import React from "react"; 
import { BrowserRouter as Router, Route } from "react-router-dom"; import Home from "./Home";
import Login from "./Login";
import SignUp from "./SignUp"; const App = () => { return ( <Router> <div> <Route exact path="/" component={Home} />
<Route exact path="/login" component={Login} />
<Route exact path="/signup" component={SignUp} />
</div>
</Router>
);
}; export default App;

Create Home, LogIn and SignUp components, for now just render some header. Here, for instance src/Home.js:

import React from "react"; const Home = () => { return ( <h1>Home</h1> 
)
} export default Home

Run the application. You should have all routes available.

Create The SignUp And LogIn Components

Now let’s add some sign up logic. Create the src/SignUp directory and move our SignUp.js there. Also rename it to SignUpView.js. Make it look like this:

src/SignUp/SignUpView.js

import React from "react"; const SignUpView = ({ onSubmit }) => { return ( <div> <h1>Sign up</h1> <form onSubmit={onSubmit}> <label> Email <input name="email" type="email" placeholder="Email" /> </label> <label> Password <input name="password" type="password" placeholder="Password" /> </label> <button type="submit">Sign Up</button> </form> </div> );  
}; export default SignUpView;

This is simple presentational component. We get the onSubmit handler as one of the props and attach it to our form. We defined email and password fields and added Sign Up button.

Now create the container component `src/SignUp/index.js:

import React, { Component } from "react";  
import { withRouter } from "react-router";  
import app from "../base"; import SignUpView from "./SignUpView"; class SignUpContainer extends Component { handleSignUp = async event => { event.preventDefault(); const { email, password } = event.target.elements; try { const user = await app .auth() .createUserWithEmailAndPassword(email.value, password.value); this.props.history.push("/"); } catch (error) { alert(error); } }; render() { return <SignUpView onSubmit={this.handleSignUp} />;  
 }  
} export default withRouter(SignUpContainer);  

This component will handle our sign up logic.

Let’s look at our handleSignUp function. It’s defined as an anonymous arrow function. I did it here to avoid using bind(this).

In this example I really need class level this because of the history object I get from props by using withRouter wrapper. Otherwize I’d better define it as a regular function.

So in this function I preventDefault to avoid reloading page, get password and email from form elements and try to create new user on Firebase using createUserWithEmailAndPassword function.

Our LogIn component will be almost the same, just change the createUserWithEmailAndPassword function call to signInWithEmailAndPassword

Add Private Routes

Ok, great now we can sign up, and log in, but unfortunately it doesn’t make much sense, because home page is available even for the non-authorized user. Let’s fix it.

Create src/PrivateRoute.js with following contents:

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

Basically this component will conditionally render either passed Component or <Redirect/> block, depending on passed authenticated prop.

Now let’s use it in our App.js. Change the Home route to PrivateRoute:

<PrivateRoute exact path="/" component={Home} authenticated={this.state.authenticated}/>  

We used authenticated field of our state, but it doesn’t exist yet. Let’s fix it.

Monitoring Auth Status

First remake your App.js to normal Component and set initial state:

class App extends Component { state = { loading: true, authenticated: false, user: null }; render(){ const { authenticated, loading } = this.state; if (loading) { return <p>Loading..</p>;  
 } return ( <Router> <div> <PrivateRoute exact path="/" component={Home} authenticated={authenticated} />  
 <Route exact path="/login" component={LogIn} />  
 <Route exact path="/signup" component={SignUp} />  
 </div>  
 </Router>  
 ) }  
}  

Now add componentWillMount to you App.js with following cotents:

componentWillMount() { app.auth().onAuthStateChanged(user => { if (user) { this.setState({ authenticated: true, currentUser: user, loading: false }); } else { this.setState({ authenticated: false, currentUser: null, loading: false }); } });  
}  

So now we’ll render Loading... until we get data from Firebase and update our state. Then we render routing and PrivateRoute redirects us to Log In page if we are not signed up.

What To Do Next

Now you can add a redirect from login page if you are logged in already, also you can add log out functionality (go read firebase documentation)

Also with this knowledge you can add authentication to wallet app from the React Ethereum Tutorial and build your own ICO platform!

So go crazy, build stuff and see you next time.

Oh, btw – here is your github link