Reading user permissions in Google Analytics via API - not working on property level - google-analytics-api

I am trying to read out the list of users, incl the user permissions, using the API call documented at https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtReference/management/accountUserLinks/list
I get the list of users as expected, but not the permissions. (Actually, for "some" users the permissions is listed, but not for the most)
The GA setup has a number of properties, and the users have permissions set on property level in most cases.
My guess is that the "property level permissions" is not reported properly through the API response for the users which in the UI/console have their permissions listed as "None (user has permissions on a lower level)"
As the next intended step is not only to read out the user list, incl permissions, but also do scripted CRUD operations I'd like to understand what the "intended way" to deal with this via the API is.
Anyone that is working with CRUD operations of users via the Analytics management API?

Ah, finally I found the API call https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtReference/management/webpropertyUserLinks/list which solves the problem.
(Sorry for not RTFM, but it is actually a bit confusing when this API call is at the end of API list, and the other call is in the beginning...)

Related

Create MS Teams chats with MS Graph (or PowerShell)

I'm currently trying to use Microsoft Graph to send a Microsoft Teams Chat message to a specific employee.
The idea behind that is that I want to be able to send chat messages using PowerShell, but for now, I'd be happy to get it done in Microsoft Graph first and build a PowerShell script afterward.
Important: I don't want to post a message to a Channel, only in a 1:1 chat.
What I've tried:
I'm able to get the current chats for my own user by using:
https://graph.microsoft.com/beta/users/{myid}/chats
If, however, I try that with a different user's id, I get a 401 (permission denied) error. I can't even see their current chats even though I have all available permissions.
In the error message, it says the following:
"User Id must match the API caller when called in delegated mode"
... but I don't want to use delegated mode since that'd mean I'm executing the commands as if I would be that user, and therefore couldn't create the chat message which I want in the first place.
It might sound rather confusing, so I hope you get what I mean.
To my knowledge, there's no way to send a message directly to the user without some kind of context. The problem becomes, for instance, where would the message appear, and who would it be from?
If you could deal with it being inside a Channel instead, then PowerShell is fine as you can set up a webhook to do this. I've done the same, from PS -> Teams a few years ago, so I assume it should still work. This article should help.
Alternatively, if you really want a "1-1" conversation, so to speak, you need to create and register a Bot, so that the message comes "from someone" to the user. This concept is called Pro-active Messaging and I've posted more about it here. However, coming purely from PowerShell it's going to be a LOT of work:
Create a Bot in Azure to get the App ID and Password. Technically this would be a non-existent Bot as there's no implementation, which means if the user were to reply it would go nowhere. This might be ok? You could possibly try build an Azure Function Bot in PowerShell, but not something I've done myself so can't advise (I've only used C# for Bots thus far)
Create a Conversation ID, and save it for later - again, a bunch of work.
Convert the code (e.g. from my post above) into PowerShell, referencing the relevant NuGet packages.
So, I'd recommend trying to find an approach using a Teams Channel rather, and messaging the user there, if you can manage that in your use case?
Unless all of this is irrelevant if you're trying to send on behalf of another user?
The term "Delegated" in this context refers to the type of permissions claims included in the OAuth token. There are two types; Application and Delegated.
There are two key rules when it comes to Application vs. Delegated scopes:
A single token may only contain a single type of scope. In other words, the token itself is either an Application or Delegated token, never a combination of the two.
The type of scopes applied to a Token is determined by the OAuth Grant you used to obtain it:
Authorization Code: Delegated
Implicit: Delegated
Client Credentials: Application
With regard to the List Chats (/chats) endpoint, only Delegated permissions are supported:
Delegated (work or school account): Chat.Read, Chat.ReadWrite
Delegated (personal Microsoft account): Not supported.
Application: Not supported.
There is a general rule of thumb when it comes to permissions in Microsoft Graph (I use 'general' here since there are a couple of exceptions in older endpoints): Delegated scopes that only apply to the current user end in Read or ReadWrite while those that apply to any user end in .All.
Since these two scopes (Chat.Read and Chat.ReadWrite) do not end in .All, and only Delegated scopes are supported, this tells you that the only Chats you are able to access are those owned by the currently authenticated User. In other words, you cannot read another User's chat messages via the API.
If you think about it, this makes a lot of sense. If you didn't have an authenticated User, who would the Chat message you sent be "from"? A chat message requires both a Sender and a Recipient.
For your scenario, there are a couple of possible workarounds from a Teams ChatBot to simply setting up a new User that you authenticate as and send messages to other Users from.

