Google Calendar API Integration Made Easy


I recently struggled to integrate the Google Calendar API while trying to create an event listing for a website. In retrospect most of it should have been easy but there were a few tricky configurations that were required. I wanted to explain the ambiguities of what it can mean to integrate the Google Calendar API, share the steps I took, and provide a simple example use case.

The Google APIs have three methods of authentication: OAuth2, JWT, and a basic API key. OAuth2 is used for retrieving user data. In this setup the user logs in with their Google account and allows your app certain levels of access to their data.

However our goal is to connect to a Google calendar that is administered by the owner of the website so that they can display upcoming events on their site. For this we need one of the other options. The API Key option is simple but also less secure, and so Google limits which API's can use this authentication method.

This brings us to JWT, otherwise known as "JSON Web Token". This is the most secure and flexible way to connect to any Google API. However keep in mind that this type of connection is only able to connect to a Google account that you manage, not a users account. To do this we will need to enable the API, find the google project ID, create a JWT token, and finally configure the calendar. We will look at each of these in turn.

Enable the Calendar API

  1. Go to the Google API Console and either select an existing project or create a new project
  2. Select the "Enable APIS and Services" button
  3. Type "Calendar" into the search box
  4. Click on "Google Calendar API"
  5. Click "Enable"

Retrieve the Google project number

  1. Go to the Google API Console
  2. In the top right of the screen click the three dot menu option next to your profile picture.
  3. Click "Project Settings"
  4. Copy the "Project Number" and paste it somewhere for safe keeping. We will refer to this as <project-number> throughout this blog post in code examples

Setup JWT access

Next we need to create the JWT token. This will provide us with the information that we need to programmatically access the Google Calendar API in a secure context.
  1. Go to the Google API Console 
  2. Choose "Credentials" from the left hand navigation
  3. Click the "Create Credentials" button
  4. Choose "Service account key"
  5. This will download a JSON file to your computer. We will refer to this as the JWT JSON file throughout this blog post.

Setup the Google calendar

Finally we need to configure the Google calendar and retrieve the ID. This was the tricky step as you have to give the JWT token access to you calendar as mentioned in steps 5-7 below. Our JWT token essentially acts as a separate user profile. Using it's client email we could give it access to various Google API's and services, even on other Google accounts.
  1. Go to Google Calendar
  2. On the left hand side hover over the calendar that you want to list events for and click the three dot menu icon
  3. Click "Settings and sharing"
  4. Scroll down and copy the "Calendar ID" and paste it somewhere for safe keeping. We will refer to this as <calendar-id> throughout this blog post in code examples.
  5. Open up the JWT JSON file and copy the client email.
  6. Go to the "share with specific people" section of the calendar and click "Add people"
  7. Paste the client email and submit the dialog

Setup example Express project

Now let's create a sample project using Node.JS with an Express server. Create a directory for your project and run the following commands:
npm init
npm install express --save
npm install googleapis --save

Create your Express server

Finally we need to write code that will start up an express server to listen to requests, contact the Google Calendar API with our connection details that we retrieved above, and then reply with the result. Note that the constants defined at the start of the file need updated based upon the corresponding values we retrieved earlier. The <private-key> and <client-email> values both come from the JWT JSON file.

/index.js

const express = require('express');
const { google } = require('googleapis');

const app = express();
const port = 3000;

const SCOPES = 'https://www.googleapis.com/auth/calendar.readonly';
const GOOGLE_PRIVATE_KEY="<private-key>"
const GOOGLE_CLIENT_EMAIL = "<client-email>"
const GOOGLE_PROJECT_NUMBER = "<project-number>"
const GOOGLE_CALENDAR_ID = "<calendar-id>"

