Problem: When I run the script, Google tells me,
You do not have permission to call openById
I had copied a script from another one of my Google spreadsheets and changed the target_ssKey variable's cell reference and created properly-sized Named Ranges in both the Source and Target spreadsheets.
Google Apps Script documentation says nothing about reasons why it might not be working:
https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#openById%28String%29
Another Google Apps Script documentation says that it should work for me because I invoke it from a custom menu:
https://developers.google.com/apps-script/guides/sheets/functions#using_apps_script_services
The second link above says:
If your custom function throws the error message You do not have
permission to call X service., the service requires user authorization
and thus cannot be used in a custom function.
To use a service other than those listed above, create a custom menu
that runs an Apps Script function instead of writing a custom
function. A function that is triggered from a menu will ask the user
for authorization if necessary and can consequently use all Apps
Script services.
I tried putting the function into a "Custom Functions" project and then into an "Add-on" project, but still got the same error message.
Any ideas on what I am doing wrong and how to make this work?
Here is my exact code:
function exportData_SStoSS() {
// Get the source data.
var source_ss = SpreadsheetApp.getActiveSpreadsheet();
var data = source_ss.getRangeByName("exportData").getValues();
// Identify the target.
var controls_sh = source_ss.getSheetByName("Controls");
var target_ssKey = controls_sh.getRange('C2').getValue();
var target_ss = SpreadsheetApp.openById(target_ssKey);
// Paste the data to the target.
target_ss.getRangeByName("importData").setValues(data);
};
I thought that I would throw in a similar issue that I had which brought me to this question, where I received the error You don't have permission to call by openById.
In my case I was trying to call functions from translate.gs which I copied from this example:
https://developers.google.com/apps-script/quickstart/docs
Note that at the top of translate.gs
/**
* #OnlyCurrentDoc
*
* The above comment directs Apps Script to limit the scope of file
* access for this add-on. It specifies that this add-on will only
* attempt to read or modify the files in which the add-on is used,
* and not all of the user's files. The authorization request message
* presented to users will reflect this limited scope.
*/
The culprit here is the #OnlyCurrentDoc comment. See here for reference:
https://developers.google.com/apps-script/guides/services/authorization
Removing #OnlyCurrentDoc fixed this issue for me
I could resolved this issue with this autorization guide of google developers.
https://developers.google.com/apps-script/concepts/scopes#setting_explicit_scopes
This entry It's necesary in json file.
"oauthScopes": [
"https://www.googleapis.com/auth/spreadsheets.readonly",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/spreadsheets"
],
I found this official note which I believe clears up what caused the issue.
If your function is a custom function, that is one which can be used like a regular spreadsheet function in the sheet itself, then it has limited access to things and cannot open other spreadsheets.
The same script can however open other spreadsheets from a menu button or similar.
Link: Documentation at developers.google.com
The method openById can be called from a "Blank Project" but not a "Custom Functions in Sheets" nor a "Google Sheets Add-on" project.
I thought a "Blank Project" would create a project that was not connected to my spreadsheet, but I was wrong. The Blank Project is connected to my spreadsheet. The other types of projects that I tried to use seem to be limited-scope versions of script projects, not able to carry out some GAS methods.
Had this same issue and came to share my solution. In my case I had two spreadsheets, call them A and B. Both used scripts bound to each respective spreadsheet. Spreadsheet B was able to write data to a tab of spreadsheet A. But Spreadsheet A kept getting the "You do not have permission to call openById" error when trying to read from spreadsheet B. I then tried adding it as a custom menu item but still the same issue.
The solution in my case turned out to be really simple. I created a new unbound script in script.google.com that calls both spreadsheets using openById. The first time running put a smile on my face as it asked for authorization. Thereafter smooth sailing.
Related
I'm new to GAS and I struggle with the permission system.
I'm a normal Google drive user and I started a spreadsheet and tried to add some code to it. My code is working, but only if I'm in the code editor. I want to use the onEdit() function so it's important for me that it works within the sheet as well. When I ran my code in the editor for the first time it opened a new window where I needed to enter my credentials to allow the script, then it worked. If I do some changes to a cell in my sheet and the onEdit() function is triggered I receive an error message that says something like this(translated):
Exception: You are not permitted to call UrlFetchApp.fetch. Required permission: https://www.googleapis.com/auth/script.external_request
In the editor I displayed the manifest file and added the permission to the oauthScopes but within the sheet I still receive the message. This is how my code looks like (simplified):
function onEdit(e)
{
var data = {
'key1': 'value1',
'key2': 'value2'
};
var options = {
'method' : 'post',
'contentType': 'application/json',
'payload' : JSON.stringify(data)
};
try{
var response = UrlFetchApp.fetch('https://a-working-url.com', options); //error happening in this line
//some more data wizardry
}catch(error)
{
Browser.msgBox(error)
}
}
Any ideas how I can open this permission screen in my sheet or any hints how to solve it in a different way? I want to create a sheet with some code running in the back online. I want to share the sheet with some friends, tried it with Excel and VBA before until I realized that it's not working with Excel Online, so I switched to GAS.
onEdit(), like all simple triggers, is bound by the following restrictions (see official documentation):
The script must be bound to a Google Sheets, Slides, Docs, or Forms file, or else be an add-on that extends one of those
applications.
They do not run if a file is opened in read-only (view or comment) mode.
Script executions and API requests do not cause triggers to run. For example, calling Range.setValue() to edit a cell does not cause
the spreadsheet's onEdit trigger to run.
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.
They cannot run for longer than 30 seconds.
In certain circumstances, editor add-ons run their onOpen(e) and onEdit(e) simple triggers in a no-authorization mode that presents some additional complications. For more information, see the guide
to the add-on authorization lifecycle.
Simple triggers are subject to Apps Script trigger quota limits.
The ones highlighted in bold apply to your question.
Basically, it boils down to this - UrlFetchApp.fetch() is a service that requires authorization, so you won't be able to execute it from your onEdit(e) trigger, even if you have its associated scope set in your manifest file.
Use installable trigger instead and write your own "onEdit" function (with a different name) that you bind to your installable trigger.
https://developers.google.com/apps-script/guides/triggers/installable#g_suite_application_triggers
This solved the issue for me.
Iv'e written a custom google sheet function using Google Apps Script, and i would like to share it with another spreadsheet user, but i do not want to share the functions source code.
I've converted the Google Apps Script to a project, but now i have no idea how to link the project back to my sheet, so the function will work again.
I also do not want to publish the AddIn to the marketplace.
Test As Addin also doesn't work, the sheet is opened in a new tab, but the cells with the custom function says #NAME?.
What am i missing?
Explanation / issues:
The error #NAME? indicates that you are trying to use a function
that does not exist. As you also mentioned, this function does not
belong to the active spreadsheet but on a different project.
Unfortunately, it is not possible to share a custom function with other spreadsheets directly.
Possible Workarounds:
You can create an add-on.
Another workaround solution would be to create a library. That is a great alternative and the documentation is quite straightforward.
Related:
Creating add ons in Google Apps Script
How to call library function as custom function from spreadsheet formula?
I am building an Google Apps Script add-on for Google Spreadsheets.
In the manifest I have explicitly requested the following scopes:
"https://www.googleapis.com/auth/script.container.ui",
"https://www.googleapis.com/auth/spreadsheets"
Also the "OAuth consent screen" within my Google Cloud project has the same scopes and these are already verified by Google.
Nevertheless it is not possible for me to give feedback to my users in case of a wrong input. I have tried the following:
SpreadsheetApp.getActiveSpreadsheet().show(htmlApp);
SpreadsheetApp.getActiveSpreadsheet().toast(message);
SpreadsheetApp.getUi().alert('Wrong input.');
SpreadsheetApp.getUi().showSidebar(html);
Browser.msgBox('Wrong input.');
Nothings seems to work, I always see the error "Authorisation is required to perform that action" within the stackdriver logs.
What would work is to create an "error sheet" and log all input errors into it, or to make one cell within the main sheet to an "error cell" and log all input errors into it. I think this is not a good solution in terms of user experience.
It seems that this problem has something to do with the authMode: https://developers.google.com/gsuite/add-ons/concepts/editor-auth-lifecycle#authorization_modes
Because "Access to user interface" is only possible within "FULL" authMode, which is not the case during onEdit().
The strange thing is, that other add-ons are able to show an alert/popup. Is this a hack? Or do I need more scopes? Or do I have to change anything else?
EDIT 08.10.2019:
#Jacques-Guzel Heron:
For instance: the user inputs a date in cell A1 and another in cell B1. Within the onEdit(e) trigger I want to check if the date in B1 is after the date in A1, if not I want to alert the user. All the above listed methods lead to the error "Authorisation is required to perform that action", when the app is published. When the app is not published .toast(), .alert() and .msgBox() work within my test environment. The strange thing is, that these methods then create a DIV-element, whereas the other add-ons create an IFRAME-element for their alert/dialog-box. Therefore I think they use another method and it has nothing to do with scopes. In addiation I had a look during the OAuth verification process of these add-ons and the scopes are listed within the dev-tools. They do not use any special "ui-scope", so I doubt the cause for this error is scope related.
EDIT 09.10.2019:
Now I know how an alert/dialog-box containing of an IFRAME-element can be made. To do this, these methods can be used:
var htmlString, msg, htmlOutput;
htmlString = '<p>my html string</p>';
msg = 'my message';
htmlOutput = HtmlService
.createHtmlOutput(htmlString)
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setHeight(140);
SpreadsheetApp
.getUi()
.showModalDialog(htmlOutput, msg);
But it is also not possible to call this method during onEdit(e).
All the above listed methods can be called, through clicking on the menu items and also through clicking on buttons within the sidebar, but not during onEdit(e).
In addition I have added all the scopes which other add-ons are using, but in vain. So again my assumption got confirmed that the problem is not scope related.
I have the impression that some smart people have managed to find an inofficial workaroung, please let me know :)
You are right on all your approach. And yes, this is intended behavior as documented on authorization modes.
Those add-ons use custom menus to use a formula that checks the cell after being called pressing a button.
On that documentation you can find information to develop your alert. Please describe what you are trying to accomplish so I can help you better, otherwise ask me for more clarification without hesitating.
The solution are installable triggers: https://developers.google.com/apps-script/guides/triggers/installable
They are running in FULL authMode and therefore are allowed to access the user interface: https://developers.google.com/gsuite/add-ons/concepts/editor-auth-lifecycle#authorization_modes
I am trying to automate a google spreadsheet on google script editor. However, when I try to identify the spreadsheet and select as the one that we are working on, it is written in the documentation cited below (openById) that scripts that use this method require authorization with one or more of the following scopes:
--> https://www.googleapis.com/auth/spreadsheets.currentonly
--> https://www.googleapis.com/auth/spreadsheets
When I add these scopes, my function doesn't run. It only runs when those scopes are not added. Either way, I am met with the error msg that reads: "We are sorry, a server error occurred. Please wait a bit and try again."
https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#openbyidid
I tried various methods include OpenByUrl and getActiveSpreadsheet...
function automatedInvoiceEmailing() {
var people = [];
// selecting the spreadsheet (without the bottom line, the function works just fine)
var ss = SpreadsheetApp.openById("1jdn3S1Iv2zDAqF6Hyy3fybKARZJYmg-LJVdUWJJS3LA");
}
Either way, I am met with the error msg that reads: "We are sorry, a server error occurred. Please wait a bit and try again."
I expected the sheet to have been selected
Edit: hmm, when I copied the google sheets and saved the new code, it runs properly!! :)
Since you are working with a bounded script (bound to the sheet you’re working with), the way to get a reference to the sheet is with var ss = SpreadsheetApp.getActiveSheet();, this will provide a reference to the bound document. You would use openById() to access another file.
As for scopes, they are added automatically when you run the script for the first time, it will ask for your permission to access your data, and when you accept, google adds them to the script project automatically.
Here are some quick-start examples on working with sheets and apps script
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.