GAS execute under the content of active user - google-apps-script

Is it possible to use a Google form, develop a GAS script that executes on form submission but have it run under the context of the users submitting the form?
Users will be in a GApps for Business domain?
Will it need to be published as a web app using doGet(), even though there will be no UI?

Only webApps have the ability to run under user's authority and they have an authorization request feature to handle that case. A form has no way to ask for authorization so it won't be able to do anything (or to trigger a script that would do anything) in the name of a user without explicit permission. That's a basic security case and hopefully there will be no way to go around it.
I guess the only way to get what you want would be to create the form with UiApp or HTML Service and deploy it as a webapp running under user's authority, in that case your users will be asked for authorization to access the services you need.
note : you said "even though there will be no UI?" but the form itself is a Ui isn't it ?...

Related

How to avoid Restricted Scopes OAuth verification process for private scripts used only by me?

I have received email from Google with subject: [Action Required] Submit your app(s) for Restricted Scopes OAuth verification,
same as many of you.
I'm using GAS only for developing applications for my personal use - not for public. Applications such as sending summary emails to my clients, when they buy a product from my web pages.
Do I have to go through the whole process of verification?
Do I have to create public Terms of Service?
Is there any way how I can explain to google, that my applications are not used by anybody else then by
me?
How to get to know for sure that my app won't stop?
I have read through FAQ (https://support.google.com/cloud/answer/9110914) and many other documents by google about this topic..
I have checked similar questions found on web, but with no luck of answers.. It looks it's pretty new experience for all of us..
Thank you for any advices.
I have personal account, so I can't use "internal apps" selection, this works only for paid G-suite customers which I'm not.
EDIT:
As Yoel Vinitsky stated, app doesn't need verification if it has only one user.
Here at bottom: https://support.google.com/cloud/answer/7454865 is table which shows that there is quota 100 new users in total, once the app presents the unverified app screen.
It seems like that I don't have to worry about verification of my apps at all, because I'm the only one user or maybe I use this app from 2 or 3 more users emails so it should be ok, my question is, is it going to be ok without verification, or not?
EDIT 2:
Google sent clarification email:
NO ACTION is required if:
Only owners use the project: If the project is only used by owners of the project, no action is required.
To determine whether you are an owner (versus an editor or viewer), follow these steps:
Click the project link above to navigate to its OAuth Consent Screen
configuration page.
Click the Navigation Menu button in the
upper-left corner, select IAM & admin, and click IAM. This will show you all project contributors and their roles.
The project doesn’t have users outside of your G Suite domain:If the project owner is using a G Suite account and the project is only used by Google Accounts in the project owner’s domain, no action is required (learn more here).
But the question is how to avoid verification with personal accounts for my own scripts used only by me?
As mentioned in the support FAQ You linked to:
When can I skip publishing my app for a review?
You do not need to request for verification if your app is
going to be used in any of the following scenarios:
1) The app is not shared with anyone else.
2) The app is used to send emails through WordPress, or
3) similar single account SMTP plug-ins.
The only drawbacks should be the warning that your app is unverified and maybe quota limits.

How to use OAuth 2.0 with a Google Apps Script library, with a static redirect URL?

