Using Google APIs with Firebase Auth and Firebase UI on the Web

Sandeep Dinesh
Google Cloud - Community
5 min readJan 3, 2018

2021 Update: I no longer recommend this method. While it still technically works, when using it in a recent project, we ran into a lot of stale login issues.

Instead, you should go the other way around and use the gapi login to pass credentials to Firebase.

I recommend following the instructions here: https://github.com/msukmanowsky/gapi-firebase

I also recommend using this helper module to load gapi: https://www.npmjs.com/package/gapi-script

Original Post:

If you are building an web app that needs to interact with a user’s Google account, chances are you are going to discover the pain that is OAuth. You need to get a OAuth token and pass that to the Google API library before you can do anything useful.

Thankfully, doing all the login stuff with Firebase Auth is super easy, and Firebase UI makes it even easier.

Niceeeeee

Firebase UI is basically a drop in library that does all the UI (buttons, etc) and redirect logic for you automatically for all supported Firebase OAuth providers (Google, Facebook, GitHub, etc).

The problem is, when you want to do more than just log in, things get murky. Let’s say you wanted to create an app that manages a user’s calendar. How do you specify the scopes you need to access other Google services? How do you get the OAuth token from Firebase UI to use in the Google API Client?

Thankfully, Todd Vanderlin wrote a great post that fixes many of these issues. Using that as a basis, let’s see how you can get Firebase UI and the Google API Client working together!

Setup Libraries

The first step is to install Firebase and Firebase UI. You can just follow the official instructions, or follow along here.

Add the following to your <head> section in the HTML:

<script src="https://www.gstatic.com/firebasejs/4.8.1/firebase.js"></script>
<script src="https://cdn.firebase.com/libs/firebaseui/2.5.1/firebaseui.js"></script>
<link rel="stylesheet" href="https://cdn.firebase.com/libs/firebaseui/2.5.1/firebaseui.css" />

This will load all the dependencies from Google’s CDN.

Setup Config

First, make sure you enable Google Login in the Firebase Console:

Go to the Firebase Console and get the Config data for your app.

Copy this config object

It should look something like this:

var config = {
apiKey: "RANDOM_STRING",
authDomain: "APPNAME.firebaseapp.com",
databaseURL: "https://APPNAME.firebaseio.com",
projectId: "APPNAME",
storageBucket: "APPNAME.appspot.com",
messagingSenderId: "1234567890"
};

We are going to use this config object to configure the Google APIs as well as Firebase. To do this, you need to add some more fields to this object.

ClientID

The first thing you need to do is get your OAuth Client ID. To do this, you need to go to the Google Developer Console.

console.developers.google.com/apis/credentials

Copy the full ClientID

Now add this to your config object

var config = {
apiKey: "RANDOM_STRING",
authDomain: "APPNAME.firebaseapp.com",
databaseURL: "https://APPNAME.firebaseio.com",
projectId: "APPNAME",
storageBucket: "APPNAME.appspot.com",
messagingSenderId: "1234567890",
clientId: "RANDOM_STRING.apps.googleusercontent.com" };

Scopes

Next, you need to add in the scopes you need for the services you want to modify. In this example, I want to get the user’s profile information (email, name, etc) and have the ability to modify and read their calendar.

To find the right scope name, there is a list of all available Google Scopes here:

https://developers.google.com/identity/protocols/googlescopes

Now search for the scopes you need. Some services (like Gmail) have very specific scopes that give you the minimum access you need to complete a task. Always make sure to use the least amount of permissions you need!

So in this example, there are three scopes to include: “email”, “profile”, and “https://www.googleapis.com/auth/calendar”

Create an array in the config object with these values:

var config = {
apiKey: "RANDOM_STRING",
authDomain: "APPNAME.firebaseapp.com",
databaseURL: "https://APPNAME.firebaseio.com",
projectId: "APPNAME",
storageBucket: "APPNAME.appspot.com",
messagingSenderId: "1234567890",
clientId: "RANDOM_STRING.apps.googleusercontent.com", scopes: [
"email",
"profile",
"https://www.googleapis.com/auth/calendar"
]
};

Discovery Docs

Time for the last step. In order for the Google API client to know which libraries to load, you need to pass in the corresponding discovery docs. Email and Profile are built into Firebase, but we want to be able to modify the Calendar with the Google API client, so we need the discovery doc for it.

To find the right discovery doc, you can use this service:

https://developers.google.com/discovery/v1/reference/apis/list?apix=true

Again, create an array and add in all the discovery docs you need

var config = {
apiKey: "RANDOM_STRING",
authDomain: "APPNAME.firebaseapp.com",
databaseURL: "https://APPNAME.firebaseio.com",
projectId: "APPNAME",
storageBucket: "APPNAME.appspot.com",
messagingSenderId: "1234567890",
clientId: "RANDOM_STRING.apps.googleusercontent.com", scopes: [
"email",
"profile",
"https://www.googleapis.com/auth/calendar"
],
discoveryDocs: [
"https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"
]
};

Finally done with all the config madness!

Setting up Firebase UI

Note: You can see the completed code here

Follow the official setup for Firebase UI. The one difference is in the “signInOptions” field. Change it to include the scopes you specified in the config object:

var uiConfig = {
signInSuccessUrl: “<url-to-redirect-to-on-success>”,
signInOptions: [{
provider: firebase.auth.GoogleAuthProvider.PROVIDER_ID,
scopes: config.scopes
}],
// Terms of service url.
tosUrl: “<your-tos-url>”
};

Setting up the Google API Client

Firebase UI will take care of all the login flow details. After the login is complete, Firebase will automatically trigger a function. Inside this function, we are going to load the Google API client.

// This function will trigger when there is a login event
firebase.auth().onAuthStateChanged(function(user) {
// Make sure there is a valid user object
if(user){
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://apis.google.com/js/api.js';
// Once the Google API Client is loaded, you can run your code
script.onload = function(e){
// Initialize the Google API Client with the config object
gapi.client.init({
apiKey: config.apiKey,
clientId: config.clientID,
discoveryDocs: config.discoveryDocs,
scope: config.scopes.join(' '),
})
// Loading is finished, so start the app
.then(function() {
// Make sure the Google API Client is properly signed in
if (gapi.auth2.getAuthInstance().isSignedIn.get()) {
startApp(user);
} else {
firebase.auth().signOut(); // Something went wrong, sign out
}
}) } // Add to the document
document.getElementsByTagName('head')[0].appendChild(script);
}
})

Tying it all together

All the “boilerplate” is finished. You can now use the Google API Client without any issues!

Note: It is important that you either check if the OAuth token is still valid before making the call, or refresh the token before calling the APIs. This is because Firebase will automatically refresh the token, but the Google API Client won’t.

// Print out the User and the 10 latest calendar events
function startApp(user) {
console.log(user);
firebase.auth().currentUser.getToken()
.then(function(token) {
return gapi.client.calendar.events.list({
calendarId: "primary",
timeMin: new Date().toISOString(),
showDeleted: false,
singleEvents: true,
maxResults: 10,
orderBy: "startTime"
})
})
.then(function(response) {
console.log(response);
});
}

Full Code:

--

--