Integrating Firebase Cloud Functions with Google Calendar API

I’ve recently started using Firebase for my projects, and found some success with their hosting, Firestore, and authentication services. When I tried using their Cloud Functions, I saw value in integrating it with their Google Calendar API. I wanted to be able to trigger the cloud function and have it manage my personal Google Calendar, but ran into some problems with the function’s authorization since I didn’t want to need a sign-in each time it executed.

After a lot of headaches, I consulted a fellow developer who had some experience with using OAuth2 and Google APIs. (Be sure to check out his Medium article on Node.js, OAuth2, and Gmail here!) Be sure to have NPM installed before beginning this tutorial.

With this problem solved, I was finally able to get my Firebase Cloud Function to quickly add events to my primary Google calendar via an HTTP trigger with only minimal details in the request body. A repository (minus the OAuth2 credentials.json file) with the code used to create our cloud function can be found here.


Part 1: Setting up your Firebase App

Obviously, the first thing we need to is to create a Firebase app. This can be done through the Google Developer Console and integrating Firebase into your app later, but I’ll be using the Firebase Console. After signing in to your Google account, you should get a list of all your Firebase projects and an Add Project button. When you click Add Project, you’ll be prompted to fill in your project details.

Creating a Firebase Project

The Project Name can be anything you like, but the Project ID must be unique through all Google projects. As you can see above, my project ID is calendar-cloud-function, but I’ll be using PROJECT_ID for the remainder of the article as an indication for you to replace with your specific Firebase project ID.

Be sure to accept all terms and conditions in the window. Once doing so, click Create project to finish creating your Firebase project. This process will take several seconds before confirming that your project was indeed created successfully. You can then enter your Firebase project.

NOTE: Behind the scenes, a project is also made in the Google Developer Console that will be used later.

If we go to the Functions tab on the left under Develop section, we’ll see our dashboard where our Cloud Functions will live.

Firebase Cloud Functions Dashboard

Because we just created this project, there will be nothing listed here. Once you add a Function to your project, you can come back to this dashboard to see the logs, HTTP trigger, and other important information about your function.

Part 2: Initializing our Firebase Project

Now that we have a Firebase project initialized on our account, we’ll be able to add/deploy Cloud Functions and integrate any other Firebase product with our project.

Open up the command prompt and navigate to a workspace where you want to house your project. Run mkdir PROJECT_ID to create a directory with the same name as your Firebase project and cd into the new directory.

First, you’ll need to download the Firebase CLI with npm install -g firebase-tools. Once installed, login to your Firebase account with the command firebase login. This will grant the CLI access to your account so that you can manage and deploy code to specific Firebase projects.

The Firebase CLI also provides helpful tools to initialize code for specific Firebase products. Run firebase init to begin the setup the project architecture for your cloud function.

Initializing your Firebase project

For this tutorial, we are only working with Firebase Cloud Functions. Select Functions for your project setup and press enter to continue with the initialization of your project.

Next, the Firebase CLI will want to know which project you want your Cloud Function to be associated with. Select the correct PROJECT_ID for the Firebase project and press enter.

Selecting the Firebase Project

After pressing Enter, you will be given the option to write the Cloud Function in JavaScript or TypeScript. Feel free to choose either, but the code for this tutorial was written in JavaScript. Continue with the rest of the project setup. For ease of use later, be sure to install the npm dependencies and a linter during your project initialization.

The Final Steps of Firebase Project Initialization

Once the npm dependencies are downloaded, your Firebase project should be created and ready to use. Open up the root directory in your favorite IDE and we can begin writing code!

Firebase Project Architecture

Your project should have the following architecture. If you enabled a linter for your project, we’ll need to make a minor change to the firebase.json file in the root directory.

In the predeploy array, edit the line "npm --prefix \"RESOURCE_DIR\" run lint" to "npm --prefix functions run lint". The entirety the file should now be as follows:

{
"functions": {
"predeploy": [
"npm --prefix functions run lint"
]
}
}

In our index.js file, you should see some commented out code. At this point, let’s uncomment the helloWorld function and deploy it to Firebase in order to see if everything is configured correctly. After commenting out the function, index.js should look like this:

A HelloWorld Cloud Function

