Using custom libraries from apps script in App Maker: Authorization problem - google-apps-script

I am using this code in Apps script
function getUserObjByEmail(email){
// Same as using AdminDirectory class.
var apiUrl = "https://www.googleapis.com/admin/directory/v1/users/"+email+"?fields=id";
var token = ScriptApp.getOAuthToken();
var header = {"Authorization":"Bearer " + token};
var options = {
"method": "GET",
"headers": header
};
var response = JSON.parse(UrlFetchApp.fetch(apiUrl, options));
return response;
}
which I run as a function from App Maker project. Things go smoothly when I use the app since I have an admin role( I guess, not sure ) but the problem arises when other normal users in our domain start using the deployed app maker app. I checked the server logs and its full of this message:
Exception: Request failed for
https://www.googleapis.com/admin/directory/v1/users/email#domain.com?fields=id
returned code 403.
Truncated server response: { "error": { "errors": [ { "domain": "global",
"reason": "forbidden", "message": "Not Authorized to access this
resource/api" ... (use muteHttpExceptions option to examine full response)
Any idea how to fix this? I have manually added the required scopes for the apps script library, I added the following:
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/admin.directory.user"

The reason this happens is because YOU have admin rights, otherwise you'd be getting the same error message. The other users don't have admin rights hence they get the error. To solve this problem, you can either deploy the application running it as the developer or you can use a service account to impersonate an admin and do the process.
Regarding the first approach, you can find more info here https://developers.google.com/appmaker/security/identity.
Regarding the second approach, you can use the following app script library https://github.com/gsuitedevs/apps-script-oauth2#using-service-accounts
Moreover, if you do not require to get custom schemas information, then you can simply use a directory model and that should work for all users. Check the reference here: https://developers.google.com/appmaker/models/directory

Related

HTTP Request to Discord API Through Google Apps Script Results in 403 Error With Response "Error Code 1020"

I'm having trouble getting guild channels with this code in Google Apps Script.
var token = "MY_TOKEN"
var url = "https://discord.com/api/v10/guilds/[GUILD_ID]/channels"
var header = {
Authorization: "Bot " + token
}
function myFunction(){
var params = {
method: "get",
headers: header,
muteHttpExceptions: false
}
var response = UrlFetchApp.fetch(url,params)
Logger.log(response.getContentText())
}
Running myFunction() results in this error message:
Exception: Request failed for https://discord.com returned code 403. Truncated server response: error code: 1020 (use muteHttpExceptions option to examine full response)
or just this if the muteHttpExceptions value is true:
error code: 1020
Some information that may be useful to diagnose my problem:
My bot is in my server, but it's shown to be offline in the member list (does it matter?)
My bot is a private bot
I have made sure that the bot token and guild ID are correct
I invited the bot to my server via a generated link in OAuth2 URL generator in Discord Developer Portal. I checked the bot scope only with administrator permission. (Additional info: The first time I tried generating URL, it didn't need a redirect URL. But for some reason, it requires me to select one from a dropdown list now, but when I click on the dropdown, the list is empty as shown in the screenshot, so I can't select one and can't generate URL from there anymore.)
Get Current User Guild (/users/#me/guilds) runs perfectly fine. It returns this array:
[
{
"id": "[GUILD_ID]",
"name": "[GUILD_NAME]",
"icon": null,
"owner": false,
"permissions": "4398046511103",
"features": [
"APPLICATION_COMMAND_PERMISSIONS_V2"
]
}
]
I think my problem has something to do with the bot permissions, but I'm just lost.

Google Chat API: Delete message from bot gives a 401 error

This is the code i'm trying to use for deleting messages posted through a webhook to a chat room (I grab messageID when I create It with this same request but POST method and sending message in a text variable):
var WEBHOOK_URL2 = "https://chat.googleapis.com/v1/spaces/<SPACE>/messages/<MESSAGEID>.<MESSAGEID>?key=<KEY>&token=<TOKEN>%3D";
var options = {
'method' : 'delete',
'muteHttpExceptions' : true,
};
var response = UrlFetchApp.fetch(WEBHOOK_URL2, options);
Logger.log (response);
The response is
"error": {
"code": 401,
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED"
}
As commented, creating messages works with those credentials (key / token from chatroom webhook) Maybe i am missing something from the documentation at https://developers.google.com/hangouts/chat/reference/rest/v1/spaces.messages/delete ?
Thank you in advance,
That error usually occurs because the request lacks the access token or that access token wasn't validated. I assume that you are using Apps Script for this task. If my assumption is true, you'll find this reference useful; it summarizes the OAuth 2.0 protocol for Google APIs using JavaScript. For obtaining access tokens, please refer to this other guide for a complete step-by-step. Please, follow those steps on your request routine and don't hesitate to write back if you need more help.

How can I trigger a Google Apps Script function from the Google API PHP Client with the authentication I have set already?

I'm struggling to trigger a Google Apps Script Function which builds many dropdowns of a Google Spreadsheet.
I need this data to be updated daily on this Google Spreadsheet so I must call the function.
Seems like I'm required to have a client-side authentication which I'm reluctant to force it to happen.
I have set already the Google API PHP Client which does batch updates, get requests and control users and its roles.
Here's how the code looks like:
public function updateTemplate ()
{
$client = $this->getClient();
$service = new Google_Service_Script($client);
$scriptId = $this->gScriptId;
// Create an execution request object.
$request = new Google_Service_Script_ExecutionRequest();
$request->setFunction('SetUpNewSpreadsheet');
try {
// Make the API request.
$response = $service->scripts->run($scriptId, $request);
echo "here<pre>";
print_r($response);
exit;
I'm getting the following response error:
Caught exception: {
"error": {
"code": 401,
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"errors": [ {
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"domain": "global",
"reason": "unauthorized"
} ]
, "status": "UNAUTHENTICATED"
}
}
I've checked the message errors and docs already. I'm wondering if maybe I'm missing something or if I can find a way to execute that request without forcing a client-side login?
Has anyone been through it?

"Insufficient Permission" when trying to authenticate to cloud-storage via apps-script

I am about to give up on this as I can't find out what I am doing wrong.
I have a cloud-storage bucket with our companies billing data (json file objects written by google) that I am supposed to process into spreadsheets.
As there is no apps script API for oauth2, I am using the custom OAuth2 library provided by google with the key "1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF", and have setup the auth request as shown in this example for service accounts:https://github.com/googlesamples/apps-script-oauth2/blob/master/samples/GoogleServiceAccount.gs
The token is being created and put into the scripts property store, where I can view it. So far so good.
I have this code for requesting the token and then I am trying to list the contents of the bucket in the function "getFilesList()":
function getService() {
return OAuth2.createService('CloudStoreGrab-Service')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setPrivateKey(creds_private_key)
.setIssuer(creds_client_email)
.setSubject(creds_user_email)
.setPropertyStore(PropertiesService.getScriptProperties())
.setScope(['https://www.googleapis.com/auth/drive','https://www.googleapis.com/auth/script.external_request','https://www.googleapis.com/auth/script.storage','https://www.googleapis.com/auth/spreadsheets']);
}
function getFilesList() {
var service = getService();
service.reset();
if (service.hasAccess()) {
var url = 'https://www.googleapis.com/storage/v1/b/'+bucket+'/o';
var response = UrlFetchApp.fetch(url, {
method: "GET",
muteHttpExceptions: true,
headers: {
Authorization: 'Bearer ' + service.getAccessToken()
}
});
}
Logger.log("Response:", response.getContentText())
}
No matter what I seem to try, the request always returns "403 Insufficient Permission". The service account has all necessary roles and permissions activated though (DwD, Storage-Administrator, Project-Owner). When I authenticate with the same credentials from gcloud and then browse the bucket with gsutils I can see the listing. This leads me to believe, that I am still requesting the auth token incorrectly. I tried using the generated token with curl and am getting the same Insufficient Permission response.
What am I doing wrong, while requesting the token?
Are the requested scopes too narrow?
Are the requested scopes too narrow?
That they are. You can find the OAuth scopes for Google's Cloud Storage API listed below (you won't need to use all of them, pick the ones best suited to your use-case, the 1st and 5th scopes in the list should be sufficient):
https://www.googleapis.com/auth/cloud-platform
https://www.googleapis.com/auth/cloud-platform.read-only
https://www.googleapis.com/auth/devstorage.full_control
https://www.googleapis.com/auth/devstorage.read_only
https://www.googleapis.com/auth/devstorage.read_write
In future, you can find the required OAuth scopes for any Google API you need at the following link:
https://developers.google.com/identity/protocols/googlescopes

How to turn on email forwarding with Google Script

A brief description of the project: I am looking to toggle the email forwarding option in the settings of one of my gmail accounts through a google script. This will be a function I would like to call every night between certain hours forwarding my mail from main_email#gmail to secondary_email#gmail.
I am having a difficult time finding the easiest way to toggle this through a google script. The simplest solution seems to be described here where they use an HTTP request. However in all honesty I don't completely understand how it all works, much less if it is the simplest way.
https://developers.google.com/gmail/api/v1/reference/users/settings/updateAutoForwarding
The code that I try and run on the gmail account to enable/disable email forwarding is the following:
function updateForwarding() {
var userID = "main_email#gmail.com"
var response = UrlFetchApp.fetch("https://www.googleapis.com/gmail/v1/users/" + userID + "/settings/autoForwarding", {
method: 'put',
enabled: true,
emailAddress: "secondary_email#gmail.com",
disposition: "leaveInInbox"
});
Logger.log(response.getContentText());
}
However I get the following error:
Request failed for
https://www.googleapis.com/gmail/v1/users/main_email#gmail.com/settings/autoForwarding
returned code 401. Truncated server response: { "error": { "errors": [
{ "domain": "global", "reason": "required", "message": "Login
Required", "locationType": "header", ... (use muteHttpExceptions
option to examine full response) (line 4, file "Code")
I recognize this is shows I need to provide credentials for making the request, but I don't understand how I would do that. I read on the tutorial (https://developers.google.com/gmail/api/auth/about-auth) I need to authorize my app with gmail and get an API key, so I have gone to the google developers console to create that. However, I have no idea how to authenticate or make the call through a Google script after a few hours of google.
Here are the key and secret I was given:
Is this the easiest solution to toggle gmail forwarding? If so, how do I authenticate my call? If not, what is the easiest solution to being able to toggle my gmail forwarding off/on?
You need to pass oAuth token in header information
function updateForwarding() {
var userID = "main_email#gmail.com";
var header = {
Authorization: 'Bearer ' + ScriptApp.getOAuthToken(),
}
var response = UrlFetchApp.fetch("https://www.googleapis.com/gmail/v1/users/" + userID + "/settings/autoForwarding", {
method: 'put',
enabled: true,
headers: header,
emailAddress: "secondary_email#gmail.com",
disposition: "leaveInInbox"
});
Logger.log(response.getContentText());
}
As noted in the authorization section of https://developers.google.com/gmail/api/v1/reference/users/settings/updateAutoForwarding, you need to use OAuth with the given scopes to make that call, not just an API key. You appear to have a client id, but you need to plug this into a library to handle the OAuth process for you. The OAuth process will then give you a Bearer token to add to your request (although most OAuth libraries will handle this for you).
It looks like https://github.com/googlesamples/apps-script-oauth2 is the current recommened way to do this if you're using UrlFetchApp (based on https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app).