I am just starting to try building a new Gmail Add-on, and am running into the following error message:
"You do not have permission to call fetch"
This happens when testing the add-on in the Script Editor, and also when deployed inside my Gmail. Here is a sample of the code:
function getContextualAddOn(e) {
var API_KEY = 'TESTKEY';
var URL = 'https://[REDACTED]';
var options = {
'method' : 'post',
'contentType': 'application/json',
'headers': {
'x-api-key': API_KEY
},
'payload' : JSON.stringify({ 'foo': 'bar' })
};
var response = UrlFetchApp.fetch(URL, options);
[more code that builds a card]
}
As you can see, it's a pretty straightforward use of UrlFetchApp.fetch. I'm brand new to Apps Script, so maybe I am missing some permissions declaration or scope in my manifest. I tried an even simpler example just using UrlFetchApp.getRequest, but that also failed with "You do not have permission to call getRequest".
The manifest for the addon is the same as in the examples:
{
"timeZone": "America/New_York",
"dependencies": {
},
"exceptionLogging": "STACKDRIVER",
"oauthScopes": [
"https://www.googleapis.com/auth/gmail.addons.execute",
"https://www.googleapis.com/auth/gmail.addons.current.message.readonly",
"https://www.googleapis.com/auth/userinfo.email"
],
"urlFetchWhitelist": [
"https://[REDACTED]"
],
"gmail": {
"name": "Test Add-On",
"logoUrl": "some url",
"primaryColor": "#4285F4",
"secondaryColor": "#4285F4",
"contextualTriggers": [{
"unconditional": {},
"onTriggerFunction": "getContextualAddOn"
}],
"version": "TRUSTED_TESTER_V2"
}
}
Is UrlFetchApp supposed to be allowed inside a Gmail Add-On, or is this just a bug? Do I need to add something to my manifest or enable some other option in the script editor?
The UrlFetchApp service requires an additional scope, https://www.googleapis.com/auth/script.external_request. Add it to your list of scopes and the code should work.
The scopes required for each Apps Script method is listed under the "Authorization" section in the reference docs (example). Alternatively, you can discover the scopes required by your script by temporarily removing the oauthScopes section of the manifest and viewing the auto-determined scopes for your code in File > Project properties > Scopes. (If you define any scopes in your manifest, this disables the "automatic scope detection" behavior of Apps Script.)
References
Setting Scopes
Manifest File
All Google Scopes
The accepted answer was from 2017. I don't know if Google has changed its authorization policy since then, but simply adding a new scope to the Project Properties settings won't work.
How do you trigger the function that call fetch?. You can't use simple triggers to do that. They fire automatically, so they can't access services that require authorization. UrlFetchApp definitely requires permission. There is no way to open a dialog to ask for users' content with simple triggers.
You, as the script owner, can add new authorization scope, but what happens when you deploy this script with end users? How are they going to grant their permission to the script to make API calls to some unfamiliar servers?
To get around this, you need to use installable triggers. Whatever are available in simple triggers, there are equivalent in installable triggers.
Let's assume that you want to call the API on opening the spreadsheet.
From the Script Editor, go to Edit >> Current Project's Triggers and set up a new trigger.
Under Run, select the name of the function that you want to trigger. In the OP's case, it's the getContextualAddOn(e) function.
Under Select event source, choose From spreadsheet.
Under Event type, choose On Open.
Configure other settings as you like and save.
Use installable trigger instead and write your own function 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.
Related
I try to publish an Editor Add-on for Google Sheet into the workspace marketplace.
But I'm struck on the review.
With this message :
The App doesn’t meet the publishing review criteria on the following:
Menu - Menu options not shown after App is installed. Please ensure that the add-on correctly uses onInstall() and onOpen() to populate its menu. The menu items populate when the add-on is first installed and when a different file is opened. See Editor add-on authorization.
My app does not have a menu, so I was thinking I must add one, in my index function.
Failed with same message.
So I add an onOpen(e) and onInstall(e) functions like the documentations.
And the review failed too.
So I don't know what to do.
My app is writed in AppScript
Here some code:
function menuItem1() {
SpreadsheetApp.getUi() /
.alert('You can contact me at ...');
}
function onInstall(e) {
onOpen(e);
}
function onOpen(e) {
SpreadsheetApp.getUi().createAddonMenu()
.addItem('Contact', 'menuItem1')
.addToUi();
}
function index(isConnected = false) {
var divider = CardService.newDivider();
.....
And here my appscript.json
{
"timeZone": "Europe/Paris",
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"oauthScopes": [
"https://www.googleapis.com/auth/script.locale",
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/script.external_request"
],
"urlFetchWhitelist": [
"myapi"
],
"addOns": {
"common": {
"homepageTrigger": {
"runFunction": "index",
"enabled": true
},
"logoUrl": "urltomylogo",
"name": "Name of my app",
"useLocaleFromApp": true
},
"sheets": {}
}
}
My app has successfully passed the oAuth verificaton by Google.
And now I'm stuck on the publishing
Help is appreciated,
Thx
Edit - Solution.
Indeed, the addon was on Editor add-on mode, I switched it to Google Workspace Addon and it worked.
Thx
Apparently you have confussed Workspace Add-ons with Editors Add-ons or viceversa. Both might be created using Google Apps Script, the way to publish them is very similar, on the first you will use the deployment ID on the second, instead you will the project version number. Another difference about these add-ons types is that an Editor Add-on can't use the CardService, it's only available for Workspace Add-ons, while Workspaces Add-ons can't use the onOpen simple trigger among other things.
Please review the details about the differences between Workspace Add-ons and Editors Add-ons on https://developers.google.com/apps-script/add-ons/concepts/types, and review carefully the publishing docs:
https://developers.google.com/apps-script/add-ons/how-tos/publish-add-on-overview?hl=en
https://developers.google.com/workspace/marketplace/enable-configure-sdk
Since you are trying to publish an Editor Add on you should check the Authorization model that these type of Add ons need, not having a proper menu for your Add on will most likely be the main reason of it's rejection.
Checking the full lifecycle of these add ons should give you an idea of what you need to implement in your current state:
If an add-on is either installed for the current user or enabled in the current document, the add-on is loaded in the document, which causes it to appear in the Add-ons menu and start listening for the simple triggers onInstall(e), onOpen(e), and onEdit(e). If a user clicks one of the add-on’s menu items, it runs.
Reference:
The complete lifecycle of an Editor Add on
I have multiple Google Apps Scripts deployed as libraries and added into Google Sheets.
The problem starts when I share these sheets with other users.
To even let them see the user menu load, I needed to give them edit access to my library scripts. View only access wasn't enough. Then I got the following error message from them "Exception: Service Admin SDK API has not been enabled for your Apps Script-managed Cloud Platform project"
And I know I'm getting this for using function AdminDirectory.Members.insert(...);
I don't want add API privileges for them in GSuite.
The following oauthScopes are in use:
"oauthScopes": [
"https://www.googleapis.com/auth/drive",
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/documents",
"https://www.googleapis.com/auth/script.send_mail",
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/admin.directory.group.member"
]
What I'm looking for is a solution to create these scripts in a way that I would able to add them to my Google Sheets, where user menu could be loaded from the scripts and called by users. All script code from the library/add-on (eg,: GSuite create new user / add user to group / open, edit docs / open, edit sheets) should be run through my credential, not with theirs. Users shouldn't be able to view/edit the libraries/add-on scripts' code.
The only code they should able to see and edit is the tiny onOpen script in the Sheet's script file. They have to have access to the script library / add-on but only to run it, call functions from it. They shouldn't be able to read and edit the library/add-on script code. Their code in the spreadsheet would be really small. Just an onOpen trigger which would load the menu from the script and give access to the main functions which could be called from the menu. Those would be public functions. The rest is private.
Script from Sheet
Library called "Script"
This is how my script is loading the menu in Sheets and calls the functions through it.
Issue:
If I understand your situation correctly:
You have an editor add-on through which you want to execute functions that access Admin SDK (via a custom menu).
You want users in your domain, which do not have privileges to access Admin SDK, to be able to execute these functions.
You are a domain admin and can access the desired Admin SDK services.
You won't accomplish this by placing your code in a library, since there's no way to "delegate" the execution of a library function: the library function will run under the authority of the user executing the menu function.
Solution:
In that case, I'd suggest the following alternative:
Create a service account.
Follow this guide to grant the service account domain-wide delegation, so that it can be used to impersonate any account in your domain: in this case, your account.
Import and use the library OAuth2 for Apps Script in order to use the service account in your Apps Script project.
Use UrlFetchApp to call your desired API, using the access token from the service account.
Code sample:
For example, if you wanted to call Directory API's users.get to retrieve data from the user currently executing this, you would do something like this:
function getService() {
const service = OAuth2.createService("Service account")
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setPrivateKey(SERVICE_ACCOUNT_PRIVATE_KEY)
.setIssuer(SERVICE_ACCOUNT_EMAIL)
.setSubject(IMPERSONATED_EMAIL)
.setPropertyStore(PropertiesService.getScriptProperties())
.setParam('access_type', 'offline')
.setScope('https://www.googleapis.com/auth/admin.directory.user')
return service;
}
function getActiveUserData() {
const service = getService();
if (service.hasAccess()) {
const userKey = Session.getActiveUser();
const url = `https://admin.googleapis.com/admin/directory/v1/users/${userKey}`;
const options = {
headers: {
'Authorization': "Bearer " + service.getAccessToken(),
'Content-Type': 'application/json'
},
muteHttpExceptions: true
}
const resp = UrlFetchApp.fetch(url, options);
const userData = JSON.parse(resp.getContentText());
return userData;
}
}
I wrote a function that adds an all-day event.
When the function running from script editor it's working fine, the all-day event is inserted to the calendar.
But when I'm running the function in the active spreadsheet =addevent(a1,b1,c1,d1)
I'm getting an error saying :
Exception: The script does not have permission to perform that action. Required permissions: (https://www.googleapis.com/auth/calendar || https://www.googleapis.com/auth/calendar.readonly || https://www.google.com/calendar/feeds) (line 11)
After searching the net I found how to add manually those permission by editing the oauthScopes in the JSON file:
{
"oauthScopes": [
"https://www.googleapis.com/auth/calendar",
"https://www.googleapis.com/auth/calendar.readonly",
"https://www.google.com/calendar/feeds",
"https://www.googleapis.com/auth/spreadsheets.currentonly",
"https://www.googleapis.com/auth/spreadsheets"
],
"timeZone": "censored",
"dependencies": {
"enabledAdvancedServices": [{
"userSymbol": "Calendar",
"serviceId": "calendar",
"version": "v3"
}]
},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8"
}
But I am still getting the same error in the spreadsheet...
Answer:
While it is not possible to run a script which requires authorisation directly from a cell in a Sheet, you can set up the script to run on button click instead.
More Information & Workaround:
As a button does not have the same authorisation restrictions as custom functions, you can use them to run code with the scopes you need. To set this up:
Go to the Insert > Drawing menu item and create a shape; any shape will do, this will act as your button.
Press Save and Close to add this to your sheet.
Move the newly-added drawing to where you would like. In the top-right of the drawing, you will see the vertical ellipsis menu (⋮). Click this, and then click Assign script.
In the new window, type whatever the name of your function is, without parentheses (for example myFunction), and press OK.
References:
Custom Functions in Google Sheets | Apps Script | Google Developers
That is because you are not allowed to use a custom function to perform actions that require authorization such as adding an event to your calendar.
From the official documentation:
Unlike most other types of Apps Scripts, custom functions never ask
users to authorize access to personal data.
However, there are some workarounds that you could try. For example, you can create a custom menu option within your spreadsheet file or a time-driven trigger.
I am sending http request from script editor in google spreadsheets, but I keep getting the following error message:
`Google Apps Script: You do not have permission to call UrlFetchApp.fetch. Required permissions: https://www.googleapis.com/auth/script.external_request`
I am using onEdit function:
function onEdit(e){
var ui = SpreadsheetApp.getUi();
var response = UrlFetchApp.fetch('http://www.eur-api.idomoo.com/');
Logger.log(response.getContentText());
}
I don't know Why am I getting this error? and I also gave permission to script.external_request scope, Any help would be appreciated.
onEdit is invoked by a Simple Trigger when a user changes a value in a spreadsheet.
However, simple triggers cannot access services that require authorization, such as UrlFetchApp.fetch. See the Google Apps Script guide
What you can do is to simply rename the function onEdit to something else, such as atEdit, so as to remove the simple trigger. Then follow the Current project's triggers menu...
and add a trigger to be called in the event of On edit.
And when creating the trigger, you will follow the Wizard to grant your apps script permission to connect to an external service.
There are two ways to solve this
I. Update your manifest and add the line "https://www.googleapis.com/auth/script.external_request" to oauthScopes
{
"timeZone": "Europe/Moscow",
"oauthScopes": [
...
"https://www.googleapis.com/auth/script.external_request"
],
"dependencies": {
...
},
"exceptionLogging": "STACKDRIVER"
}
II. Or remove oauthScopes key from your manifest totally
You can find how to edit the manifest here Manifests
I know its an old thread, but I find it weird of having to rename the method to something else, e.g. from onEdit to onEditHandler just to make it work. It turns out that I can make it work by:
Remove the trigger.
Re-add the trigger.
This is possible probably due to previously the handler doesn't have the fetch url, therefore it doesn't have to ask for authorization to access external request. Once it is re-added, then it has the proper authorization because you are asked to re-authorize the handler.
You'll need to authorize your script to access the external_request service. If you're the owner of the project, you should be able to grant access by running and confirming with the oauth page.
Read more about authentification here: https://developers.google.com/apps-script/guides/services/authorization
I experienced this error after adding the onEdit function without also explicitly adding a trigger. This was resolved by adding an onEdit trigger that calls the function. Triggers -> Add Trigger, On edit event type.
Try changing the link https.
Looking at their api documentation:
API Endpoints
Idomoo’s API 2.0 has several endpoints all starting from one of several roots, depending on the territory in which you want your data sent to and processed:
USA https://usa-api.idomoo.com/api/v2
EU https://eur-api.idomoo.com/api/v2
You should
Remove Current triggers
and then
create new trigger by selecting event "OnEdit"
I'm trying to replace the contents of a Google Sheet with a BigQuery query.
I'm in the Google Sheet and using a script based on these: https://greenido.wordpress.com/2013/12/16/big-query-and-google-spreadsheet-intergration/
Accessing BigQuery with Google Spreadsheet
All the script does is pull the info from a BigQuery query and write it to a Google Sheet. But if I just run the script, I end up getting an error: BigQuery: No OAuth token with Google Drive scope was found
What do I need to do to get this to work?
After a lot of Googling, I found the answer. Apparently, even though I need to give my script the authority to manage not just my Google Sheet, but also the authority to manage my Google Drive.
All I have to do is add a function to make Google ask me for permission for the script to manage my Drive.
Here's the function:
function usingAppsScriptsToken ()}
// we need to provoke a drive dialog
// DriveApp.getFiles()
}
Note that key ingredient is DriveApp.getFiles(), and it still works even though it's commented. When I run the function, I'll get a pop-up window that says "(your script) would like to View and manage the files in your Google Drive". When I allow it, the data import function works.
Source
No need to add anything to your code.
You simply need to add an additional scope to the dependencies part of the appscript.json file:
"dependencies": {
"enabledAdvancedServices": [{
"userSymbol": "BigQuery",
"serviceId": "bigquery",
"version": "v2"
},
{
"userSymbol": "Drive",
"serviceId": "drive",
"version": "v2"
}]
}
In the View menu you could select to Show the manifest file:
Just add
DriveApp.getFiles()
to any function in your project and run it. After your running, you see a window that asks permission to the Drive.
Afterall you can delete this row and everything is will be ok.