node.jsgoogle-calendar-apiservice-accounts

Can't authenticate google service account using Node.js


My goal is to allow people to add events to a calendar through my website (which uses Firebase currently.) I'm attempting to allow them to add the events to a service account; however, I'm having issues getting the service account authenticated. When I attempt to deploy my code, I get an 'unexpected token google' error at the await google.auth.getClient part. I have google API tools installed globally.

//ADD CALENDAR EVENT
const {google} = require('googleapis');
const calendar = google.calendar('v3');

//Authenticate Service Acounnt
function getCredentials() {
  const filePath = path.join(__dirname, 'credentials.json';
  if (fs.existsSync(filePath)) {
    return require(filePath)
  }
  if (process.env.CREDENTIALS) {
    return JSON.parse(process.env.CREDENTIALS)
  }
  throw new Error('Unable to load credentials')
}

//Create Calendar Event
function addEvent(event) {
  return new Promise(function(resolve, reject) {
      calendar.events.insert({
          calendarId: 'primary',
          resource: {
              'summary': event.eventName,
              'description': event.description,
              'start': {
                  'dateTime': event.startTime,
                  'timeZone': TIME_ZONE,
              },
              'end': {
                  'dateTime': event.endTime,
                  'timeZone': TIME_ZONE,
              },
          },
      }, (err, res) => {
          if (err) {
              console.log('Rejecting because of error');
              reject(err);
          }
          console.log('Request successful');
          resolve(res.data);
      });
  });
}

//Add Event To Service Acount 
exports.addEventToCalendar = functions.https.onRequest((request, response) => {

  const eventData = {
      eventName: request.body.eventName,
      description: request.body.description,
      startTime: request.body.startTime,
      endTime: request.body.endTime
  }; 

  const credentials = getCredentials();
  const client = await google.auth.getClient({
    credentials,
    scopes: 'https://www.googleapis.com/auth/calendar',
  }) 

  addEvent(eventData, client).then(data => {
      response.status(200).send(data);
      return;
  }).catch(err => {
      console.error('Error adding event: ' + err.message); 
      response.status(500).send(ERROR_RESPONSE); 
      return;
  });

}); 

I've been following a combination of these two tutorials: https://medium.com/zero-equals-false/integrating-firebase-cloud-functions-with-google-calendar-api-9a5ac042e869 https://dev.to/mornir/create-a-service-account-to-authenticate-with-google-5b1k

I've spent a lot of time googling what could be wrong, but to be honest, this google authentication stuff confuses the heck out of me. I'd appreciate whatever help I can get, thanks :)


Solution

  • If my understanding is correct, how about this modification?

    Modification points:

    Modified script:

    //ADD CALENDAR EVENT
    const { google } = require("googleapis");
    const path = require("path");  // Added
    
    // --- I added below script.
    const key = require(path.join(__dirname, 'credentials.json'));
    const jwtClient = new google.auth.JWT(
      key.client_email,
      null,
      key.private_key,
      ["https://www.googleapis.com/auth/calendar"],
      null
    );
    const calendar = google.calendar({ version: "v3", auth: jwtClient });
    // ---
    
    //Create Calendar Event
    function addEvent(event) {
      return new Promise(function(resolve, reject) {
        calendar.events.insert(
          {
            calendarId: "primary",
            resource: {
              summary: event.eventName,
              description: event.description,
              start: {
                dateTime: event.startTime,
                timeZone: TIME_ZONE
              },
              end: {
                dateTime: event.endTime,
                timeZone: TIME_ZONE
              }
            }
          },
          (err, res) => {
            if (err) {
              console.log("Rejecting because of error");
              reject(err);
              return;
            }
            console.log("Request successful");
            resolve(res.data);
          }
        );
      });
    }
    
    //Add Event To Service Acount
    exports.addEventToCalendar = functions.https.onRequest((request, response) => {
      const eventData = {
        eventName: request.body.eventName,
        description: request.body.description,
        startTime: request.body.startTime,
        endTime: request.body.endTime
      };
    
      addEvent(eventData) // Modified
        .then(data => {
          response.status(200).send(data);
          return;
        })
        .catch(err => {
          console.error("Error adding event: " + err.message);
          response.status(500).send(ERROR_RESPONSE);
          return;
        });
    });
    

    Note:

    References: