Google Firebase authentication between Vue.js and Node.js

Tamás Polgár
Developer rants
Published in
7 min readAug 16, 2020

Save a lot of manual digging, read this.

So, what are we trying to do today?

We’re going to build a Vue.js app and a Node.js app serving as frontend and backend for a web project. The user can log in on the frontend with Firebase Authenticate, using his Google, Facebook, Twitter, Github or whatever other account he has. The backend will detect the login, validate it, and allow the user to access the backend as a registered user.

This tutorial may be useful even if you work with some other frontend framework or backend engine. Google’s service works pretty much the same way on every platform, so if you’re into, say, Java and Python, or you’re working on a mobile app and not a website, the process and the methods will be still pretty much the same.

The OAuth2 login mechanism, a short overview

You perhaps already know how OAuth technology works, but if you don’t, here’s a quick rundown.

Once upon a time we used password authentication for websites, meaning that for every single project you had to implement the forms, the verification mechanism, maintain a user database, etc. OAuth brought a major change. Now you can use your account from some major online service to log in to other websites. Google Firebase allows you to enable such functionality in your project, eliminating the need for writing your own authentication engine. The downside is that you’ll have to rely on some shady big bad company. If you dislike that, you can use OpenId which is pretty much the same thing, but (allegedly) free of all this New World Order shit.

The login process with these authentication agents is the following. You click a button on the website. A popup window appears, or you’re redirected to another page (you can choose which method to implement) where Google takes control and shows the login options. If you wanted Google authentication, it’ll be Google’s login interface, if you chose Facebook, Twitter or others, it’ll be theirs. They’re all handled by Google, you don’t have to implement a connection to every single authentication provider (although you can if you wish).

When the user finished logging in, the agent returns control to your website either by closing the popup or navigating to a callback page. Then you’ll receive information about the user’s account like his name, email address, profile photo, and a lot more as a JSON structure. It’s called a JWT or JSON Web Token. Among this information is the authentication token. It’s a long, seemingly random string. You’ll have to pass this to your backend. It can be sent as POST data to https://your.site/login.

When the backend receives this string, it connects to the provider and requests validation of the token. Basically it asks Google: “Hey, do you know this guy? Is he legit?” Then Google responds: “Yup, he’s legit, and here’s his name, email, profile picture, etc.” After this response you can accept this user’s login, or register him as a new user, and so on.

Then you can start a HTTP session, and from this point the backend will recognize the frontend until the session expires or the user logs out and terminates it.

This method is way more secure than submitting passwords the old-fashioned way. The user can leverage all of Google’s advanced security features to keep his account safe, and you don’t have to worry about some bastard sniffing out network traffic. Google provides not only the service, but also officially supported libraries to implement everything both on the frontend and the backend.

The only drawback is that it’s a little bit complicated at first sight. Not because it’s really complicated, but there’s a lack of concise examples on how to implement a simple login feature which most projects need. Most of us who figured it out often spent long days trying to understand Google’s inconsistent lingo and cross-referencing manuals. But cheers, here I am to help you out!

Step 1: Create the application

Go to https://console.firebase.google.com and create your project, or open an existing one to add Firebase Authentication.

On the left side panel click Authentication, then on the Sign-in Method panel choose what kind of authentication would you like to implement. Apart from various third party services there’s also Email/Password, but it requires the implementation of the sign-in form and handle things like confirmation, password reset, etc. There’s also anonymous login.

When you choose a third party authentication service, you will have to configure the app not only on Firebase’s console, but also at the partner’s own control panel. Facebook, Twitter, Github and the rest all have their own API to handle authentication and other connections. It would go beyond the scope of this document to describe how to configure every single service, but I can assure you it’s a fairly easy process for most of them. You’re going to need a user account at each of the selected partners too. To keep this tutorial simple, I’m going to assume we’re only adding Google authentication. So just enable Google.

A Web Client ID and a Web Client Secret token will appear. That’s great, but we won’t need them.

We’re now ready to implement our frontend authentication. We’ll return to the Firebase Console later, so you may want to leave the tab open.

Step 2: The frontend part

Google provides some vanilla JavaScript snippets, but even better, there are officially supported wrappers for all major frameworks, including Vue.js. Of course Firebase can do much more than just authentication, and so can these add-ons.

Adding VueFire and Firebase to your project is as easy as this:

npm i vuefire firebase

Then add this to your main.ts:

import { firestorePlugin } from 'vuefire';Vue.use(firestorePlugin);

That’s all. Now let’s add a Google Sign-in button to our app.

