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

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.

Related

Execute web app with Gmail access as user who executes the script

I started quite recently experimenting with web apps, and I am now busy getting them to run across accounts within my organization.
I need to update labels to Gmail emails across these accounts, as well as update a shared spreadsheet. I trigger my scripts via a get request triggered from the client details spreadsheet, which identifies the email threads in the associated accounts and applies them a label.
For this to work without having to create a web app per account executed as the owner of the account, I imagined that a deployment executed as the user who executes the trigger would just do it. However, doing so results in an html response that seems to be an authorization screen from Google.
I am not very familiar with the required authentification concept in this case, as I had no issue since a year than I work with Google scripts. I guess Google should show the authentification prompt like they always do, but in this case it's not showing up.
It works fine when the app is run as myself, but I’d hate to have to replicate and maintain the project on each account, even though that is a way to achieve the result.
I read a number of articles, but many did not apply to my situation, and others were beyond my current skill to try them all out. I also tried a few things in the cloud console but I am too noob to get my head around it fully.
I use the required oAuth scopes and don't see what can be missing. I tried putting "Authorization": "Bearer " + ScriptApp.getOAuthToken() in my request's headers but this makes no difference.
Thanks in advance for your help!

YouTube API and brand account

I am using, since a long time, a Google script that accesses my YouTube channel, gets and modifies some information from it and saves some data in a Google sheet.
It always worked fine, but then, about a week ago, Google somehow split my access rights between my normal account (primary email) and my YouTube account (that goes under a different nickname).
I cannot find a way to run even the simplest command:
var my_playlists = YouTube.Playlists.list('snippet', {
mine: true,
maxResults: 50,
})
.items;
The problem is that google now prompts me with an authorization page and I can choose between 2 accounts. One is my primary account, the other is the YouTube one.
If I choose my primary account, the code runs but I cannot see the data of the YouTube account.
If I choose the YouTube one, I still cannot access the data I want and it keeps asking for permission every time I run the code.
I understand there is a problem of authorization between the two channels, but I did not have it before and cannot find any suggestion to solve it.
What can I resolve this problem?
I've been struggling with the exact same issue but for another cause.
Anyways, so far I can manipulate anything I want within my PERSONAL youtube account, granting access using OAuth to MY ACCOUNT, but if grant access to my branded account, the script doesn't even begin, apparently it's a bug that causes loop in the script.
You can check this out for more info:
YouTube Apps Script API only runnable by accounts without a YouTube channel?
https://issuetracker.google.com/issues/36764531
https://mashe.hawksey.info/2017/09/identity-crisis-using-the-youtube-api-with-google-apps-script-and-scheduling-live-broadcasts-from-google-sheets/
Using Youtube Data API to Edit with Brand Account Playlist

How to give write permissions only to UI app to write data to a Spreadsheet

I have developed a web application using Google scripts UIApp class which will collect the data of work done by each associate and writes data to my spreadsheet.
Problem I'm facing is I have to share my spreadsheet to all the associates with write permission where it enables them to see others data. I want to hide this sheet from all but they should also be able write data using the web application I shared.
Please let me know for more details or any code snippets
Note: I have Not used Google Form because I need change the list values dynamically based on the selection and the type of user.
You can deploy the app you have built with UiApp to be executed as "you" and allow access to anyone. The spreadsheet won't need to be shared anymore but as it is anyone (even anonymous if you are not in a domain) will be able to use it...
You'll have to implement an access control yourself, again this will be different in a domain or in a "normal" gmail account (in a domain you can get the user email, in a gmail account you can't)
(since apparently I can't comment.. but to follow up on this question.)
Is there a best practice for running as something other than really-yourself?
Say a team is managing it, or your a contractor who won't stay with the company, and so you're account and access is likely to go away.
I assume it results in creating a shared account, or perhaps a groups or something? You start getting into all sorts of ACL issues. And a simple ``run as yourself'' doesn't seem like a good long term solution.

Second authorization with same scope and offline access_type has unexpected permission dialog

If I specify access_type=offline in the auth url and a user attempts to auth a second time I get a box that says it is asking for offline access.
I would have expected it to be already authorised and so not require additional permissions
Any ideas?
Edit:
A bit more info. The first time around it makes no mention to the user of needing offline access. I would have thought the offline permission to be mentioned in the original auth anyway.
Edit 2:
Some more info on my use case. It is possible in our system for a person to have two accounts but then use the same google drive account. This means that we have no way of knowing that user has already authorized with google and so have to present the authorization again for the second user.
The first time around (for user 1) you are told that the app is asking for :
View and manage Google Drive files that you have opened or created
with this app
View and manage the files and documents in your Google
Drive
The second time around (for user 2) you are told the app is asking to:
Have offline access
This seems wrong to me.
As an aside:
The whole "have offline access" statement is very confusing for a user and also quite misleading. Most people assume this means the app can read the contents of your pc. In fact it means that the app can authenticate with your account with out you being there (i.e. using a refresh token).

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.