How to handle authentication on Node JS using Firebase 🔥
Tags: node, javascript, firebase, react
Published: 2020-05-22 18:21:55

When we start to build an API with Node, the first thing that comes in mind is **Authentication**.
Then we think in JWT, hash passwords, define the secret keys of JWT, and this is a little bit boring when we need to build a small service or API.

In this article, we are going to show how this works using Google Sign-in, but the same applies to any of the other login providers that are available on Firebase. For further detail on how to set up them, see this link from Firebase [docs](https://github.com/firebase/firebase-admin-node)

##Firebase
Firebase is Google's mobile application development platform that helps you build, improve, and grow your app. Inside Firebase, we got modules like **Authentication**, **Push Notifications**, **Realtime Database**, and more cool things.

##What are we'll do
A NodeJS backend that authenticates requests through Firebase.

To begin, we need to create a project on [Firebase](https://console.firebase.google.com/).

##Firebase setup
The initial screen is to create a new Project on Firebase, click at `Create Project`

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/a6fz90a2thwjtjp09dbi.png)

Now, we got a screen to give a name to our application, for this example, my project name is `firebase-auth-server`
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/jbh5rm8rm03d94if2ali.png)

Now Firebase is creating our project.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/lgfqrkioojbsf0xq3nv8.png)

After created, Firebase console will give us a dashboard with several services, please select the `Authentication` menu.

And then we have a list of providers that Firebase gives us, but for us first, we need to select Authentication by `Google`.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/gy3tkguy6tugyv5md6fs.png)

Great! Firebase can now accept authentication of our frontend by Google.

##Backend setup

Now we need to start the project and install the express.

```bash
mkdir server
npm init -y
npm install express cors
npm install -D nodemon
```

After this, we need to create a file called `index.js` on the root of the project and create the code bellow.


```javascript
const express = require("express");

const app = express();

app.use("/", (req, res) => {
  res.send("Hello World");
});

app.listen(4000, () => console.log("The server is running at PORT 4000"));
```

The code above will create a basic express server and this is our start.

After this, we need to create a basic endpoint following the code below: 

```javascript
/**
 * index.js
 */
const express = require("express");
const cors = require("cors");
const authMiddleware = require("./auth-middleware");

const app = express();
app.use(cors());

const books = [
  {
    id: 1,
    name: "Harry Potter",
    image:
      "https://pmpub-catalogue.s3-eu-west-1.amazonaws.com/covers/web/9781781100240.jpg",
  },
  {
    id: 2,
    name: "Clean Code",
    image:
      "https://images-na.ssl-images-amazon.com/images/I/41jEbK-jG+L._SX374_BO1,204,203,200_.jpg",
  },
  {
    id: 3,
    name: "Javascript: The good parts",
    image: "https://images-na.ssl-images-amazon.com/images/I/81kqrwS1nNL.jpg",
  },
];

app.use("/", authMiddleware);

app.get("/books", (request, response) => {
  return response.send({ books });
});

app.listen(4000, () => console.log("The server is running at PORT 4000"));
```

Now, we need to back at `package.json` file and add a `start` script and test our code.

```json
{
  "name": "firebase-auth-server",
  "version": "1.0.0",
  "main": "index.js",
  "author": "Nikollas Betiol",
  "license": "MIT",
  "scripts": {
    "start:dev": "nodemon index.js"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "devDependencies": {
    "nodemon": "^2.0.3"
  }
}
```

After, our `package.json` file should look like the code above,
then we can execute the `script` to run the application.

```bash
npm run start:dev
```

Let's navigate to `http://localhost:4000/books`

Now, you must have this.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/eubozwmxxgu5d6eo3uhv.png)

Great, we have an endpoint on our API that returns a list of books, but you can notice that everybody can access our endpoint and we don't wanna this 🤔

Let's fix this using the [firebase-admin](https://github.com/firebase/firebase-admin-node), is the library that we will use to integrate with Firebase.

Here we gotta install the `firebase-admin`

```bash
npm install firebase-admin
```