I can't figure out how to make a shared Google Apps Script library, that uses OAuth 2.0.
The problem is that the usercallback redirect URL changes, every time I use the library in a different script. However, that means I'd need to add a new app and whitelisted redirect URL to Asana for each spreadsheet I use the script in. I'm using https://github.com/googlesamples/apps-script-oauth2.
Is there a way to always authenticate with the same redirect URL, so that the library I make can be used from any script, without registering a new redirect URL in Asana?
I'm a Developer Advocate here at Asana. If I understand your question correctly, then yes, you'll have to handle the callback separately for each script. For security reasons, we validate that the OAuth app registration registers the same url as an integration actually requests when authenticating. If this weren't true, for instance, it'd be possible to create a malicious script that uses the client_id from a legitimate script but asks for the redirect to go to its own credential-grabbing endpoint. This is fixed if the app that got the client_id on app registration also specifies precisely which endpoint should be the legal endpoint to redirect to. That means each OAuth app needs to have its own unique and consistent redirect URL :(
I suppose you could possibly create a single "router" Google Apps script which would set the state parameter with some user/script pair when hitting Asana's oauth_authorize endpoint and forward the user credentials on to the script that exists behind the router script based on that user/script pair when the response comes back, but it's not super trivial.
One final option would be to use a Personal Access Token to access Asana's API. This one token can be used by an unlimited number of scripts for access. The downside is that this token "looks like you", that is, it takes action on behalf of not a third party user but you yourself - your scripts would be an automated version of the user whose Personal Access Token they use. This can be mitigated to some extent by creating a "bot account" to access our API and giving it access inside of Asana to the projects or teams you want to gather data on. The other downside to this approach is that every script that uses the personal access token will break if you ever revoke the one token, so if that ever happens by either intent or accident, you'll have to update the Personal Access Token information in every script that uses it.
Hopefully this helps you to evaluate the options and choose which one of these options works best for your script.

Admin access to Domain User's Gmail?

I'm currently writing an auditing script that is focusing on users' gmails and need access to their message lists. I have admin access and scopes for the AdminSDK, the script will be executed by the admin.
I'm wondering how exactly to do this? I have my domain's userlist via Directory, but I can't use GmailApp with a specific user, only the current user(admin). I was also thinking about assigning a timed Trigger to each of the users and using GmailApp locally, but I can't figure out how to do that either(I don't think this is possible).
One idea that I'm working on is pinging the Gmail API using the admin's credentials via URLFetchApp, but can I get my domain's users information with this method?
What are your thoughts? Any guidance will be appreciated.
I'm currently using GAS on a service account.
While using service account, you can impersonate users in your domain and perform actions on their behalf. For this you will need to perform domain wide delegation of authority in your domain.
Here you can find documentation about domain wide delegation.
Here you can see an example, I know is on Drive but the principle is the same.
Hope this helps.

Google Apps Script - Access to different account (contact-api) via OAuth2-authentication

Retrieve/Update Google-Contacts from Apps Script (Spreadsheet)
Environment Desc:
We have a shared spreadsheet belonging to a domain-account "PrimContact" where we also manage our contacts.
The spreadsheet is shared with selected users in the domain with r/w-access.
Workflow so far: after making changes to the spreadsheet persist those changes through script-call.
This api-call was authorized via clientAuth and as of a few days that won't work anymore.
Through clientAuth we were able to allow all the users to manipulate the sheet and finally update
the contacts of the targeted contact (PrimContact).
Problem:
Reading up about deprecation of clientAuth I tried, and somewhat succeeded, to change
authentication to OAuth2. As I understand things there are two ways I can authenticate a
user. Through a clientAccount or via serviceAccount.
SideNote: The following two pages helped a lot in getting it done, especially for serviceAcc.
[1]client account with: https://github.com/googlesamples/apps-script-oauth2
[2]service account auth with: https://github.com/mcdanielgilbert/gas-oauth2-gae
For that to work I added a project to PrimContact-user and created both a web-account and a
service account. Using aforementioned scripts as a starting point authentication works too, but
in the end it's not what I am trying to accomplish.
Client Account: the script is calling the api (contact-api) with an access token for the currently
logged in client although I provided the clientId of the PrimContact-user. Now I COULD run the script as PrimContact-user beforehand and store the token
in the document. If the access-token has not expired yet the other users can work with this
token just fine and therefore "operate" on the PrimContact-data. But as soon as the token
expires I would have to call the script as PrimContact-user again, which is not to very comfortable.
Service Account: got it working with gas-oauth2-gae, but the contact-list is empty. The call
itself is successfull though. I guess this is due to the service account not being tied to
the PrimContact-user although the project is associated with this user?
Goal:
Making an api-call (contacts) inside google-apps-script(spreadsheet) used by different users and
manipulate contact-data of a different account, i.e. the account who originally shared the spreadsheet.
Maybe I'm getting the whole idea of OAuth2 completely wrong, so far my understanding of the
clientAccount-thing is that the currently logged in user allows the project (which belongs to the
PrimContact-user) to manipulate the data of the currently logged in user.
What data the service-account-authenticated call is manipulating.. I'm not quite sure..
If it helps I can add the code-snippets, but as everythings "working" & still not doing what
I really need it to do I'm not sure if it's helpful.

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.