I have the same problem as described here: Google Web Apps - Get user email but run scripts as owner
The given solution is to create a client script that runs as the current user and a middleware script that runs as the owner. The client script then calls the middleware script with UrlFetchApp.fetch(...)
and the middleware handles the request in the doGet(e)
function. This works fine in a test environment.
But to have it productive, I need to have the middleware script only accessible by domain users. Than, the UrlFetchApp.fetch
call returns a login dialog.
So, is there a way to call a Google App Script by URL without manual log in?
This is my frontend script that runs with the user's privileges:
function doGet(e) {
var data = HtmlService.createHtmlOutput(backendCall());
// TODO: Format data as HTML
return HtmlService.createHtmlOutput(data);
}
function backendCall() {
const url = `${backendUrl}?user=${encodeURI(Session.getEffectiveUser().getEmail())}`;
const options = {
method: 'GET',
muteHttpExceptions: true,
headers: {
Authorization: `Bearer ${ScriptApp.getOAuthToken()}`,
Accept: 'application/json'
}
};
return UrlFetchApp.fetch(url, options).getContentText();
}
And the backend script that runs with the owner's privileges:
function doGet(e) {
return ContentService.createTextOutput(getUserData(e.parameter.user)).setMimeType(ContentService.MimeType.JSON);
}
function getUserData(user) {
const sheet = SpreadsheetApp.openById(sheetId).getActiveSheet();
const data = sheet.getDataRange().getValues() // Get whole sheet data. This is much faster than getting data row by row.
.filter((row) => row[cols.user] === user) // Select data for selected user.
.map(formatRow) // Format sheet row to JavaScript objects.
.sort((a, b) => a.day - b.day); // Sort by date.
return JSON.stringify(data); // Return as JSON string.
}
The result is, that the backend script returns not the data, but the error message "Error 401 Unauthorized".
UrlFetchApp.fetch()
then the login request is unavoidable because this method uses a scope that requires authorization.ScriptApp.getAuthToken()
in headers AND the project file must be shared with domain too (at least as viewer)