google-apps-scriptweb-applicationsgoogle-oauth

How to connect with UrlFetchApp to Apps Script web app when I have "anybody with google account" options on


I have a very simple stand-alone google scripts project which is deployed as a Web App. It just contains two test functions:

function doGet(e) {
  Logger.log(e);  
  return ContentService.createTextOutput('Get OK');
}

function doPost() {
  Logger.log("doPost");  
  return ContentService.createTextOutput('Post OK');
}

I have another Apps Script project with a simple function:

function doConnect() {
    var response = UrlFetchApp.fetch(
        "https://script.google.com/macros/s/XXXXXXXXX/exec",
        {
            method: "get",
            muteHttpExceptions: true
        }
    );
  Logger.log(response.getContentText());
}

At the moment I am testing things and run my doConnect just from Run button in the Apps Script editor.

Context: As soon as the above proof-of-concept works, I would fire my doConnect from spreadsheet "button" (image with bound script). This script would run with permissions of spreadsheet owner refresh some values in protected cells that are untouchable for regular editors.

All works perfectly when a web app is deployed with "Who has access" = "Anyone" option. When I change this option to "Anyone with Google account" I get "Error 401 Unauthorized".

In order to pass authorization info I have modified my function as below, but no success.

function doConnect() {
    var response = UrlFetchApp.fetch(
        "https://script.google.com/macros/s/XXXXXXXXX/exec",
        {
            method: "get",
            headers: {
                Authorization: "Bearer " + ScriptApp.getOAuthToken()
            },            
            muteHttpExceptions: true
        }
    );

  Logger.log(response.getContentText());
}

When I just paste the url into another tab of the same browser - I get the expected result. Am I somehow able to pass authorization info via request?


Solution

  • In the case of Google Apps Script Web Apps, when "Who has access" is set to "Anyone with a Google account" and a client is required to send requests to the Web App, it is necessary to include an access token in the request. At that time, one of the Drive API scopes must be included. If the scope is missing, an error will occur. I suspect this might be the cause of your current issue. To resolve this, consider modifying your script as follows:

    Modified script

    function doConnect() {
        var response = UrlFetchApp.fetch(
            "https://script.google.com/macros/s/XXXXXXXXX/exec",
            {
                method: "get",
                headers: {
                    Authorization: "Bearer " + ScriptApp.getOAuthToken()
                },            
                muteHttpExceptions: true
            }
        );
    
      Logger.log(response.getContentText());
    
      // Please add the following comment line.
      // DriveApp.getFiles();
    }
    

    In this modification, the comment line // DriveApp.getFiles(); is added. When this comment line is included and the script is run, the scope https://www.googleapis.com/auth/drive.readonly is automatically added by the script editor. This ensures that the access token used for requesting the Web App includes the necessary scope.

    Of course, the comment line // DriveApp.createFile(); can also be used. In this case, the scope https://www.googleapis.com/auth/drive will be added.

    Note

    Reference