Google Script OAuth for multiple users - google-apps-script

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.

Related

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.

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.

GAS execute under the content of active user

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 ?...

Automate the oauth authentication without browser in cron utility

I am trying to upload some documents on Google drive, i want to run a cron script which is executed at mid night every day and the files generated as a result of it should be uploaded on the uses Google drive.
I tried the standalone script, which uploads document on Google drive, but for that i have to every time do allow access via browser.
However my purpose is to run a cron and upload the files, at the time the cron executes there will be no browser access.
Is there any way i can do the authentication process without manual intervention.
any help in this case would be really appreciated.
THanks,
you can authorize your App(script) with Google Drive.
Here, you mentioned you are writing a script which upload docs to your Google Drive.
I suggest you register a app in Google Cloud Console to get client ID and client Secret firstly,
and turn on Drive API for you registered App.
Then use this client ID and Secret to run oauth flow in your script to get an access token and refresh token, the access token's lifespan is about 3600s, and if it's expired, you can also get a new one with the refresh token.
User's interaction(consent) is required only in the first time you request access token.
In this way, your script can work in "a real script way".
Here are some reference:
https://developers.google.com/drive/about-auth
https://developers.google.com/accounts/docs/OAuth2InstalledApp?hl=zh-CN
I am assuming its only one user drive account you are uploading to. Have you considered using a service account fo this? https://developers.google.com/drive/service-accounts
If its not a single user account you are uploading you can just save the refresh token some place and use that to get a new authtoken every night.
Hi i figured the problem,
i was generating refresh token from oauthplayground and was trying to integrate it in the php script....which was invalid......
I then printed the refresh token returned for the first time when a user allows access and used that for future generation of access token and it works like charm. thanks All for help

How do I obtain an access and refresh token for a google apps script

Hi I have a very simple Google Apps Script, i.e. one that is created when in Google Drive and click create and then script.
What I would like to be able to do is have users authenticate using the oauth 2 protocol, receive the authorisation code and exchange that for an access token and refresh token. This requirement is for an IPhone app so I would rather save the refresh token so users do not have to login repeatedly.
My issue is that I do seem be able to get the access and refresh token, I can see the client_id of the app in the url returned from the authentication step, however I believe I also need client_secret to request the access and refresh token from:
https://accounts.google.com/o/oauth2/token.
I'm asking it this even possible, if so do you know of any examples and if not could you recommend a different approach (perhaps use an application specific password).
Many thanks
You should be able to obtain this from the Oauth Playground.
Oauth Playground