Posted on: Written by: K-Sato
⚠️ This article was posted over a year go. The information might be outdated. ⚠️

Table of Contents

Set up Firebase

Create a new app

First go to firebase console and create new app.

image

Add auth

Click Authentication and then click SET UP SIGN-IN METHOD.

image

And enable things you want to use to sign in.

image

Get firebase credentials

Go to your project settings and get the app’s firebase credentials.

image

The credentials look something like below

apiKey: "your_key",
authDomain: "your_app_id.firebaseapp.com",
databaseURL: "https://your_app_id.firebaseio.com",
projectId: "your_app_id",
storageBucket: "your_storage_bucket",
messagingSenderId: "sender_id",
appId: "your_app_id"

Set up the front end

Create your app.

$ create-react-app your-app-name
$ cd your-app-name

Install react-router and firebase packages.

$ yarn add firebase react-router react-router-dom

Connect the App to firebase

Paste your firebase credentials to .env.

// .env
REACT_APP_FIREBASE_KEY="your_key"
REACT_APP_FIREBASE_DOMAIN="your_app_id.firebaseapp.com"
REACT_APP_FIREBASE_DATABASE="https://your_app_id.firebaseio.com"
REACT_APP_FIREBASE_PROJECT_ID="your_app_id"
REACT_APP_FIREBASE_STORAGE_BUCKET="your_storage_bucket"
REACT_APP_FIREBASE_SENDER_ID="sender_id"

Create a new file src/base.js. And paste the code below. It initiates your firebase application with the given credentials.

import * as firebase from 'firebase/app'
import 'firebase/auth'

export const app = firebase.initializeApp({
  apiKey: process.env.REACT_APP_FIREBASE_KEY,
  authDomain: process.env.REACT_APP_FIREBASE_DOMAIN,
  databaseURL: process.env.REACT_APP_FIREBASE_DATABASE,
  projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
  storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.REACT_APP_FIREBASE_SENDER_ID,
})

Add context

Create src/auth/AuthProvider and put all the authentication logic in here. And we are going to pass the authentication data and functions through the component tree using Context.

import React, { useEffect, useState } from 'react'
import { app } from '../base.js'

export const AuthContext = React.createContext()

export const AuthProvider = ({ children }) => {
  const [currentUser, setCurrentUser] = useState(null)

  const login = async (email, password, history) => {
    try {
      await app.auth().signInWithEmailAndPassword(email, password)
      history.push('/')
    } catch (error) {
      alert(error)
    }
  }

  const signup = async (email, password, history) => {
    try {
      await app.auth().createUserWithEmailAndPassword(email, password)
      history.push('/')
    } catch (error) {
      alert(error)
    }
  }

  useEffect(() => {
    app.auth().onAuthStateChanged(setCurrentUser)
  }, [])

  return (
    <AuthContext.Provider
      value={{
        login: login,
        signup: signup,
        currentUser,
      }}
    >
      {children}
    </AuthContext.Provider>
  )
}

Add Private route

Create src/auth/PrivateRoute and paste the code below. The idea is that only authenticated users can access the private route.

import React, { useContext } from 'react'
import { Route } from 'react-router-dom'
import { AuthContext } from './AuthProvider'
import Login from './Login'

const PrivateRoute = ({ component: RouteComponent, ...options }) => {
  const { currentUser } = useContext(AuthContext)
  const Component = currentUser ? RouteComponent : Login

  return <Route {...options} component={Component} />
}

export default PrivateRoute

Add Routing

Open src/App.js paste the code below.

import React from 'react'
import { BrowserRouter as Router, Route } from 'react-router-dom'
import PrivateRoute from './auth/PrivateRoute'
import { AuthProvider } from './auth/AuthProvider'
import Home from './components/Home'
import Login from './auth/Login'
import SignUp from './auth/SignUp'

const App = () => {
  return (
    <AuthProvider>
      <Router>
        <div>
          <PrivateRoute exact path="/" component={Home} />
          <Route exact path="/login" component={Login} />
          <Route exact path="/signup" component={SignUp} />
        </div>
      </Router>
    </AuthProvider>
  )
}

export default App

Create Home, Login and Signup components.

Create the following compoentns.

src/components/Home.jsx

import React from 'react'
import { app } from '../base'

function Home(props) {
  return (
    <div>
      <h2>Home Page</h2>
      <button onClick={() => app.auth().signOut()}>Sign out</button>
    </div>
  )
}

export default Home

src/auth/Login.jsx

import React, { useContext } from 'react'
import { withRouter } from 'react-router'
import { AuthContext } from './AuthProvider'

const Login = ({ history }) => {
  const { login } = useContext(AuthContext)

  const handleSubmit = event => {
    event.preventDefault()
    const { email, password } = event.target.elements
    login(email.value, password.value, history)
  }

  return (
    <div>
      <h1>Log in</h1>
      <form onSubmit={handleSubmit}>
        <label>
          Email
          <input name="email" type="email" placeholder="Email" />
        </label>
        <label>
          Password
          <input name="password" type="password" placeholder="Password" />
        </label>
        <button type="submit">Log in</button>
      </form>
    </div>
  )
}

export default withRouter(Login)

src/auth/Signup.jsx

import React, { useContext } from 'react'
import { withRouter } from 'react-router'
import { AuthContext } from './AuthProvider'

const SignUp = ({ history }) => {
  const { signup } = useContext(AuthContext)

  const handleSubmit = event => {
    event.preventDefault()
    const { email, password } = event.target.elements
    signup(email.value, password.value, history)
  }

  return (
    <div>
      <h1>Sign up</h1>
      <form onSubmit={handleSubmit}>
        <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 withRouter(SignUp)

References

About the author

I am a web-developer based somewhere on earth. I primarily code in TypeScript, Go and Ruby at work. React, RoR and Gin are my go-to Frameworks.