0

I have been trying (with little success) to have a google cloud function be triggered via an http request from a google sheet (google apps script) and it seemingly won't work. A few important things:

  • The function should only run if the user comes from my organization
  • The user should not have to be invited to the GCP project

I know this can be done very easily in google colabs and Python. The following script will let a user in my organization who is not in the GCP project trigger the cloud function:

import requests
import google.auth
from google.auth.transport.requests import Request
from google.colab import auth


credentials, project_id = google.auth.default()
request = Request()
credentials.refresh(request=request)

GCF_URL = ''https://project_location-project_id.cloudfunctions.net/name-of-your-funciton'' 
resp = requests.get(GCF_URL, headers={'Authorization': f'Bearer {credentials.id_token}'})

This will work and trigger the cloud function for any users inside my organization but does not work for my personal email for example.

Now, I would like to replicate this behvaiour inside a google apps script such that an end user with access to that sheet can trigger the cloud function as long as they are a member of my organization.

I have tried some things I have seen online such as this example:

function callExternalUrl() {

    var url = 'https://project_location-project_id.cloudfunctions.net/name-of-your-funciton';

    var oauthToken = ScriptApp.getOAuthToken(); // get the user who's logged into Google Sheet's OAuth token

    const data = {
        oauthToken, // 1. add the oauth token to the payload
        activeUser: param.user // 2. this here is important as it adds the userinfo.email scope to the token
        // any other data you need to send to the Cloud Function can be added here
    };

    var options = {
        'method' : 'get', // or post, depending on how you set up your Cloud Function
        'contentType': 'application/json',
        // Convert the JavaScript object to a JSON string.
        'payload' : JSON.stringify(data)
      };

    const response =  UrlFetchApp.fetch(url, options); 

    Logger.log('Response Code: ' + response.getResponseCode());

}

This gives a 403 error but if I change it up so that it gives the OAuth on the correct format like this:

function callExternalUrl() {

    var url = 'https://project_location-project_id.cloudfunctions.net/name-of-your-funciton';

    var oauthToken = ScriptApp.getOAuthToken(); // get the user who's logged into Google Sheet's OAuth token


    var response = UrlFetchApp.fetch(url, {
    headers: {
      Authorization: 'Bearer ' + oauthToken
    }
  });
    // const response =  UrlFetchApp.fetch(url, options); 

    Logger.log('Response Code: ' + response.getResponseCode());

}

I get a 401 (i.e. the authorization failed). Now, it seems that I simply have to get the correct authentication from the users to send in this request for it to work. I have seen this github repo that focuses on getting OAuth2 from google apps scripts (https://github.com/gsuitedevs/apps-script-oauth2), but I can't seem to get that to work either, it would have to be adapted to cloud in some way I am unaware of.

I have read

Securely calling a Google Cloud Function via a Google Apps Script

which is very similar but it did not seem to get to the root of the problem, any input on how to make this process possible?

Fredrik Nilsson
  • 549
  • 4
  • 13
  • Hi ! You basically want to trigger this Cloud function if a user of your organization runs the script (which is in a sheet) am I right? You said *"This will work and trigger the cloud function for any users inside my organization but does not work for my personal email for example."* but then you say *" I would like to replicate this behvaiour inside a google apps script such that an end user with access to that sheet can trigger the cloud function as long as they are a member of my organization."*. **Which people do you want to authorise to run the function?** – Mateo Randwolf May 27 '20 at 07:09
  • Hi! I want people in my organization to be able to trigger it, but not other people. That is, the same as in the Python example. I have set up our organization domain as cloud function invoker so that part works, the issue is all about how to get the OAuth2 identity token in apps script :) – Fredrik Nilsson May 27 '20 at 07:13
  • Then I believe it should be working for all the users of your organization. Have you followed [all these steps](https://developers.google.com/apps-script/api/how-tos/execute#target-script) to be able to call a Google Cloud App with your Apps script script? – Mateo Randwolf May 29 '20 at 14:28
  • It says unfortunatly in the link that you provide that the script calling and the application must share a GCP project, which does not work in this case – Fredrik Nilsson Jun 01 '20 at 07:23
  • Do you have a GCP project for your Google Cloud function? You could be the owner of the script/sheet that is linked to that GCP project and let the other users of your organization access the sheet and have the ability to therefore, trigger your script. I believe that as long as you created the script you can link it to the GCP project and therefore let everyone in your organization trigger it. Let me know if that works. :) – Mateo Randwolf Jun 02 '20 at 09:08
  • That will not work because users (who have no access to the GCP project) need to be able to duplicate the sheet unfortunately :) – Fredrik Nilsson Jun 02 '20 at 10:03
  • So, I have tried to figure out how the sharing permissions work and I believe I got it now. So if you share a sheet with its script or a script you are just granting apparently access to that sheet and script, not to the GCP project the script is in. So the users will be able to run and use this script without being able to change the configuration of the GCP project. Could you give this a try **in an example script and GCP project (not your original one, one for testing just in case)** to see if the users that make a copy of the script can run it and call successfully the GCP function? – Mateo Randwolf Jun 04 '20 at 09:41

0 Answers0