How to handle authentication on Node JS using Firebase 🔥
Nikollas Betiol
Posted on May 22, 2020
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
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.
Firebase setup
The initial screen is to create a new Project on Firebase, click at Create Project
Now, we got a screen to give a name to our application, for this example, my project name is firebase-auth-server
Now Firebase is creating our project.
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
.
Great! Firebase can now accept authentication of our frontend by Google.
Backend setup
Now we need to start the project and install the express.
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.
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:
/**
* 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.
{
"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.
npm run start:dev
Let's navigate to http://localhost:4000/books
Now, you must have this.
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, is the library that we will use to integrate with Firebase.
Here we gotta install the firebase-admin
npm install firebase-admin
Lets back at the firebase console and download the credentials. You can follow this step clicking here.
Create and Save the file inside the firebase
folder.
Your code should look like this.
/*
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
touch auth-middleware.js
and use the code bellow
/*
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.
/**
* 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
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;
touch Login.js
touch BookList.js
In the file Login.js
, paste the code below:
/**
* src/Login.js
*/
import React from "react";
export default function Login() {
return <h1>Login</h1>;
}
and in the file BookList.js
, paste the code:
/**
* 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.
NOTE: THIS IS NOT THE BEST WAY TO CREATE AN AUTHORIZATION FLOW, THIS PROJECT IS JUST AN EXAMPLE
/**
* 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 and get the configs.
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.
/**
* 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:
/**
* 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
npm start
Once started React will open a browser window
Navigate to http://localhost:3000/login
You can click in the GOOGLE
button
Cool, after login you must be redirected to the booklist.
Back to the BookList.js
component and paste the code below
/**
* 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/
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.
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.
Thank you \o/
Posted on May 22, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.