Edit on GitHub
Report issue
Page history

Submitted by @{[ TutorialCtrl.tutorial.github_username ]} {[ TutorialCtrl.tutorial.date_published | date:'mediumDate' ]}

title: Using OAuth 2.0 and Google Cloud Functions to access Google services description: Learn how to use OAuth 2.0 with Google Cloud Functions to access a user's data from Google services. author: ace-n tags: Cloud Functions, OAuth, Gmail, G Suite date_published: 2018-01-05


OAuth 2.0 is a community standard that allows users to grant programs access to user data in a secure and reliable manner. In this tutorial, we'll be using a process known as 3-legged OAuth (3LO). Instead of storing usernames and passwords, 3LO lets you store authorization codes. These can then be securely converted into authorization tokens, which can grant access to user data on Google services such as Gmail.

This tutorial assumes you've set up your environment for developing on Google Cloud Platform (GCP). Furthermore, this tutorial covers authenticating with Google services outside of Google Cloud Platform. If you'd like to interact with Google Cloud Platform services, see the documentation for more information.

This process involves several steps:

  • Generating an OAuth 2.0 client ID, which the client can use to authenticate itself with OAuth 2.0 APIs
  • Configuring local files with GCP-project-specific information
  • Deployment of local files to Cloud Functions


Generating an OAuth 2.0 client ID

In order for an OAuth 2.0 API to verify our program's identity, we must include an OAuth 2.0 client ID with some of our requests to the API. The following steps show how to enable the Gmail API and download the client ID to your local machine.

  1. Enable the Gmail API by visiting the Enable an API page in the GCP Console (under APIs > Enable APIs and Services) and selecting the appropriate GCP Project.
  2. Find the GCP region you want to deploy your function to. (In general, response time is quickest for the regions closest to you.) For the rest of this tutorial, replace [YOUR_GCF_REGION] with your selected region's name (for example, us-central1).
  3. Generate a new OAuth 2.0 client ID by visiting the GCP Console credentials page. Configure the fields as indicated below:

    • Application type: Web application
    • Name: an appropriate, memorable name for your client
    • Authorized JavaScript origins: https://[YOUR_GCF_REGION]-[YOUR_GCP_PROJECT_ID].cloudfunctions.net/oauth2callback
  4. Click Create, then close the resulting dialog box and click the Download icon next to your newly created client ID. The resulting file is your Client Secret file.

Configuring local files

Now that you've created a Client Secret file, you can download the code and configure it to use a particular GCP project and Cloud Functions execution region. The function needs this information when running on Cloud Functions, so these changes must be made prior to deployment.

  1. Create a file named index.js file from the provided index.js file.
  2. Create a package.json file from the provided package.json file.
  3. Rename your Client Secret file to client_secret.json, and move it to the directory that contains your index.js and package.json files.
  4. In index.js, replace [YOUR_GCP_PROJECT_ID] and [YOUR_GCF_REGION] with your GCP Project ID and GCF region ID respectively.


Once you've configured your local files appropriately, run the following commands in the same directory as index.js to deploy the appropriate Cloud Functions:

gcloud beta functions deploy oauth2init --trigger-http
gcloud beta functions deploy oauth2callback --trigger-http
gcloud beta functions deploy listlabels --trigger-http

Visit https://[YOUR_GCF_REGION]-[YOUR_GCP_PROJECT_ID].cloudfunctions.net/oauth2init to see your Cloud Functions in action, or go to the GCP Console's Stackdriver page to see the logs.

Code overview

The code in this tutorial implements 3LO using Cloud Functions and the Gmail API. Below is a brief synopsis of the key parts of index.js.

Requesting an authorization code

The first step of 3LO is to request an authorization code. The scopes field defines what permissions the generated authorization code will grant. For this tutorial, we need read-only access to a user's Gmail account.

exports.oauth2init = (req, res) => {
  // Parse session cookie
  // Note: this presumes 'token' is the only value in the cookie
  const cookieStr = (req.headers.cookie || '').split('=')[1];
  const token = cookieStr ? JSON.parse(decodeURIComponent(cookieStr)) : null;

  // If the current OAuth token hasn't expired yet, go to /listlabels
  if (token && token.expiry_date && token.expiry_date >= Date.now() + 60000) {
    return res.redirect('/listlabels');

  // Define OAuth2 scopes
  const scopes = [

  // Generate + redirect to OAuth2 consent form URL
  const authUrl = oauth2Client.generateAuthUrl({
    access_type: 'online',
    scope: scopes

Handling the authorization token

The second step of 3LO is to receive the authorization code (via a callback URL) and store it for safekeeping. In this example, we store it in a cookie on the user's machine.

exports.oauth2Callback = (req, res) => {
  // Get authorization details from request
  const code = req.query.code;

  return new Promise((resolve, reject) => {
    // OAuth2: Exchange authorization code for access token
    oauth2Client.getToken(code, (err, token) => {
      if (err) {
        return reject(err);
      return resolve(token);
    .then((token) => {
      // Respond with OAuth token stored as a cookie
      res.cookie('token', JSON.stringify(token));
    .catch((err) => {
      // Handle error
      res.status(500).send('Something went wrong; check the logs.');

Interacting with Google services

The final step of 3LO is to interact with the appropriate end-user services. In this example, we'll list the user's Gmail labels.

exports.listlabels = (req, res) => {
  // Parse session cookie
  // Note: this presumes 'token' is the only value in the cookie
  const cookieStr = (req.headers.cookie || '').split('=')[1];
  const token = cookieStr ? JSON.parse(decodeURIComponent(cookieStr)) : null;

  // If the stored OAuth 2.0 token has expired, request a new one
  if (!token || !token.expiry_date || token.expiry_date < Date.now() + 60000) {
    return res.redirect('/oauth2init').end();

  // Get Gmail labels
  oauth2Client.credentials = token;
  return new Promise((resolve, reject) => {
    gmail.users.labels.list({ auth: oauth2Client, userId: 'me' }, (err, response) => {
      if (err) {
        return reject(err);
      return resolve(response.labels);
    .then((labels) => {
      // Respond to request
      res.set('Content-Type', 'text/html');
      res.write(`${labels.length} label(s) found:`);
      labels.forEach(label => res.write(`${label.name}`));
    .catch((err) => {
      // Handle error
      res.status(500).send('Something went wrong; check the logs.');
See more by @{[ TutorialCtrl.tutorial.github_username ]} and more tagged {[ tag ]}{[ $last ? '' : ', ' ]}

Submit a Tutorial

Share step-by-step guides


Request a Tutorial

Ask for community help


GCP Tutorials

Tutorials published by GCP


Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see our Site Policies. Java is a registered trademark of Oracle and/or its affiliates.