Lets back at the firebase console and download the credentials. You can follow this step clicking [here](https://firebase.google.com/docs/admin/setup#initialize-sdk).

Create and Save the file inside the `firebase` folder.

Your code should look like this.

```javascript
/*
  firebase/index.js
*/
const firebase = require("firebase-admin");

const credentials = require("./credentials.json");

firebase.initializeApp({
  credential: firebase.credential.cert(credentials),
  databaseURL: "https://<yourproject>.firebaseio.com",
});

module.exports = firebase;
```

Now we need to create an auth middleware to filter our requests and authorize or deny requests.

Then, we need to create a file called `auth-middleware.js`

```bash
touch auth-middleware.js
```

and use the code bellow

```javascript

/*
    auth-middleware.js
*/
const firebase = require("./firebase/admin");

function authMiddleware(request, response, next) {
  const headerToken = request.headers.authorization;
  if (!headerToken) {
    return response.send({ message: "No token provided" }).status(401);
  }

  if (headerToken && headerToken.split(" ")[0] !== "Bearer") {
    response.send({ message: "Invalid token" }).status(401);
  }

  const token = headerToken.split(" ")[1];
  firebase
    .auth()
    .verifyIdToken(token)
    .then(() => next())
    .catch(() => response.send({ message: "Could not authorize" }).status(403));
}

module.exports = authMiddleware;

```

After, we can back at the `index.js` file and add the `auth-middleware` middleware.

```javascript
/**
 * index.js
 */
const express = require("express");
const authMiddleware = require("./auth-middleware");

const app = express();

const books = [
  { id: 1, name: "Harry Potter" },
  { id: 2, name: "Clean Code" },
  { id: 3, name: "Javascript: Good practices" },
];

app.use("/", authMiddleware);

app.get("/books", (request, response) => {
  return response.send({ books });
});

app.listen(4000, () => console.log("The server is running at PORT 4000"));

```

Cool, I think that the backend is ready to receive requests from our frontend!

##Frontend
Let's start creating a project using `create-react-app`
You can find the CSS [here](https://gist.github.com/betiol/f826eea2c41c40f978c72e05bf178619)

```bash
npm install -g create-react-app
create-react-app frontend
cd frontend/
npm install firebase react-router-dom react-router
```

Now we need to create two files;
```bash
touch Login.js
touch BookList.js
```

In the file `Login.js`, paste the code below:

```javascript
/**
 * src/Login.js
 */
import React from "react";

export default function Login() {
  return <h1>Login</h1>;
}
```

and in the file `BookList.js`, paste the code:

```javascript
/**
 * src/BookList.js
 */
import React from "react";

export default function BookList() {
  return <h1>BookList</h1>;
}
```

We just created two important files in our application, let's configure the `App.js` to use [react-router](https://reacttraining.com/react-router/web/guides/quick-start).

`NOTE: THIS IS NOT THE BEST WAY TO CREATE AN AUTHORIZATION FLOW, THIS PROJECT IS JUST AN EXAMPLE
`

```javascript
/**
 * src/App.js
 */
import React from "react";
import "./App.css";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import Login from "./Login";
import BookList from "./BookList";

export default function App() {
  return (
    <div className="App">
      <BrowserRouter>
        <Switch>
          <Route path={"/login"}>
            <Login />
          </Route>
          <Route path={"/book-list"}>
            <BookList />
          </Route>
        </Switch>
      </BrowserRouter>
    </div>
  );
}

```

Now, you can follow this documentation [Setup Web Project Configuration](https://firebase.google.com/docs/web/setup?authuser=0) and get the configs.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qld7mqu6rhk8z2en8fp0.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/b9r4zcecmghtm2c72hbh.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fdl6sa3ewxnvew4xkid2.png)

Let's create a file called `firebase.js` inside the `src` folder and paste the code below, with this code we'll create the firebase config.
```javascript
/**
 * src/firebase.js
 */
import firebase from "firebase/app";
import "firebase/auth";

const firebaseConfig = {
  apiKey: "your apiKey here",
  authDomain: "your authDomain here",
  databaseURL: "your databaseURL here",
  projectId: "your projectId here",
  storageBucket: "your storageBucket here",
  messagingSenderId: "your messagingSenderId here",
  appId: "your appId here",
};

firebase.initializeApp(firebaseConfig);

const auth = firebase.auth();

export { auth, firebase };

```

Now, we gonna back to the file `Login.js` and paste this code.
Your code should look like this:

```javascript
/**
 * src/Login.js
 */
import React from "react";
import { useHistory } from "react-router-dom";
import { auth, firebase } from "./firebase";

export default function Login() {
  const history = useHistory();
  async function googleLogin() {
    //1 - init Google Auth Provider
    const provider = new firebase.auth.GoogleAuthProvider();
    //2 - create the popup signIn
    await auth.signInWithPopup(provider).then(
      async (result) => {
        //3 - pick the result and store the token
        const token = await auth?.currentUser?.getIdToken(true);
        //4 - check if have token in the current user
        if (token) {
          //5 - put the token at localStorage (We'll use this to make requests)
          localStorage.setItem("@token", token);
          //6 - navigate user to the book list
          history.push("/book-list");
        }
      },
      function (error) {
        console.log(error);
      }
    );
  }
  return (
    <div>
      <button onClick={googleLogin} className="login-button">
        GOOGLE
      </button>
    </div>
  );
}

```

Then back to the terminal and run the application
```bash
npm start
```
Once started React will open a browser window

Navigate to `http://localhost:3000/login`

You can click in the `GOOGLE` button

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1lgqwcqrm9vktjywktju.png)

Cool, after login you must be redirected to the booklist.

Back to the `BookList.js` component and paste the code below

```jsx
/**
 * src/BookList.js
 */
import React, { useEffect, useState } from "react";

export default function BookList() {
  //create state to store our book list
  const [books, setBooks] = useState([]);

  useEffect(() => {
    async function loadBooks() {
      //fetch the book list
      const request = await fetch("http://localhost:4000/books", {
        //use the authorization
        headers: {
          Authorization: "Bearer " + localStorage.getItem("@token"),
        },
      });

      const allBooks = await request.json();
      //set the book list on state
      setBooks(allBooks.books);
    }
    //invoke the function
    loadBooks();
  }, []);

  return (
    <div className="container">
      <h1>BookList</h1>
      {/* map the book list to show book name and image */}
      {books.map((book) => (
        <div key={book.id} className="booklist">
          <img className="image" alt={book} src={book.image} />
          <h3>{book.name}</h3>
        </div>
      ))}
    </div>
  );
}
```

No, we can see the booklist \o/

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ewze58mjiecuykuvrxn6.png)

##Conclusion

This is enough push to get you started with firebase auth on the server. You can check out more possibilities exploring the [Firebase Docs](htps://firebase.google.com/docs/auth).
I hope this helped you to learn how to create an integration with firebase auth and if you wanna see the source code, check on my [Github](https://github.com/betiol/firebase-auth-devto).
Thank you \o/