app.get('/', (req, res) => {
  const jwtClient = new google.auth.JWT(
    GOOGLE_CLIENT_EMAIL,
    null,
    GOOGLE_PRIVATE_KEY,
    SCOPES
  );

  const calendar = google.calendar({
    version: 'v3',
    project: GOOGLE_PROJECT_NUMBER,
    auth: jwtClient
  });

  calendar.events.list({
    calendarId: GOOGLE_CALENDAR_ID,
    timeMin: (new Date()).toISOString(),
    maxResults: 10,
    singleEvents: true,
    orderBy: 'startTime',
  }, (error, result) => {
    if (error) {
      res.send(JSON.stringify({ error: error }));
    } else {
      if (result.data.items.length) {
        res.send(JSON.stringify({ events: result.data.items }));
      } else {
        res.send(JSON.stringify({ message: 'No upcoming events found.' }));
      }
    }
  });
});

app.listen(port, () => console.log(`Example app listening on port ${port}!`));

Now run your server with "node index.js" and go to localhost:3000 to see the result. You should see up to the next 10 events that were added to the Google calendar. This can be used to integrate a Google Calendar with an upcoming events feature on a website or could serve as a starting point for other features requiring a Google calendar integration. The JWT authentication shown here can be used for a wide variety of Google APIs. Now I will explain each part of the code in turn.

Create a JWT client

This code uses the "google.auth.JWT" class from the "googleapis" npm library to create a JSON Web Token client that can be used to connect to Google APIs. If it has been correctly configured in the various Google admin panels (as we did earlier) then this should allow us to connect to the Google calendar.
const jwtClient = new google.auth.JWT(
  GOOGLE_CLIENT_EMAIL,
  null,
  GOOGLE_PRIVATE_KEY,
  SCOPES
);

Connect to our project

This code creates an instance of the "google.calendar" using the jwtClient that we created above. Note that we are providing it the number of our Google project but that we have not yet specified what calendar that we want to retrieve events for.
const calendar = google.calendar({
  version: 'v3',
  project: GOOGLE_PROJECT_NUMBER,
  auth: jwtClient
});

Connect to our calendar

The "calendar.events.list" method is one of many that we could connect to at this point. The full HTTP API is explained on the Google Calendar API Reference page. However this "googleapis" Node.JS library seems to have much morel limited documentation, even if the underlying HTTP requests that this library makes are the same. As you can see this is where we specify parameters to the API such as what date to start from, how many results to get, and how to order the results. This JSON object that you see below is the first parameter to the "calendar.events.list" method.
calendar.events.list({
  calendarId: GOOGLE_CALENDAR_ID,
  timeMin: (new Date()).toISOString(),
  maxResults: 10,
  singleEvents: true,
  orderBy: 'startTime',
}, ... )

Return the event list

The second parameter is a function which will give you either an error or a result. If there is an error we simply turn the error into a string and return it in the Express response. If there are results then we simply turn the items into a string and then return this in the Express response.
calendar.events.list({
  ...
}, (error, result) => {
  if (error) {
    res.send(JSON.stringify({ error: error }));
  } else {
    res.send(JSON.stringify({ events: result.data.items }));
  }
});

There are a few things to keep in mind with this example. First and foremost you would want to move the constants that we defined at the start into environment variables and reference them with "process.env.GOOGLE_CALENDAR_ID", as an example. Secondly you would not want to return the entire error object to the client. Finally you would want to accept GET parameters in the Express request object and then pass these through to the "calendar.events.list" method so that the client can specify the type of data it wants.

Final thoughts

JWT provides flexible access to the Google API's, and going through and understanding the process in an example such as we have done here opens up a whole new world of available data to integrate with. Exploring the Google API Library can spark many ideas, and the authentication that we described above makes all of it available. Keep in mind that the JWT token needs used in a secure context, and therefore could not be used to directly connect JavaScript running in the browser to a Google API. Instead the browser JavaScript would need to connect to a server API that in turn connects to the Google API, which is what we have demonstrated above.

Comments

Popular Articles

The Vanilla Javascript Component Pattern

The Sunless Citadel: A D&D 5e Session Report

Getting Started with Harp