Home > Software design >  Invoking an Authenticated cloud function from Google AppScript
Invoking an Authenticated cloud function from Google AppScript

Time:09-27

I have seen many questions in invoking cloud functions from AppScript, but I am unable to invoke the function from any of those methods. Here are the things I have already checked:

[x] - Invoke successful from Google Cloud Testing Tab

[x] - Invoke successful from command line: curl <CLOUD_FUNCTION_URI> -H "Authorization: bearer $(gcloud auth print-identity-token)"

[x] - Invoke successful from Call API: gcloud functions call YOUR_FUNCTION_NAME --data '{"name":"Keyboard Cat"}'

[x] - Invoke successful from Python client library:

from modules.cloudInvoker import CloudFunctionInvoker
from os import environ
uri = environ['URI']


invoker = CloudFunctionInvoker(service_account_path=r'secrets/service.json',
endpoint=uri)

if __name__ == '__main__':

    response = invoker.session.post(uri,json={
        "test":True
        })
    print(response)

where my invoker Class looks like this:

from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession


class CloudFunctionInvoker:
    def __init__(self,service_account_path:str,endpoint:str)->None:
        try:
            self.path = service_account_path
            self.creds = service_account.IDTokenCredentials.from_service_account_file(service_account_path, target_audience=endpoint)
            self.session = AuthorizedSession(self.creds)
        except Exception as e:
            raise(e)
    
    def updateEndpoint(self,new_endpoint:str)->None:
        try:
            self.creds = service_account.IDTokenCredentials.from_service_account_file(self.path, target_audience=new_endpoint)
            self.session = AuthorizedSession(self.creds)
        except Exception as e:
            raise(e)

But when I try to invoke the same function using app script as shown below:

const cloudFunctionInvoker = (payload,cloud_function_uri) => {
  const token = ScriptApp.getIdentityToken();
  // const token = ScriptApp.getOAuthToken();

  const headers = { "Authorization": "Bearer "   token };
  const options = {
      "method": "post",
      "headers": headers,
      "muteHttpExceptions": true,
      "contentType": "application/json",
      "payload": JSON.stringify(payload||{})
  };

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

  try{
  const response_object = JSON.parse(response.getContentText());
  console.log(response_object);
  }
  catch(e) {
    console.log("Error = ", e.message);
    console.log(response.getContentText());

  }
}

I get a 401 unauthorized error.

I have tried using both identity token and OAuth token, but none of them works.

Additionally, I have also set up my manifest.json to include scopes:

"oauthScopes": [
    "https://www.googleapis.com/auth/cloud-platform",
    "https://www.googleapis.com/auth/script.external_request"
  ],

Finally, I changed my project to work within the google cloud project environment: enter image description here

But none of these worked for me. Here's the command I used to deploy my cloud function:

gcloud functions deploy <function_name> --entry-point main --runtime python39 --source . --timeout 540 --trigger-http

Allow unauthenticated invocations of new function <function_name>? 
(y/N)?  n

WARNING: Function created with limited-access IAM policy. To enable unauthorized access consider `gcloud alpha functions add-iam-policy-binding <function_name> --region=us-central1 --member=allUsers --role=roles/cloudfunctions.invoker`

CodePudding user response:

I wrote an article on that topic, but focus on Cloud Run.

The security principle on Cloud Run and Cloud Functions is the same (the same underlying infrastructure is shared between both). So you should be able to achieve what you want with that article. If not, let me know I will help you.

  • Related