May 2022

Google API Service Accounts With NodeJS

For a recent project I needed update to a single shared Google calendar. I decided to go with a Google service account to manage this. I’m going to post here how I did it.

What is a Service Account

A service account is used by an application as opposed to a real living person. It allows your application to make authorized API calls directly. A service account is identified by its email address, which is unique to the account.

  • Service accounts can not be logged into with browsers.
  • Authorization is done with a public-private RSA key.
  • Service accounts are not part of your Google domain. They do not share global resources like a live user.

Create a Service Account

At the very top choose the project drop down. This will open up the project window where you can select an ongoing project or create a new one. Each service account is located in a project. After you create a service account, you cannot move it to a different project.

In the Google Developers console (link) under the leftmost APIs & Services menu you will find the credentials option. At the top of the screen click the Create Credentials option. You will have a choice as to which type of credential you would like to create. Select service account. Most, though not all, API’s should work with service accounts.

Service Account Authentication

There are a number of ways to authenticate an application using a service account (link). If you are deployed on Google cloud you can use an attached service account. You can use a Workload Identity with Kubernetes pods. There is also the Workloads Identity Federation that works with other service providers. Here we will be using a service account key which allows us to deploy on our own cloud provider.

Create a Public-Private key.

Click on your service account name to bring up the management menu. There is a number of menus near the top of the screen; select keys. Press the add keys dropdown menu and select create new key. Use json unless you have a reason to do otherwise. Remember not to add this key to your git repository or put it anywhere the public can see it.

Create and Share a Calendar

Create a calendar in Google Calendars and look at it’s settings (3 little dots next to the name). Find “share the calendar with specific people” and add the email address of your service account. Give your service account the role “make changes to events”. Since the service account isn’t a real user, you don’t get a confirmation email, and the calendar won’t immediately show up using the Google Calendar API list method.

Find the calendar id under the integrate calendar heading on the settings page. It should look like an email address. Save this, we will be using it in a bit.

Getting Started

Install the google api package.

npm install googleapis

View the Google APIs documentation on github.

https://github.com/googleapis/google-api-nodejs-client

In the Google console, you will find “APIs and Services > Enabled APIs and Services” add the Calendar API to your project.

Code Pre-requisites

The following are three preliminary steps we need to preform before accessing the calendar API. After this we can start accessing the API methods. I will implement them in a class structure just to keep things clean.

  • Import the google api library
  • Create a new authentication object.
  • Obtain an instance of the calendar interface.
import { google } from "googleapis";
constructor() {
    const auth = new google.auth.GoogleAuth({
        keyFilename: GoogleCalendar.KEY_FILENAME,
        scopes: GoogleCalendar.SCOPES,
    });

    this.calendar = google.calendar({
        version: "v3",
        auth: auth,
    });
}

API Methods

Now that the environment is setup we will now go through a few of the available API calls. For a full list of see the Calendar API Documentation.

List

The list method allows you to view available calendars. It is found in the calendar.calendarList implementation. This is also where you find the create, get, and delete calendar methods. This is one of the simpler API calls.

list() {
    return new Promise((resolve, reject) => {
        this.calendar.calendarList.list((err, res) => {
            if (err) reject(err);
            if (res) resolve(res.data);
        });
    });
}

Insert

Newly added calendars won’t show up in the list until you have inserted them. We use the calendar identifier we saved above. In this case we also pass in an options object, containing a resource object, which in turn has the calendar id we want to add.

insert(id) {
    return new Promise((resolve, reject) => {
        const options = {
            resource: {
                id: id,
            },
        };

        this.calendar.calendarList.insert(options, (err, res) => {
            if (err) reject(err);
            if (res) resolve(res.data);
        });
    });
}

Delete

When you look at the API documentation for delete you notice that calendar id is in the url. This implies that we use a calendarId field in our options object. The resource field, as used above, goes in the body. This is something to watch out for when interpreting HTTP calls to NodeJS API calls.

remove(id) {
    return new Promise((resolve, reject) => {
        const options = {
            calendarId: id,
        };

        this.calendar.calendarList.delete(options, (err, res) => {
            if (err) reject(err);
            if (res) resolve(res.data);
        });
    });
}

Add Event

To add an event we access the events property of the calendar API. In this case we include both the calendar id in the URL as well as body properties.

addEvent(id, start, end, summary){
    return new Promise((resolve, reject) => {
        const options = {
            calendarId: id,
            resource: {
                start: {
                    date: "2022-05-21",
                },
                end: {
                    date: "2022-05-23",
                },
                summary: summary,
            },                
        };

        this.calendar.events.insert(options, (err, res) => {
            if (err) reject(err);
            if (res) resolve(res.data);
        });
    });        
}

References

Google Event Object

Google Calendar Create Event