Cannot retrieve the reach estimate for some Facebook ads (from the API)

The API lacks some clear explanations on retrieving the reachestimate for either an ad account or an ad. I have made sure that:
I am an admin/ or added to a Facebook app
I have a paid advertising campaign
The adaccount ID is added in the Settings Advanced panel of the Developer App page
I've been trying to:
In Graph API Explorer, retrieve the data by query expansion: me?fields=adaccounts{campaigns{adsets{ads{reachestimate}}}}. However, I always get one of the following (randomly):
Still in the explorer, retrieve it by direct access: act_{adaccount_id}/reachestimate I get this, even if I am 100% sure the ad account is added in the Advanced Settings panel:
Both of 1 and 2 in the iOS project. I get this: com.facebook.sdk.core error 8
Test it by curl with the example from here. I get this (the same with the one from point 2): The ad account is not enabled for usage in Ads API.
Just as a further note, for point 1 that's not the whole query, but I didn't write the adjacent fields because they would've been redundant for the purpose of this question.
I simply need to retrieve the ad accounts, the campaigns, the ad sets and the reach estimate simultaneously in the same query. It seems like a dead spot for me. Do you have any suggestions? Can you show me a Graph API explorer working example? Or, if what I'm asking is impossible, can you simply show some code that works?
Are you app and ad account owned by the same person?
Facebook Ads API has tiered access. https://developers.facebook.com/docs/marketing-api/access
A newly registered app is in Development Tier and can only access the user's own ad accounts. You need to make some API calls on your own ad account for testing in order to get promoted to Basic Tier and manage other people's ad account.
Apparently, I got:
Please reduce the amount of data you're asking for, then retry your request.
Because the query was to broad. Those 'adjacent' fields actually triggered a massive query, so the solution was to either:
Put a limit(1) on the campaigns.
Individually retrieve the reachestimate for each adset.
I chose the latter because it suited my needs, but it's up to you which solution works better.

REST API DESIGN - How to overcome the impedance mismatch between a front end client's needs and REST principles?