This will return a message of “Hello from Firebase!” when the Cloud Function is executed. In the command prompt, run firebase deploy --only functions in the project’s root directory. The deploy will take ~1 minute to complete, but should succeed. Once successful, navigate back to your project’s Firebase dashboard and see our newly created helloWorld function listed in the Functions dashboard with an HTTP endpoint for a trigger.

Firebase Functions Dashboard

Copy the HTTP endpoint and paste it in a new tab of the browser. This will execute your function and you should get a “Hello from Firebase!” message back. This means that your project is configured correctly and now have a Cloud Function deployed!

This function doesn’t do much, but the opportunities for what it can do are endless. For this tutorial, we will be working with the Google Calendar API (v3). Google has hundreds of other APIs available, and I encourage you to check them out once you are done with this article. To work with Google APIs, you will first need to set up our OAuth2 credentials. This will authenticate your function when interacting with Google’s APIs.

Part 3: Create Calendar API Credentials

For this part, we’ll be generating our API credentials that our Cloud Function will use to interact with the Google Calendar API. This eliminates the need for sign-in prompts and allows your cloud function to execute quickly and reliably with a fresh token to access your specific Google Calendar.

First, go to the Google Developer Console and select the project you created if it is not already selected. You should be on your project’s main dashboard, with cards for many different aspects of your project. Select Go to APIs overview in the section for APIs.

Main dashboard for your GCP Firebase project

In the API Dashboard, select Credentials from the menu on the left. If you’ve made credentials for other apps, you may have some already listed here, otherwise you’ll be prompted to create your own credentials.

Options for Creating API Credentials

You may see a warning banner near the top of the page saying:

To create an OAuth client ID, you must first set a product name on the consent screen

To fix this, click the Configure consent screen button on the alert and pick a name for your “product”. Once you name your product, you may need to select an email for a Support Email before the Save button is enabled. Once enabled, click Save to be redirected to the OAuth Client ID creation screen.

On the credentials screen, select Web Application under Application Type to bring up the other criteria needed for OAuth credentials. Name the OAuth Client ID something meaningful so you can keep track of the credentials for your project.

OAuth Client ID criteria

Under Authorized redirect URIs in the Restrictions section, add the URI https://developers.google.com/oauthplayground. Once the redirect URI is added, click anywhere outside the input to ensure the URI was entered correctly. If everything looks correct, click the Create button at the bottom!

If your OAuth client credentials were created successfully, you will be redirected back to your credentials screen with the following alert window active:

Your OAuth Client credentials

If you click OK, you should see the credentials listed under the OAuth2.0 client IDs section on the Credentials page.

In the right-most column for your client ID is a download icon. This will download a JSON file of the OAuth client credentials. The file should contain the following data:

{  
"web":{
"client_id":"CLIENT_ID.apps.googleusercontent.com",
"project_id":"PROJECT_ID",
"auth_uri":"https://accounts.google.com/o/oauth2/auth",
"token_uri":"https://www.googleapis.com/oauth2/v3/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_secret":"CLIENT_SECRET",
"redirect_uris":[
"https://developers.google.com/oauthplayground"
]
}
}

Rename this file to credentials.json and save it in the same directory as index.js file for the project you created in Part 2.

Part 4: Configure OAuth2 for your project

Now that we have our OAuth Client credentials, we’ll need to actually go into our redirect URI and configure the OAuth2. To do this, go to https://developers.google.com/oauthplayground. On the page, click the Settings icon in the top-right of the screen to pull up the configuration settings. Select Use your own OAuth credentials at the bottom to bring up inputs for the Client ID/Client Secret you just created.

OAuth2 Configuration

After entering both the Client ID and Client Secret from your credentials.json file you created in Part 3, leave the above window open. On the left-side of the screen, search for the Calendar API v3 and select the appropriate scope that you want your cloud function to have.

OAuth2 Calendar API configuration

Because we want our app to manage/edit/read from your Google Calendar, select the scope https://www.googleapis.com/auth/calendar for full read/write access. Once that scope is selected, click Authorize APIs at the bottom of Step 1.

You’ll be taken to a Google sign-in page where you sign in to the Google account who’s calendar you want to access. Once signed in, you’ll be asked to confirm access for your credentials to manage your Google calendars. Approve of this message to continue. This will redirect you to Step 2 of the OAuth2 Playground form.

OAuth2 Configuration Step 2

You should have the Authorization code populated. This code is only valid for a short period of time (3600 seconds precisely). While it’s active, you’ll need to click Exchange authorization code for tokens to populate a refresh token that we will be able to use later in our cloud function.

