4

I created 2 simple standalone scripts to test the authorization workflow. The first script is a web app that is accessible only to me.

function doGet(e) {

return ContentService.createTextOutput(JSON.stringify({"message":"works!"}))
                     .setMimeType(ContentService.MimeType.JSON);

}

The calling script gets the token via ScriptApp.getAuthToken() and makes a 'GET' request to the web app.

function call() {

var token = ScriptApp.getOAuthToken();
var header = {"Authorization":"Bearer " + token};
var options = {
"method":"GET",
"headers": header,
"muteHttpExceptions": true
};


var url = 'APP_URL';

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

Logger.log(response.getResponseCode()); //returns 401
Logger.log(response.getContentText()); // returns 'Unauthorized'

}

Unfortunately, it doesn't seem to work as I get the 'Unauthorized' response. My initial thought was that the token is scoped to each individual script, but GAS documenation indicates the contrary, stating that the ScriptApp token would be sufficient in month cases.

https://developers.google.com/apps-script/reference/script/script-app#getOAuthToken()

I would appreciate any help.

Anton Dementiev
  • 5,451
  • 4
  • 20
  • 32
  • Also, be noted that the [token](https://developers.google.com/apps-script/reference/script/script-app#getOAuthToken()) expires after a time (a few minutes at minimum) and scripts should handle authorization failures and call this method to [obtain a fresh token](https://ctrlq.org/code/20155-oauth-authorization-errors-execution-api) when needed. – abielita Aug 07 '17 at 13:41
  • The examples you gave describe scenarios where the script is being called from outside GAS using GAS Execution API whereas I'd like to be able to call the web app from another GAS project. The reason is that I don't want to expose my app by setting the access to 'Anyone, even anonymous'. What if I accidentally expose the link to the app? I still want the script to run only when I access it using my credentials. Hope this makes sense. – Anton Dementiev Aug 08 '17 at 14:58

1 Answers1

8

If you are still looking for this answer, how about this answer? I think that when the scopes are installed by Manifests, you can access the Web Apps using the access token with the scopes.

Deploy Web Apps :

The condition for deploying Web Apps is as follows.

  • On script editor on the project with doGet().
    • Publish -> Deploy as web app
    • For "Execute the app as:", set "Me".
    • For "Who has access to the app:", set "Only myself".

At above condition, when "headers": {"Authorization":"Bearer " + token} is not used for option, the error occurs. So in order to access to Web Apps with above condition, please add the following 2 scopes. In your case, the following scopes are required to authorize.

https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/script.external_request

In your case, the above 2 scopes are required. In the case of only https://www.googleapis.com/auth/script.external_request, the error of Unauthorized occurs.

Add scopes to Manifests :

Please install above scopes to Manifests (appsscript.json) as follows.

  • On script editor on the project with call().
    • View -> Show manifest file
    • Please add the following oauthScopes to appsscript.json.
      • "oauthScopes": ["https://www.googleapis.com/auth/script.external_request", "https://www.googleapis.com/auth/drive"]

Response :

After it installed above, please try to run your call() again. In my environment, I retrieved the following response.

200.0
{"message":"works!"}

If I misunderstand your question, I'm sorry.

Tanaike
  • 181,128
  • 11
  • 97
  • 165
  • This worked like a charm, thank you! I thought manifest scopes were filled automatically at runtime, but the scopes tab under 'project properties' is always blank. Actually, adding "https://www.googleapis.com/auth/script.external_request" was enough in my case. Btw, did you find it somewhere in the docs? – Anton Dementiev Feb 17 '18 at 14:48
  • @Anton Dementiev Manifests are required to be set by users. By this, the scopes that the oauth2 process was required before got to be able to be easily used. The detail information of Manifests is https://developers.google.com/apps-script/concepts/manifests – Tanaike Feb 17 '18 at 23:13
  • Thanks! I know what manifests are, it's just confusing to me that scopes themselves aren't very well-documented. According to Google, relevant scopes are determined programmatically at runtime. It would have been easier for any scopes to be added to the manifest file after the user has authorized them. Instead, they are confined to 'Project properties' menu and you still need to explicitly include them in the manifest. Also, isn't googleapis.com/auth/script.external_request basically the same scope as the one used for UrlFetchService? If so, I'm confused as to why I need to explicitly add it – Anton Dementiev Feb 18 '18 at 15:18
  • Anyway, too much rambling from me. Thank you very much for your help! – Anton Dementiev Feb 18 '18 at 15:19
  • @Anton Dementiev ``googleapis.com/auth/script.external_request`` and the scope of UrlFetchService are the same. When the scopes are installed in Manifests, the priority of installed scopes is higher than 'Project properties'. When Manifests is not used, the scopes in the project are automatically installed. On the other hand, When Manifests is used, the scopes are required to be manually installed. This might not be written to the document. Is my understanding for your comment correct? – Tanaike Feb 18 '18 at 23:19