client (imitating google sheets add-on) :
function getReqParam(type){
//DriveApp.getFiles() - commented row needed for the Drive scope request
let data = { param2: "value2" ,param1: Session.getActiveUser()};
var params = {
method: type,
contentType: "application/json",
headers: { Authorization: "Bearer " + ScriptApp.getOAuthToken() },
payload: JSON.stringify(data),
muteHttpExceptions: true,
};
return params;
}
function sendPostReq(){
let res = UrlFetchApp.fetch(url, getReqParam("POST"));
console.log("sendPostReq response: ", res.getResponseCode());
console.log("sendPostReq response: ", res.getContentText());
}
webapp:
function doPost(e){
console.log("doPost",e);
try{
saveRegToDB(JSON.parse(e.postData.contents));
e.method = "POST";
//return regisration status
e.regStatus = {status: "active"};
}catch(err){
e.regStatus = {status: "error"};
e.err = JSON.stringify(err);
e.errMSg = JSON.stringify(err.message);
console.error("doPost exception",err);
console.error("doPost exception",err.stack);
}
return ContentService.createTextOutput(JSON.stringify(e))
.setMimeType(ContentService.MimeType.JSON);
}
function saveRegToDB({param1,param2}={}){
let rowID = -1;
if (param1 && param2){
let ss = getSS();
let sheetName = "Registrations";
let s = ss.getSheetByName(sheetName);
let r = s.getLastRow() + 1;
rowID = r;
let rVals = [param1,param2,getTimeStamp()];
let vals = [rVals]; //2 dimensions array
console.log("reg saveToDB ",vals,r);
//write to sheet
s.getRange(r,1,1,rVals.length).setValues(vals);
}
console.log("saveRegToDB:" ,rowID);
return rowID;
}
function getSS(){
let ssid = getSSid();
let ss = SpreadsheetApp.openById(ssid);
SpreadsheetApp.setActiveSpreadsheet(ss);
return ss;
}
function getSSid(){
return PropertiesService.getScriptProperties()
.getProperty("regSSID");
}
function getTimeStamp() {
return Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyy-MM-dd HH:mm:ss");
}
I have a simple google web app. The web app is supposed to serve a google sheets addon, to store add-on related information to a private SS (owned by the add-on account), for example: users' registrations. I am wondering about the Who has access setting I should use in order to deploy the the web app, and the usage of access token that comes with it as explained here.
The Execute as (legacy editor: Execute the app as
to Me
- When deploying webapp with Who has access:
Anyone with Google account (Anyone in legacy editor)
web app should be called with access token
headers: { Authorization: "Bearer " + ScriptApp.getOAuthToken() }
There are 2 problems with that approach:
- here it is claimed that webapp script project should be shared with all the users that might use it. In my case every user that will install the addon, that is: everyone. This is a disatvantage for itself. Despite that, another user (say,
user2
) can access successfully the web app. - In order the use access token the client has to request for Drive scopes, even though web app doesn't use any of the Drive API. More over, even of calling the web app with access code, it fails to access the user drive files, due to missing permissions
Exception: You do not have permission to access the requested document.
So not only, client is enforced to ask for Drive scope web app does not need, even if trying to "use" Drive API to access client drive - it is blocked.
I have tested it by setting the regSSID
script property read in getSSid()
to spreadsheet owned by the user2
, and also executing client from user2
account script editor
What is the benefit of deploying web app with Anyone with Google account (Anyone in legacy editor)
and using access token for that?
- When deploying webapp with Who has access:
Anyone
(Anyone, even anonymous
in legacy editor) no access token is required, thus no need to ask for Drive scope. This is good thing. The question is what might the disadvantages of deploying the web app toAnyone
, especially in terms of security. I guess web app can filtered out all calls from unwanted access by validating applicative post request parameter. Is this a real security issue?