Correct scope for Google App Script Execution API? - google-apps-script

I'm hoping to automate some HR work by running a Google App Script via the Execution API. Without getting too much into the details, I'd like to pass employee evaluation data as a parameter into the App Script. The script will then use this data to compile an "Employee Review" GDoc.
So far, I have ran a simple test App Script using the Execution API. For example, I can successfully run a simple function which logs a string or interacts with spreadsheets. So far so good.
But I run into problems when trying to write to a GDoc (which is unfortunately integral to my task). Here's my paired down script:
// TODO: Eventually, we'll pass these variables as arguments
var docId = "MY-DOC-ID";
// Find the team member review doc
var doc = DocumentApp.openById(docId);
// Replace placeholder text
var docBody = doc.getActiveSection();
docBody.replaceText('{{DATE}}', "Date set by App Script!!!");
doc.saveAndClose();
This script works when I press the "Run" button in the App Scripts web UI. But when I try to run via the Execution API, I get:
{
"error": "unauthorized_client",
"error_description": "Unauthorized client or scope in request."
}
So apparently I haven't provided the correct scope? Following the docs, I can find the necessary scope(s) in Project Properties > Scopes which says:
But when I try adding that scope, it wont work. As I said other scopes (e.g. https://www.googleapis.com/auth/spreadsheets) work just fine. Perhaps the auth/documents scope is no longer supported or there's a bug in their API?
Questions
What is the correct scope? I can see a big list here but I don't see https://www.googleapis.com/auth/documents, so?
Any other suggestions? For example, is it possible to write to a Google Doc using the Google Client API directly (i.e. without using App Scripts)?

Doh. I figured out the solution to my problem. While it was a dumb mistake, it's nevertheless worth posting as it may save others confusion in the future.
First, a little context about my setup. I'm authenticating to the Google Client API using a Service Account. Furthermore, as is common when using a service account setup, I am impersonating a user within our organization (specifically my own account).
My missing step (obvious in hindsight)...
Log into the App Script web UI as the person you are impersonating.
Manually run the script by pressing the play button
If the impersonated user has not already granted permissions to access the required scopes, you will be prompted to do so.
After granting access (specifically for the https://www.googleapis.com/auth/documents scope), my authorization error disappeared.
So the lesson: Make sure the account you are impersonating has granted access for all the scopes which your script requires.

Related

OAuth Bug in Apps Script using YouTube Data API

I have used Apps Script successfully on many occasions, and one of the reasons I like it, especially for personal enhancements or projects related to Google Services is just how seamlessly it integrates auth. However, when trying to integrate the YouTube Data API into one of my Google Sheets' Apps Scripts (I am trying to use the sheet to manage a YouTube playlist), I encountered an error that I have never encountered before.
The code is very simple, I am just trying to get some data from a playlist to return to the logger in the context of my Google Sheets Apps Script. Note that this Apps Script belongs to the same account as the YouTube playlist. The OAuth Client Verification docs specifically state:
Note: Verification is not required for Apps Script projects whose
owner and users belong to the same Google Workspace domain or
customer.
However, when I run my script, the OAuth screen says the app is unverified (this has never happened when I have used any other APIs accessing my own account in Apps Script), and even though I authenticate and it says "Authentication Successful", the script is blocked and it repeatedly (as in forever, in an endless loop) asks me to authenticate again.
Completely at a loss for what is going on. 1.) I shouldn't have to verify this script per the docs I referenced above, and I have never had to before for accessing my own content. 2.) The successful authentication but then failing and repeatedly asking me to authenticate again is driving me mad.
Please advise!
Code is very simple, just trying to get this to return ANYTHING:
const syncVideos = () => {
let response = YouTube.PlaylistItems.list('snippet,contentDetails', {'playlistId': '<REDACTED>'});
Logger.log(response);
}
Answer: This turned out to not be a code or OAuth issue really, but more of an unintuitive procedure when authenticating, i.e. when authenticating with Google to access one of your channel's data through the YouTube Data API, authenticate with your main channel, even if requesting data from other channels connected to your account.

form.setRequireLogin() giving error Script error message: Exception: This operation is not supported

Quite new in the apps script world. Trying to create "google form generator" with dynamically created questions/attachment.
All worked well until I noticed that whenever I create the form, users have to "sign in by google account". This was not requested so I found setRequreLogin().
Whatever I set (false or true) I receive the error: "Script error message: Exception: This operation is not supported"
I did some googleing around and it seems the solution is to have the "google suite gmail account".
I use my personal #gmail.com email.
Do anybody have got the same error?
Or is there anybody who is not having the same error using the "regular" gmail?
How I do it (because it might be a bit different than default):
I use python to execute function that is created in appscript
The apps script had to be linked to "standard GCP project" otherwise I would not be able to execute from python (external API call)
I publish the apps script "deploy as API executable" so I can execute (and pass couple of parameters) the script from Python
Thanks for help
function createForm(ordernumber,surname, country, data_list) {
var form = FormApp.create(ordernumber);
form.setTitle(ordernumber +" | " + surname)
.setDescription('anything')
.setConfirmationMessage('you are welcome...');
// .setAllowResponseEdits(true)
// .setLimitOneResponsePerUser(true)
// .requiresLogin(false);
.setRequireLogin(true);
// .setAcceptingResponses(true);
}
According to the setRequireLogin() documentation:
setRequireLogin() - Sets whether the form requires respondents to log in to an account in the same domain or a subdomain before responding. The default for new forms is false unless a domain administrator changes the default.
This feature is available only for forms created by Google Workspace users. Users of other types of Google accounts can't be required to log in.
Therefore, if you posses a gmail account, you cannot use this method.
However, since your script is creating a new form, the users who use this API executable will have to authorize this operation, hence the login screen they are receiving.
Reference
Apps Script Form Class.

Getting all viewers of spreadsheet using App Script

i wrote code for getting all viewers of spreadsheet in app script .
i have used getViewers() method to get viewers names who actually viewed it. but that method is returning me the names of people to whom i actually shared the spreadsheet....
is there any other way that i can get all viewers of spreadsheet.?
is there any web automation tools that can solve my problem?
Answer:
It is not possible to get a list of people that have opened your a Google Drive file using Google Apps Script - a method that returns this list does not exist. The getViewers() method returns the list of people with view and comment permissions for a file, while getEditors() retrieves the list of people that have edit permissions.
The Issue:
is there any other way that i can get all viewers of spreadsheet.? is there any web automation tools that can solve my problem?
There is no way of getting viewers of a Google Sheet as this is a huge security issue. This information is not stored and is therefore not retrievable.
Workaround:
You can make a custom function which stores the username of a person when they open the file - though be aware that triggers have restrictions and will only run if the person opening the file has edit access. I have included a list of Apps Script Trigger Restrictions below for you to look through and decide what is the best approach for you.
Code:
function onOpen(e) {
var user = e.user.getEmail();
// do some code to store or save this parameter
// for example save it to a hidden sheet or email it to yourself
// though an email would require an installable trigger to be made
}
Simple Trigger Restrictions:
These are not all of the restrictions (full restrictions are available here), but these are the ones that I believe to be most relevant for you.
As per the Google Apps Script Simple Triggers documentation:
They do not run if a file is opened in read-only (view or comment) mode.
They cannot access services that require authorization. For example, a simple trigger cannot send an email because the Gmail service requires authorization, but a simple trigger can translate a phrase with the Language service, which is anonymous.
They can modify the file they are bound to, but cannot access other files because that would require authorization.
They may or may not be able to determine the identity of the current user, depending on a complex set of security restrictions.
This last point is important - getting information about the current user is possible depending on the security policies of the the G Suite domain. A detailed explanation of this can be found in the getActiveUser() method documentation:
If security policies do not allow access to the user's identity, User.getEmail() returns a blank string. The circumstances in which the email address is available vary: for example, the user's email address is not available in any context that allows a script to run without that user's authorization, like a simple onOpen(e) or onEdit(e) trigger, a custom function in Google Sheets, or a web app deployed to "execute as me" (that is, authorized by the developer instead of the user). However, these restrictions generally do not apply if the developer runs the script themselves or belongs to the same G Suite domain as the user.
There are big security issues with getting a list of people that have viewed a file, for good reason, and so what you are looking to do it highly restricted by Google.
References:
Class File of Google Apps Script
getViewers() method of Class File
getEditors() method of Class File
Simple Triggers
onOpen(e) Trigger
Simple Trigger Restrictions
Installable Triggers
Event objects
Class User of Apps Script
User.getEmail() method
Class Session
getActiveUser() method of Session Class

Google App Scripts cannot be given Authorization or Permission

Why am I not able to give permission/authorization to a Google Apps Script that I also made using the same Google account?
It seems like Google doesnt trust myself to use my own Google Apps Script with my own Spreadsheet.
Here is the line of code that breaks everything. If this line doesnt exist, I'm not asked for permission.
var sheet = SpreadsheetApp.getActiveSheet();
So it's trying to access the spreadsheet that created this Google Apps Script, also made using my account but I cant grant permission.
When I run the line of code above, I am told I need to give permissions, so I do by selecting the account name I am already logged into. I am greeted by this error,
This app isn't verified
which unfortunately does not provide competent documentation to troubleshoot.
Any feedback or help would be much appreciated! Thanks!
Click on the "Advanced" link and you'll be able to authorize your script.
To reduce the scope of permissions you request, you also have the option of declaring your script project to be only able to interact with the bound document:
/* #OnlyCurrentDoc */
function myFunction() {
...
This declaration is incompatible with some methods (such as SpreadsheetApp.openById()), and using an incompatible method results in an error in the application execution.
Successfully adding it to your project is generally sufficient to remove the "This application is unsafe" layer of the authentication flow, meaning the authorization and permission list is not hidden behind the "Advanced" tab.
In addition to declaring as current document only, manually editing the requested scopes of your project in its project manifest can help reduce the perceived threat from an unverified application (for example, retaining only the "read_only" version of certain scopes, where applicable). Apps Script documentation offers more details on project manifests.

Set email signature using Google Apps Script with Gmail API

I'm trying to set the Gmail signature of the user executing the script (Execute the app as: "User accessing the web app"; Who has access to the app: "Anyone within my domain") using the following function:
function setSignature(signature) {
var newSig = Gmail.newSendAs();
newSig.signature = signature;
Gmail.Users.Settings.SendAs.patch(newSig, "me", Session.getActiveUser().getEmail());
}
where signature is some html. This function is called from a client-side script when a form is submitted:
google.script.run.withSuccessHandler(signatureSuccess).setSignature($("#signatureParent").html());
The user is served a web app using the HtmlService containing the form. The Gmail API has been enabled in both the Advanced Google Services window as well as the Google API Console.
My issue is that when the I try and execute the function I receive the following console error message:
The message states that the auth scope gmail.settings.basic is missing. This is despite the user authorizing the web app before any html is served:
How do I fix or work around this issue?? The strange thing is I've had this working previously so I don't know what I'm doing wrong.
EDIT:
I've noticed that if I create a simple Apps Script with just the function:
function testSet() {
var testSig = "signature";
var newSig = Gmail.newSendAs();
newSig.signature = testSig;
Gmail.Users.Settings.SendAs.patch(newSig, "me", Session.getActiveUser().getEmail());
}
And leave out everything else I get presented with these permissions to authorize:
If I click Allow it works! So clearly "Manage your basic mail settings" a.k.a. auth scope gmail.settings.basic is required and isn't being asked for in the more involved script.
So how do I force that permission to be acquired or how do I rewrite my script to get the correct set of permissions needed?
After extensive testing I've determined that this issue is a bug in Google Apps Script in determining what scopes are required.
A basic version of my script requires these scopes (File > Project Properties > Scopes):
Extending the script to interact with Google Drive modifies the scopes to this:
By dropping the required gmail.settings.basic scope a critical function within the script is denied permission to run. Infuriating.
I was also facing the same issue on nodejs application, the solution is to generate referesh token using this required scope which is mentioned in the rest api documentation find below.
rest apis documentation
you can create refresh token using required scopes on this link if you're logged in developer account.
https://developers.google.com/oauthplayground: