I would like to submit a post request to a published Google App Script Webapp containing authorization information - google-apps-script

I have written a google app script which I have published.
It is set to run as me, but should be accessible to others in my company workspace
I've also written a NEXTJS front end that handles authentication, but I'm struggling to identify what the post requests should look like regarding authorization.
I have reviewed much of the information Google has provided regarding authentication using oauth

Related

Reposting: Not possible to use Google login authenticator button for Google webapp [duplicate]

When attempting to use Google federated authentication login button for a Google webapp, error message identified mismatch with related URI and javascript host domains. Solutions, as in this 2019 post (Get gmail address using Google Apps Script, Error: redirect_uri_mismatch) weren't working for me.
I then found this recent article: What is the Authorized Javascript Origin for a webapp powered by Google Script?
I understand it to say that, due to recent actions by Google, it is no longer possible to use the Google authenticator for a Google webapp because redirect URI and javascript origin host domains "cannot be googleusercontent.com”, which is the host domain for Google webapps.
So, my question duplicates earlier posts (i.e., 2019) but in new circumstances. The conclusion of the recent post I've cited seems so radical to me that I'm seeking confirmation, or explanation of how I am misunderstanding it.
As background: I need the webapp to operate under the "(me)owner" account for connectivity to owner spreadsheets, but also need the user's Gmail address (required) for application access control (no other access to user Gmail account; users not all in a shared Workspace domain). Google login would provide the user Gmail address. So, before totally abandoning this solution, I hoping to get additional clarification.
According to the official docs, it's not possible to use Google Sign-In for Websites, and this post from the Google Apps Script Issue tracker Fail to Add *.googleusercontent.com into Authorized JavaScript origins as Google Apps Script uses googleusercontent.com
To achieve your goal, as I mentioned in your previous question, you might use the UrlFeth service to call the Google Sheets API to do the connectivity to your spreadsheet and setting the web app as the user instead as you.
From https://developers.google.com/identity/protocols/oauth2/web-server#uri-validation
Domain
Host TLDs (Top Level Domains) must belong to the public suffix list.
Host domains cannot be “googleusercontent.com”.
Redirect URIs cannot contain URL shortener domains (e.g. goo.gl) unless the app owns the domain. Furthermore, if an app that owns a shortener domain chooses to redirect to that domain, that redirect URI must either contain “/google-callback/” in its path or end with “/google-callback”.
Related
How to Properly Configure GAS Web App (as another user) to Execute GAS API Executable (as me) using OAuth2?
User access request when GAS run as the user
While true that you can no longer add googleusercontent.com, you may be able to solve this by using two webapps and managing authentication/authorization between the two:
Webapp#1:
Run as: Me
Access: Anyone even anonymous
Webapp#2:
Run as: User
Access: Anyone
You may be able to create a jwt token from webapp#2 and verify it on webapp#1. As it is a custom solution, security may be questionable.
References:
Authenticate with a server - Here, webapp#1 acts as server and webapp#2 acts as client.
ScriptApp.getIdentityToken()

Read Gmail POST Notification using Standard Google Cloud Platform (GCP) Script

I am trying to create a subscribing webapp using Google Scripts App to receive and decode POST notifications from Gmail API whenever a new email is received. The new changes in the Google Cloud Platform (GCP) is making it very hard to work. All the documentation/videos I have found about this are obsolete.
I created a script with a doPost() function directly from Google Drive (not linked to Google Docs, Sheets or Forms) and deployed it as a webapp with a provided link. I had to link the script with a standard GCP project as the default GCP projects which are automatically created for any Google Scripts App are not accessible anymore. The next step was to go to PubSub API in GCP, created a topic. When I try to create a subscription to allow the webapp to receive the POST messages from Gmail API, and set its delivery type to PUSH, an Endpoint URL is required. When I use the webapp link, I get the error:
The supplied URL is not registered in the subscription's parent project. Please see documentation on domain ownership validation.
I went throug the domain ownership validation and tried all possible solutions I found online without success. Without the PUSH subscription, I am unable to receive the notification, decode its body, get the email id then retrieve and decode the email body. Any help is highly appreciated.

"Invalid legacy scope provided" error when attempting to access a Google API from web app?

Here's what I'm trying to do:
Remotely execute a Google Apps Script function from an online automation service (Zoho Flow, similar in purpose to Zapier.)*
This function that I am remotely executing is to add gmail labels to everyone in an organization.
In order to do this, I've done the following:
Created a service account with domain-wide-delegation in the same GCP project associated with the function that adds gmail labels.
Used the OAuth2 library for Google Apps Script to perpetuate JWT authorization for that service account in my script.
Verified that function works with service account functionality for all users in a Google oragnization within google apps script
Deployed this script as an API Executable to enable remote execution
Created authtokens authorized with the mail scope for the Apps Script API (https://mail.google.com/), as well as an additional scope required by the OAuth2 library in my script. This is done in the google developer playground, using OAuth2.0 Client ID credentials that are authorized as a part of that same GCP project.
Successfully executed the function remotely using the Google Apps Script API with Postman
Now, in order to actually make this functionality official, I now have to replace postman and the google developer console with the actual client, which is this Zoho Flow platform for api connections and process automation.
In order to make the switch I've done the following;
Added the authorized redirect URl for the client (Zoho Flow) under the same credentials that are used for the Google Developer Playground:
Utilized the credentials found from the JSON representation of those credentials** for creating what's called a "connection" in this software, which is basically an easy-to-use OAuth2.0 connection with a nice front-end that can be used for accessing API data (this is the part where I create this connection):
Entered the same scope for this connection that were authorized in the google developer playground, as well as that additional scope (https://www.googleapis.com/auth/script.external_request) that the OAuth2.0 library for Google Apps Script uses:
Lo and behold, I get the error below when attempting to gain access to Google API data from a web application, and the scopes that are said to cause the error is every scope except for the mail scope: https://mail.google.com/. I've done additional testing to verify that every other scope that is a part of the google apps script API also create this error, not just this external scope for the OAuth2 library.
Support said it was likely an issue with my credential permissions; is my line of logic for this correct? If it is, then it is an issue with their software that I will have them pursue further.
Some additional testing has been done on the software (Zoho Flow) to confirm whether or not it is a software error or not: I'm not certain if the process defined in my answer is best practices, or even 100% correct (other users can speak to it,) but I've confirmed that the error I am seeing is likely an error with the client.
Here's why:
When authorizing for multiple scopes, I get the error seen at the end of my question:
When changing that connection to utilize only one of my scopes instead, like so:
The connection proceeds properly, and I can remotely execute functions that utilize only that one scope successfully. This does work for any one scope that I authorize. The only problem is, it's a rare occurrence that a script only requires one scope. While this I can get around this major bug, I cannot remotely execute my function that adds gmail labels to all users in an organization because it requires two scopes. This will be mentioned to the development team and it should be fixed soon.

In Google Apps Script, avoid second 'Review Permissions' prompt, possibly by using approval_prompt

I have searched StackOverflow, etc. for a solution to this problem, and several answers 'point me in a direction' (mentioning approval_prompt = auto not approval_prompt = force), but none are applicable (as far as I can tell) to my situation.
I have a Web Application hosted at www.mjpanel.com that expects to use a Google Apps Script that I 'own', but the Javascript at www.mjpanel.com calls the Google Apps Script (deployed as a Web App with doGet()) as a Web Service. It expects the web service call to return various JSON objects.
If the user has not yet authorized my application, the call to the Google Apps Script Web App / Web Service will not return a JSON object, causing www.mjpanel.com Javascript code to fail saying "Invalid Request" (because it isn't a JSON object as my code expects).
To prevent this from happening, www.mjpanel.com uses gapi.auth2.init to get the permissions/scopes it needs. I'm developing everything now, so if/whenever the Google Apps Script evolve to use something (like sending GMail emails as the user) that is new, I have been figuring out the scope to request, adding it to the list of scopes in the gapi.auth2.init call, and everything is fine. The next time a user uses the app., they get initially prompted for the newly added scope, then everything proceeds fine.
However, now sometimes one of my test users has a Web Service call fail because Google Apps Script is returning another request for permissions for a 'new permission' of 'Have Offline Access'.
There's nothing about my script that would warrant the user needing to grant this permission.
When I research, a lot of stuff (mostly about requesting OAuth2 stuff in a 'structure' different than the way my app. is set up) says it has to do with submitting a 'approval_prompt=force' in my request URL.
However, the way I have my app set up, all the URLs I would use (aside from my 'custom stuff' in the query string) are dictated by Google Apps Script. And I can't find any place where any URL I use has an approval_prompt in it.
I can't figure out where I would need to configure that approval_prompt to be auto (as is recommended in the 'successful answers' I find).
Of if the idea of approval_prompt is 'on the wrong track', any information in general to help me solve this problem would be greatly appreciated.
Thanks in advance for any help you can give me.
Unfortunately the Google Apps Script native OAuth flow includes approval_prompt=force. This causes the following conditions:
If cookie exists in browser and has permission for this application the consent screen will not be displayed.
If cookie exists in browser but does not have permission for this application: consent screen will be displayed
If cookie does not exist in browser and the application has permissions: application will request 'Have offline access'.
The easiest way around this is to manage your own OAuth flow and use the Execution API. The following link will take you to the javascript quick start.
https://developers.google.com/apps-script/guides/rest/quickstart/target-script

Google Script OAuth for multiple users

I've created a Google App Script that handle 2 different OAuth connections.
1- Google itself to send mail on behalf of the user and access google docs (google api console used to get keys, secret)
2- gtraxapp wich is a timesheet cloud-based app. (Script is registered, got a key/secret, etc.)
The script is published as a web app. It works perfectly for my user.
When logged on a different user name, I can authorize Google OAuth without providing different key/secret, and emails will be sent from the actual user.
Problem happens with the 2nd app (gTrax).
Authorization seems to work. Running the function inside the script to authorize lead to a screen asking for permission, gtrax then appears in the account as a registered app (could revoke access if needed).
But, when running the app, I get a message saying I need permission to do this action (UrlFetchApp / simple get)
My question is :
Is this possible that I need to register each user to get a key/secret for everyone (and dealing with that in the script)...
Or do OAuth can be registered with 1 key/secret ?
In other word, are (should) key/secret linked to a single user or are they only a kind of RSA-like key pairs that, when verified, can be used to authorize any user.
My understanding is this. When you use built-in Apps Script functions, like MailApp.sendEmail, the Google Apps Script "environment" takes care for you to ask authorization for the user (1st time he access your app) and save and manage the oAuth tokens for you, so it all runs smoothly.
When you call an external service using UrlFetchApp, Apps Script oAuth authorization process works differently. The authorization is just a strange popup you get on the script editor, when you actually make the fetch call. It is not processed at "compile time" and asked before you run anything like the other services. But you also do this step only once.
The "gotcha" is that this different authorization process does not work when a user is running the app as a webapp. AFAIK it only works from the script editor itself or running directly from a spreadsheet.
If your users are just a known few, you could advise everybody to open the script editor (or a spreadsheet that contains it) and run an specific function that will just attempt the UrlFetchApp.fetch call so the popup shows up and they authorize it. Once this step is done, they can use the webapp normally. Apps Script will do the magic for you after that.
But if you plan to share this broadly, say at the Chrome Web Store, and don't want to ask every user to do this somewhat strange step, then you'll need to manage all the authorization process yourself. It means, you'll have to register your app with the third party service (if it's Google's, it's at the API Console), where you will receive a client id and a client secret. With those you'll have to place a "Authorize" submit button on your app html that will redirect the users to the 3rd party authorization url, providing the correct scope, etc. When they authorize it, the 3rd party will redirect the user back to your app providing a code token as URL parameter. You'll use this code to call the 3rd party oAuth service to get the real access and possibly refresh tokens that you'll have to use on your UrlFetch calls. You'll be responsible to save these tokens, refresh them when they expire and so on. Not a very simple procedure :-/
Oh, and although your app have only one id and secret, the tokens are per user. Which makes sense, since each call you do must be on behalf of a specific user and he *must* have authorized it.
I hope this helps.