Given the following scenario:
a RESTful API
that RESTful API has permissions/authorizations that can be granted to entire entity collections, and/or to particular entities, i.e. complex role based permission rules.
The API is (according to RESTful principles) HATEOS-driven (resource url's are revealed through the API. Once you login and get back the "user" resource, you are able to drive the entire API through links given in responses.
A front-end client (web app) that needs to use this API
Imagine now the front-end wants to build a menu. That menu is based on access to particular entities and/or entity collections. For example an "Administration" menu will be shown if the user has access to one of a number of different entities and/or collections.
How do I build the menu? I need to know the permissions the user has in order to build the menu propertly. I don't know all the permissions the user has because it would require walking the url's of the REST API to see all the objects the user has permissions on.
This seems like a tough thing to overcome, but maybe I am missing some obvious technique. How can this impedance mismatch overcome?
Your REST API can expose a resource (or it can be a part of the user resource returned after a user has been successfully signed in) which will contain information what resources the user can access and therefore what menu items should be available for this user.

is there a deep dive on google's oauth2 scopes?

I'm looking for some deep down detailed information on google's use of oauth scopes
My Drive app is working, so I get the simple use of scopes. However I have the following detailed questions/issues..
I specify scopes twice. Once in my app and then also in the API
Console. What is the respective significance of these two scope
declarations?
If I remove scopes, must my user re-authorise my app, or is this
only required for adding additional scopes?
If the answer to 2, is 'I can't silently remove scopes', will the
Google libraries deal gracefully with re-authorising the user, or
will I just get 403 failures? I've read How should an application add/remove scopes to an existing grant? but the accepted answer specifically references adding scopes, whereas my question is about removing scopes.
Can different modules within my app request different scopes within
the superset specified in the API console? To explain, my app has 3
components: a chrome extension accessing Drive, a web client using
JS to access Drive and YouTube (in online mode), and a server
component which accesses Drive (in offline mode)..
Can my app. enquire what scopes it has been granted?
A general question, I'm sure I face the same dilemma as many app authors. If I increase functionality (a good thing since it attracts users), I also need to increase permissions/trust a user places in my app (a bad thing since it repels users). Are there any recommendations on how apps should best handle this conflict of interests?
List of scopes in your client code - this is what a user authorizes your app to do
When you request authorization from a user, you need to specify what you would like the user to consent to. This is what the list of scopes is used for - it controls the text the user sees when they authorize your application, and the refresh / access tokens granted by that authorization are limited to making API calls that are allowed by those scopes.
List of enabled services in the API Console - this is what your app authorizes users to do
To my knowledge there is no list of scopes specified in the API Console. There is however a list of Google services that can enabled. Enabling/disabling a service here is more about turning on/off ability to make API calls and managing quota and/or accepting terms of service related to that API, than it is authorization.
When an API call is made - you send along an access token
The access token encapsulates the user making the request, the scopes the user authorized you for, and the client ID used for the authorization (which in turn belongs to your project). At this point you need to have the service that the API call is sent to enabled on the project, and the correct scope for the API request - or you will get a 403.
When your list of required scopes changes - you should expect users to need to re-authorize
At the point you request an access token (typically by sending a refresh token) you need to be prepared for that request not to succeed. Maybe it's because you've added scopes - but maybe a user has chosen to visit https://accounts.google.com/IssuedAuthSubTokens and has revoked your applications access. I'm not sure whether if you request less scopes than was granted by the user initially will trigger this, I would experiment to test - but the point is that regardless your code needs to be able to handle this scenario. I believe the OAuth2DecoratorFromClientSecrets (from the linked question) will handle this gracefully for you but am not certain - it should be easy enough to verify.
Using the same authorization across multiple clients - suggest reading through this doc and see if it covers all of your scenarios: https://developers.google.com/accounts/docs/CrossClientAuth
To see scopes granted to an access token - use the OAuth2 API: https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=yaxxxxxxxxxxxxxxx

How can I get read-only access to the Google Apps Profiles API?

I have an application which wants to provide customization for users once they log in. Simple things like displaying a profile image and job title. This information is available in the Google Apps Profiles API, but the domain-admins are concerned about overreach with the scope. In particular, they don't want to approve the application if it has write access when it isn't needed.
The regular scope (with read/write) for the API according to the API Documentation is https://www.google.com/m8/feeds/profiles and I have tried all of the following with no luck
https://www.google.com/m8/feeds/profiles.readonly
https://www.google.com/m8/feeds/profiles.read
https://www.google.com/m8/feeds/profiles/#readonly
https://www.google.com/m8/feeds.readonly
https://www.google.com/m8/feeds.read
https://www.google.com/m8/feeds/#readonly
What scope can I specify in order to get read-only access to the Profile data? If I'm barking up the wrong tree entirely, where should I be looking?
Any non-admin user can access the GAL programmatically, see:
https://github.com/google/gfw-deployments/blob/master/apps/shell/gal/gal_feed.sh
I don't believe this api call is documented or supported officially. Note that the Global Address List is a compilation of user profiles, groups and shared contacts. If you don't want to see groups and shared contacts you'll need to figure out how to parse them out.
You need the user account under whose credentials the code is running to be either:
super admin or
to be listed under CPanel > Domain Settings > Admin Roles > [...put it in a created/user role...] > "Provisioning APIs" > Users - create/update/read/delete (as required, ticked ON). For example, for read only access to the Profiles API, set it there to 'read'.
I wrestled with this myself. I was not able to get this to work either.