For this tutorial, we will add this refresh token to the credentials.json file we created earlier to limit the number of files accessed by our cloud function later. An updated version is below, and your file should be the same format.

Updated credentials.json File

There you go! You now have OAuth2 configured for your cloud function so that the Refresh token, Client ID, Client Secret can get you a valid Access token when working with the Google Calendar API. If you initialize this project as a Git repository, be sure to specify credentials.json in your .gitignore file so that you don’t accidentally add your credentials to a public repository.

Part 5: Write a Cloud Function to interact with Google Calendar

Now that we have OAuth2 configured for the Google Calendar API, we can begin writing code to interact with it! To do this, navigate to your project in the command line and go into the functions folder where your package.json lives. There, run npm i googleapis --save to install the necessary Google API Node.js tools.

First thing we’ll do is import all the required packages we’ll be using. The completed code for index.js can be found here. We’ll put this at the top of our file, before any methods we write later. Be sure that credentials.json is in the same folder as index.js, otherwise the path will be need to be updated.

Next, we’ll begin writing our Firebase function. In Part 2 of this tutorial, we wrote a helloWorld() Firebase function. We’ll replace that with the following addEventToCalendar() method.

The request and response parameters act as entry points and exits for our cloud function to interact with Firebase and the user. The request will have the data needed to make our calendar event, and we create that event in the first line of the function, storing it in eventData.

Next, we use our imported googleCredentials to create an oAuth2Client object with all the credentials we need to verify us as the correct user. We then set the refresh_token for the oAuth2Client credentials so that we have a fresh token when accessing the Google Calendar API.

Finally, we call a method addEvent() that has not been written yet, passing it the eventData and oAuth2Client details, waiting for either a Success or Failure. Once either is received, we pass the details of what happened back to the user with the response parameter given by Firebase.

The last method we need to write is the addEvent() method reference above. The full method is below:

As mentioned before, we passed our calendar event and authentication that were created in the initial addEventToCalendar() Firebase function. We then use the Google Calendar API by referencing the calendar object we created earlier. The full API for the Google Calendar can be found here. If successful, we pass the newly-created calendar event data back in the Promise with a message of Success that will be handled by the Firebase function we created above.

And that’s it! The Firebase function is now complete. Like before, we will deploy this function by running the command firebase deploy --only functions in the root directory of the project. After a minute or two, the Firebase CLI will say that the Cloud Function is deployed.

Part 6: Executing your Cloud Function

Once your function is deployed, go to the Google Developer Console and navigate to your Firebase project. In the menu on the left, select Cloud Functions from the list. There, you should see the Firebase function you just created in your Cloud Functions dashboard. Click the addEventToCalendar function to get more information about it.

Here, you should see four tabs for your cloud function: General, Trigger, Source, and Testing. Check out each one to learn more about your function, including its HTTP trigger endpoint.

We’ll start by going to the Testing tab though. Here, you’ll see the following input options:

Testing Dashboard for the Cloud Function

The empty {} JSON object is your request body. If you remember, we access several elements of this request body in our cloud function to create the calendar event. Because of this, we’ll need to replace the Triggering Event to something along the lines of:

{
"eventName": "Firebase Event",
"description": "This is a sample description",
"startTime": "2018-12-01T10:00:00",
"endTime": "2018-12-01T13:00:00"
}

Click Test the function to call your Firebase function with the above request body. If everything is correct, you should get a response with details about your newly created event. If you navigate to your Google Calendar, you’ll be able to see your event, exactly where it’s supposed to be.

Created Firebase Event

Conclusion

That’s it, we’ve officially got a Firebase Cloud Function deployed that will create events in your calendar with very minimal details needed in the request body. This function has an HTTP endpoint, so it can be hit by several different methods.

Further work could include using Alexa/Google Home to call that HTTP endpoint after adding specific voice prompts. Besides that, your interaction with the Calendar API could be extended by deleting events, modifying existing ones, reading out events occurring today, or others. Security for your Cloud Function could also be a next-step, so that you are sure that only you and your services are able to call your Cloud Function.

Now that you have a Cloud Function deployed in your Firebase project, I’d encourage you to look into several other Firebase services to expand your project even more. Good luck, and I hoped this help you learn something new about a cool, interesting technology!