First let’s create a JSON file called firebase.json where our Firebase defaults will be kept. What goes into this file? Open Firebase Console, click Project Overview, and scroll down on the General tab. You’ll find a Firebase SDK snippet there. Inside is a JSON structure, marked as Your web app’s Firebase configuration. Copy and paste this into the JSON file. It should look something like this:

{
apiKey: "xxx",
authDomain: "xxx.firebaseapp.com",
databaseURL: "https://xxx.firebaseio.com",
projectId: "xxx",
storageBucket: "xxx.appspot.com",
messagingSenderId: "1091091352725",
appId: "1:1091091352725:web:xxx",
measurementId: "G-xxx"
}

Now we can create our Vue component:

import Firebase from 'firebase';
import * as firebaseConfig from "./firebase.json";
@Component({})export default class Login extends Vue { private app; created() {
if (!Firebase.apps.length)
this.app = Firebase.initializeApp(firebaseConfig);
}
}

This creates a Firebase instance. Why the condition? It is because the instance can be created only once during a session. If it already exists, an exception will be thrown. This will happen even when we modify our code, and the app is refreshed in the browser because app-level dependencies aren’t refreshed.

Here we get to the first tricky part. Don’t worry, it’s not that tricky.

What we initialize here is an instance of the global Firebase object. It will persist throughout the app. Upon initialization, Firebase automatically assigns a name to the instance, which is always [DEFAULT] if you don’t specify another. The condition is to prevent reinitialization when one app instance already exists, causing an exception.

Naming is only necessary when you need more than one instances, but that isn’t likely unless you’re writing some really big application. In that case every time you call a Firebase function, you’ll also have to specify which instance are you trying to talk to, or Firebase will assume you’re addressing [DEFAULT]. If you want to give the instance a name, it’s this simple:

this.app = Firebase.initializeApp(firebaseConfig, 'My Instance');

Now we have the instance, but it doesn’t do anything. Add a button or something to your template, and bind the @click event to this function:

public firebaseLogin() {  const provider = new Firebase.auth.GoogleAuthProvider();  Firebase.auth().signInWithPopup()
.then(async user => {
let idToken;
await Firebase.auth().currentUser.getIdToken(true)
.then(res => idToken = res);
console.log(idToken); })
}

The signInWithPopup() function will open the Google sign-in agent in a browser popup modal. To use Facebook, Twitter or other providers, you should change the value of provider to the appropriate authentication provider like Firebase.auth.FacebookAuthProvider().

The function is asynchronous and we await the retrieval of the token because we’ll send it to the backend when it’s retrieved. Replace the console output with the backend call (using Axios for example) to pass the token. The frontend part is now done!

Step 3: The backend part

Let’s assume you already have a Node.js app with Express up and running. You’ll need to addfirebase-admin.

npm install firebase-admin --save

Verifying a token needs a little bit more trickery than logging in. First, go to Firebase Console again, click the gear icon, and go to Service Accounts.

Here you’ll see another configuration snippet for Node.js, Java, Python and Go. It’s not the code you’re looking for (as we’re obviously using Typescript). Click the Create new private key button. You’ll get some JSON data again, containing a private key and some other information. Put this into a separate JSON file, but NOT IN YOUR PROJECT DIRECTORY!!

Why not? Well, it’s called private key for a reason. This is your app’s unique identification, a fingerprint if you prefer. Anyone can attempt a login to your app, meaning to tell an OAuth sign-in partner that he wants to get in. But the OAuth partner will only offer validation if your app is asking. In other words, anyone can leave a message for you at the post office, but they’ll only deliver them to you, upon presenting proper identification. If you put the JSON into your project directory, it may get pushed into your repository and leaked.

The best way to handle this JSON is to store it in a dedicated directory on your server, inaccessible from the outside, but accessible for Node.js to read. I usually create a configuration JSON file for my apps and read the path to the secret file from there.

Here’s how you validate the token:

import * as admin from 'firebase-admin';const googleSecret = require('c:\secret\google.json');verifyToken(token) {
const serviceAccount = googleSecret;

if (!admin.apps.length)
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "xxx.firebaseio.com"
});
}

The databaseURL value came from that JavaScript snippet on the Firebase Console which I suggested you to ignore. This is the exact same Firebase instance initialization as on the frontend.

Actual verification is a breeze now. Assuming we have the token from the frontend in a variable named token:

admin.auth().verifyIdToken(token)
.then(user => {
console.log(user);
});

And boom! The login is verified. You can store the data, request the user’s full profile or anything. It’s a good idea to start a session and save the user’s name, user ID and perhaps email address for further reference.

--

--