Google Apps Script API Authorizations for DriveApp.getFileById

797 views Asked by At

I have a Google Cloud Platform Project (GCP) that runs almost all scripts/functions directly, but a couple through an API. Everything is only accessible internally to the G Suite domain, and the OAuth consent screen Application Type is "Internal".

enter image description here

I have a script, which is not called via an API, but directly on a timer every x minutes. It performs a

DriveApp.getFileByID(pictureID)

This works great! No problems.

I also have a different script, in the same GCP Project, which instead of running triggered by a timer, runs by being called through an API. Here is the line of code that calls it (not really important):

var result = UrlFetchApp.fetch(url, options);

The API script runs great! Until it gets to the following lines:

      try { var file = DriveApp.getFileById(pictureID); }
      catch (e) {
        Logger.log('e = ' + JSON.stringify(e));
        return;
      }

The result of the log is

e = {"name":"Exception"}

I verified that the pictureID is the same as it is in the non-API script that works. I am doing a "try" in this API-run script to make sure that the software has access to the file, not to actually access it.

I am pretty sure that this is an authorization issue. I've been using GCP only for a little while now, have some experience with authorizations, but not a lot.

Here are some details around the authorizations...

The project's scripts Project Properties (File/Project Properties) shows that it needs the following OAuth Scopes: enter image description here

According to Google's documentation at https://developers.google.com/apps-script/reference/drive/drive-app#getfilebyidid,

Scripts that use this method require authorization with one or more of the following scopes: 

https://www.googleapis.com/auth/drive.readonly
https://www.googleapis.com/auth/drive

Here are the scopes that I've defined now on the GCP Oauth consent screen: enter image description here

As you can see, I've added drive, drive.readonly, & drive.file (which doesn't really seem to be needed).

On top of it all, this particular image file is stored in the Google Drive of the owner of the GCP Project, scripts, and top-level admin of the G Suite domain. That will not always be the case, as users will be sharing images from their own Google Drive to this software/GCP owner. However, I have a feeling that even now the script triggered by a timer would work with those user-shared files, but not the script called through an API.

I'm pretty sure this is an Auth issue, but I am missing something somewhere.

Thank you for your help!

Update:

Here is the code from the script that CALLS the API script (changed some for confidentiality), as I'm wondering if perhaps the problem may not be on the client/calling side. Perhaps I'm not getting the OAuthToken correctly? Or the token doesn't have the correct permissions?

  var token = ScriptApp.getOAuthToken();
  
  var header = {
    "Content-Type": "application/json",
    "Authorization": "Bearer " + token,
  };
  
  var parms = [id];
  
  var data = {
    "function": "updateSettings",
    "parameters": parms,
    "devMode": true,
  }
  
  var options = {
    "method":"POST",
    "headers": header,
    "muteHttpExceptions": true,
    "payload": JSON.stringify(data)
  };
  
  // Call the API
  var result = UrlFetchApp.fetch(url, options);
1

There are 1 answers

0
Chris On BEST ANSWER

I figured it out after contacting Google, and unfortunately not getting much help, and a few more hours of trying and research...

What I was missing was adding "oathScopes" to the manifest/appsscript.json file. I played around with the scopes needed and ended up with the following two shown below. I figured out the solution by looking at this answer: Using AuthToken obtained via ScriptApp.getAuthToken() to call web apps in GAS.

Inside the script editor, go to View/Show manifest file.

Here is what it looked like before:

{
  "timeZone": "America/New_York",
  "dependencies": {
  },
  "webapp": {
    "access": "MYSELF",
    "executeAs": "USER_DEPLOYING"
  },
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8"
}

and here is what it looks like now...

{
  "timeZone": "America/New_York",
  "dependencies": {
  },
  "webapp": {
    "access": "MYSELF",
    "executeAs": "USER_DEPLOYING"
  },
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "oauthScopes": [
    "https://www.googleapis.com/auth/drive",
    "https://www.googleapis.com/auth/script.external_request"
    ]
}

After adding, I saved appsscript.json. I then went to my runOnEdit trigger (the calling script), removed and re-added it. However, that caused a nasty looking error: enter image description here

I looked that up, and found this post: Receiving error when creating new trigger on Apps Script. So, I ran the code in the script editor, and indeed it brought up the auth screen. I approved, re-added the trigger, and now everything works great in calling the API!