Add simple authentication to your React app using Firebase

Egor Egorov
6 min readFeb 19, 2018

--

Authentication? Cookies? …Tokens?

User authentication can is notoriously tricky. Cookies, tokens, sessions, signatures.. Ain’t nobody got time for dat! We want a simple login/logout functionality that only allows a signed-in user to access our app. Luckily Firebase makes it extremely easy.

Firebase allows you to authenticate users with an email/password, or by trusted identity authentication providers such as Google, Facebook, Github, and Twitter. The easiest way I found is using Google for this. Anyone with a Google account can sign-in and all of the logic surrounding any tokens or cookies is taken care of for you.

I’ll be using the image upload preview app from my previous post for this authentication example. The sign-in functionality will simply let the user see our app once they are authenticated, and prompt them to log in if not. This will set us up for adding functionality to allow the users to store and access photos in a database. But that is for another day. Let’s see what the code looks like for the simple authentication:

const React = require('react')
const Preview = require('./Preview.jsx')
import firebase, { auth, provider } from '../firebase.js'
class Main extends React.Component {
constructor(props) {
super(props)
this.state = {
user: null
}
this.login = this.login.bind(this)
this.logout = this.logout.bind(this)
}
login() {
auth.signInWithPopup(provider).then((result) => {
this.setState({
user: result.user
})
})

}
logout() {
auth.signOut().then((result) => {
this.setState({
user: null
})
})

}
componentDidMount() {
auth.onAuthStateChanged((user) => {
if (user) {
this.setState({user})
}
})
}
render() {
let authButton = this.state.user ?
<button onClick={this.logout}>Log Out</button> :
<button onClick={this.login}>Log In</button>
let uploader = this.state.user ?
<Preview/> :
<h4>Log in to use photo-loader</h4>
return (
<div>
{authButton}
{uploader}
</div>
)
}
}
module.exports = Main

The bold chunks of code are the meat of our authentication app. Let’s see what those are doing.. But first we have to configure Firebase. Start a new project and go to the authentication menu. Open the ‘SIGN-IN METHODS’ tab and enable the Google provider. This is absolutely the simplest method. Everyone has a Google account!

Configuring Firebase

Now just click ‘Web Setup’ in the top right corner and copy the chunk of code in the modal. Ignore the instructions to paste it into your HTML. We are doing this like proper React developers, so lets make a separate file called firebase.js and put the code there. We won’t need the script tags, but we will have to install Firebase by running npm install --save firebase and importing it to our firebase.js file. Here’s what the file should look like:

const firebase = require('firebase')const config = {
apiKey: "AIzaSyDzyLI6X7lz0oGtys_FWoh_tucQP1jSGdA",
authDomain: "photo-load.firebaseapp.com",
databaseURL: "https://photo-load.firebaseio.com",
projectId: "photo-load",
storageBucket: "photo-load.appspot.com",
messagingSenderId: "119279445969"
}
firebase.initializeApp(config)
const provider = new firebase.auth.GoogleAuthProvider()
const auth = firebase.auth()
module.exports = {
firebase,
provider,
auth
}

Make sure to add the two highlighted lines, which give us access to the auth methods like signInWithPopup() and signOut(), and set Google to be the auth provider.

To import all 3 of the exports in one line we use import instead of require() and JSX destructuring syntax.

import firebase, { auth, provider } from '../firebase.js'

Make sure that your path to the firebase config file is correct. Now we have access to all the Firebase auth services we need. Let’s dive into the login() and logout() functions. These lines in particular:

auth.signInWithPopup(provider).then((result) => {...})auth.signOut().then((result) => {...})

The first one launches a popup window using your selected provider. For Google it generates a token that your browser remembers while you stay on the page.

signInWithPopup()

The signOut() method just makes your browser delete the memory of the authentication token.

then() what?

These auth methods all return an object with a user property, so we use then() to pass that object to a callback function which sets this.state.user to the user object that gets returned from our auth function. If callbacks confuse you, you are not alone. A callback function basically just an event listener that waits for something to happen before it runs, in our case it waits for the user object to be returned by our auth function.

For login we set this.state.user to that user object. If the authentication fails, result.user will be null, which is perfect. For logout we also just set the user to null in our state.

Now we can use conditional rendering to check the state and only render the good stuff if there is a user, and if the user property is null we can render something like this:

The login/logout functionality works now, but try logging in and refreshing the page. The auth object We don’t want to log our users out on a page refresh. Let’s fix that.

What we can do is listen for a change in the the auth state. Firebase has the perfect event listener for this called onAuthStateChanged() which takes a callback function and passes the user object to it. This is exactly what we need. Now on any auth state change we will be able to check if the user object exists and if it does, store it in this.state.user.

auth.onAuthStateChanged((user) => {
if (user) {
this.setState({user})
}
})

componentDidWhat?

This is what is called a lifecycle method. It is a method of the React.Component class and comes with every component we make, just like constructor() and render(). In our case we want to use componentDidMount() which executes right after the component is rendered to the DOM. That’s exactly when we want to start listening for changes to the auth state.

Now the app signs you back in if you were already authenticated when the page refreshes. This also lets us clean up our code a little. Every time the auth state changes, if there is a user object, we want to store it in our component state. If there isn’t, we want to store null.

Both signInWithPopup() and signOut() change the auth state, an therefore trigger onAuthStateChanged() so we can actually remove the setState() calls from our login and logout functions and just call it once from onAuthStateChanged(). We just set this.state.user to whatever is passed to our callback (user object or null).

Lets also just move our login and logout functions into our constructor since they are only once line each, and we can get rid of those ugly bind statements. The end result should look like this:

const React = require('react')
const Preview = require('./Preview')
import firebase, { auth, provider } from '../firebase'
class Main extends React.Component {
constructor(props) {
super(props)
this.state = {
user: null
}
this.login = () => { auth.signInWithPopup(provider) }
this.logout = () => { auth.signOut()}

}
componentDidMount() {
auth.onAuthStateChanged((user) => { this.setState({user}) })
}
render() {
let authButton = this.state.user ?
<button onClick={this.logout}>Log Out</button> :
<button onClick={this.login}>Log In</button>
let uploader = this.state.user ?
<Preview/> :
<h4>Log in to use photo-loader</h4>
let userInfo = this.state.user ?
<h5>Signed in using {this.state.user.email}</h5> :
null
return (
<div>
{userInfo}
{authButton}
{uploader}
</div>
)
}
}
module.exports = Main

Much more sleek, right? We got all that functionality into basically 3 lines of code.

I also added a little line to show the user what email they used to sign in. I access it from the user object in our component state. The object has some properties like email and photoURL. Print the user object to your console to explore what other properties it has.

Anyway, here is how the app should look when you are logged in.

Next time I will add functionality to let users actually store photos, see them and delete them. Basically a private photo album. Cheers!

--

--