Accessing Google APIs using Service account in Node.JS

  This article is going to be a walkthrough on performing authentication with Google APIs and Node.js. I’m going to build a Node.js application which successfully authenticates with a Google account and make simple requests for the following APIs: Google Sheets API, Google Drive API and Google Calendar API. In order to avoid using personal Google account information when accessing the API, I’m going to set up a service account which is a special account representing my application. This account has a unique email address that can be used to grant permissions to.


  A few assumptions to begin with though:

  • we have a Google account;
  • we know what Node.js is, and have it set up (if not, you can get it from here);
  • we have npm installed (usually it comes with Node.js).

Create the project in Google Developers Console

  In order to be able to access Google Services, go to Google Developers Console and create a new project. Provide a name for your project and an ID, which can be generated as well.

Create the service account

  On the left menu, select Credentials, then Create credentials. Select Service account key from the type of credentials list. After this, choose Compute Engine default service account, JSON as a private key type and hit Create button which will trigger the download of the JSON private key.

Fig. 1 Create a service account

Enable the APIs

  Having the JSON private key created is not enough. We need to enable the APIs which will be used with this service account. To do that, select Library from the left menu and then search for “Google Sheets API” and press the Enable button. This way you can enable whichever Google API you need, but for now, let’s enable two more APIs: “Google Drive API” and “Google Calendar API”. Now, on your dashboard (Fig. 2), you should be able to see the APIs that were enabled and several charts which can be really useful for monitoring your activity.

Fig. 2 Google APIs dashboard

Grant access to resources

  The access is granted by assigning permissions to the service account, using its email address. For example, in order to access a google spreadsheet, it must be shared with the service account email address. Basically, all resources which are going to be requested through a Google API, must be shared with the service account (unless they are public).

  In order to work with Google Sheet API and Google Drive API, create a Google spreadsheet and insert some information in it, for example a list of movies with their rating. Then share this spreadsheet with the service account. For the Google Calendar API, create an event and share it with the service account as well. But in case of Calendar API, event sharing is done by sending invitations to guests.

  That’s it! Now that we have a private key that we can use from a Node.js app, enabled APIs and shared resources, let’s start with Node.js app.

Set up the Node.js project

  Create a new Node.js Application and install Google API library by running following npm script: npm install --save googleapis.

  Now it’s time to use the private key that we downloaded earlier. Let’s copy it to our project and name it privatekey.json (you can name it whatever you want).

Fig. 3 Node.js project structure

  After this, import in main.js both Google library and private key:

let google = require('googleapis');
let privatekey = require("./privatekey.json");

  Now let’s use the private key to configure a JWT auth client and authenticate our request.

// configure a JWT auth client
let jwtClient = new google.auth.JWT(
       privatekey.client_email,
       null,
       privatekey.private_key,
       ['https://www.googleapis.com/auth/spreadsheets',
        'https://www.googleapis.com/auth/drive',
        'https://www.googleapis.com/auth/calendar']);
//authenticate request
jwtClient.authorize(function (err, tokens) {
 if (err) {
   console.log(err);
   return;
 } else {
   console.log("Successfully connected!");
 }
});

  In square brackets, right after privatekey.private_key we’re specifying Scopes for Google APIs. Auth scopes express the permissions you request users to authorize for your app. Now that we have successfully authenticated, let’s start querying APIs.

Google Sheets API

  First one on the list is Google Sheets API . Having google spreadsheet from Fig. 4, suppose we want to get the movie names which have their rating between 5 and 10.

Fig. 4 Google spreadsheet with a list of movies and their ratings

  In order to do this we need the spreadsheet ID which can be taken from URL (all characters before edit as in example below:

  https://docs.google.com/spreadsheets/d/1Dua_kwZjCZx1pBp_6umDVQYy_t2MT5KfmPf6u7kakcA/edit#gid=0

  Besides the spreadsheet ID we need the sheet name and the range which we want to get data from. A range is composed from the sheet name and the range itself, which has two values, first one is the top left corner, and second is the bottom right corner. In our case the range would be A5: B10.

//Google Sheets API
let spreadsheetId = '1Dua_kwZjCZx1pBp_6umDVQYy_t2MT5KfmPf6u7kakcA';
let sheetName = 'Top Rated TV Shows!A5:B10'
let sheets = google.sheets('v4');
sheets.spreadsheets.values.get({
   auth: jwtClient,
   spreadsheetId: spreadsheetId,
   range: sheetName
}, function (err, response) {
   if (err) {
       console.log('The API returned an error: ' + err);
   } else {
       console.log('Movie list from Google Sheets:');
       for (let row of response.values) {
           console.log('Title [%s]\t\tRating [%s]', row[0], row[1]);
       }
   }
});
Google Drive API

  Suppose we want to search all files which have the “TV” word in their name. In order to do this, we need to define the q parameter, which is a search query, that contains one or more search clauses.

//Google Drive API
let drive = google.drive('v3');
drive.files.list({
   auth: jwtClient,
   q: "name contains 'TV'"
}, function (err, response) {
   if (err) {
       console.log('The API returned an error: ' + err);
       return;
   }
   var files = response.files;
   if (files.length == 0) {
       console.log('No files found.');
   } else {
       console.log('Files from Google Drive:');
       for (var i = 0; i < files.length; i++) {
           var file = files[i];
           console.log('%s (%s)', file.name, file.id);
       }
   }
});
Google Calendar API

  Lastly, suppose we want to list the events from the calendar using Google Calendar API. In order to be able to access the primary calendar of the currently logged in user, we should use the “primary” as calendar ID.

//Google Calendar API
let calendar = google.calendar('v3');
calendar.events.list({
   auth: jwtClient,
   calendarId: 'primary'
}, function (err, response) {
   if (err) {
       console.log('The API returned an error: ' + err);
       return;
   }
   var events = response.items;
   if (events.length == 0) {
       console.log('No events found.');
   } else {
       console.log('Event from Google Calendar:');
       for (let event of response.items) {
           console.log('Event name: %s, Creator name: %s, Create date: %s', event.summary, event.creator.displayName, event.start.date);
       }
   }
});

  It is time to see the results of our work! In Fig. 5 we can see that all APIs have responded to our request and returned the information that we asked for.

Fig. 5 Program output

  There is some setup work to get things ready when using a Service Account, but once that’s done you can focus on API requests. In this article we used just 3 Google APIs, but there are a lot more of them, which can be accessed through Google’s API explorer.

Share this article:

Constantin Harea
Java Developer