Insufficient permissions error when inserting a new Google analytics view - php

$KEY_FILE_LOCATION = __DIR__ . '/service-account-credentials.json';
// Create and configure a new client object.
$client = new \Google_Client();
$client->setApplicationName("Hello Analytics Reporting");
$client->setAuthConfig($KEY_FILE_LOCATION);
$client->setScopes(['https://www.googleapis.com/auth/analytics']);
$analytics = new \Google_Service_Analytics($client);
// Construct the body of the request and set its properties.
$profile = new \Google_Service_Analytics_Profile();
$profile->setName('View name');
$analytics->management_profiles->insert('123425914', 'UA-2344718-15', $profile);
I try to insert view on GA App but API return insufficient permissions error.
When I had tried to get data if I enter the wrong $VIEW_ID then the same error is printed.
I had enter those parms in insert method
existing VIEW_ID - the same error occurred if enter none existed VIEW_ID.
Second param is existed APP_ID.
Do you see some mistake here? I double check permissions on GA dashboard and everything seems to be ok.

either the user you are authenticating with does not have admin permissions on the Google Analytics account.
You have not received beta access to the write methods on the Management API.
Views (Profiles): insert
Write operations in the Management API (e.g. create, update, delete, patch) for Web Property, View (Profile), and Goal resources are currently available as a developer preview in limited beta. If you're interested in using these features, request access to the beta.

Related

Specify the channel to upload the videos in Youtube API using PHP

I have two channels under my Google account. I can upload the videos to my main channel using the Youtube API for PHP. I want to upload the videos to my second channel (Not the main channel). I have searched a lot, but could not find a solution for that. What I just figured is, that I may need to use the Google_Service_YouTube_ChannelContentOwnerDetails() class, but I don't know how to specify this detail to $youtube->videos->insert("status,snippet", $video) method specified at https://github.com/youtube/api-samples/blob/master/php/resumable_upload.php.I have also found that there is onBehalfOfContentOwner and onBehalfOfContentOwnerChannel attributes which I may need to use, but I think these parameters are for the accounts which have given access to other channels to manage their channels on behalf of them, and I don't need to use them because I own my two channels under one Google account. (Maybe I am wrong). I just want to upload the videos to my second account by authorizing from my Main channel.Any help will be highly appreciated in this regard.
There's no way for one to specify a channel ID to the Videos.insert API endpoint. But bear with me for a while...
The first time one issues the OAuth 2.0 authorization flow, his/her app is receiving something as the following JSON object:
{
"access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
"expires_in": 3920,
"token_type": "Bearer",
"scope": "https://www.googleapis.com/auth/youtube.force-ssl",
"refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}
The access token is short-lived, while the refresh token is long-lived (but can be revoked at will). This kind of JSON object gets cached in a local file, for to be used later when the app needs a fresh access token (that is obtained from the API based on the stored refresh token). The access token needs to be passed on to each API endpoint that requires authorization.
The above two tokens are relative to the Google account that one has been logged into during the authorization process. Under most common circumstances, each Google account is uniquely associated to a certain YouTube account (i.e. channel). But there can be Google accounts that are associated with multiple YouTube channels (see this doc, the section Use Brand Accounts managed by your Google Account).
Now my conjecture: I do think that it's possible for one to have N such JSON objects (relative to the same scope; e.g. https://www.googleapis.com/auth/youtube.upload), each being associated with a different Youtube channel -- all under the umbrella of a single Google account --, all being stored locally in separate files (or even all in one file), such that, when issuing API calls that need to target a given channel, to choose programmatically the associated pair of tokens out of the whole set of N objects.
The second part of my answer contains source code illustrating my conjecture above. It's not my intention to present here a complete and/or an all-encompassing solution, but only to set forth an application frame that would fit the various ways a concrete PHP app may function (e.g. single desktop apps or apps that run autonomously on remote servers that have no browser installed).
The app manages a set of JSON files -- all stored in the same directory ($auth_conf_path). Each file contains the required credentials relative to a certain channel, such that to be able to create from it a proper instance of class Google_Client. The names of these JSON files are of form CHANNEL_ID.json, where CHANNEL_ID is the ID of the channel to which this file is referring to.
The app is split into two parts: one creating these credentials JSON files upon initiating OAuth authorization flows; the other making API calls relative to a given channel for which a credentials JSON file already exists.
The first part of the app, by using initChannelCredentials within an usual PHP OAuth flow, produces IDs of and credentials JSON files relative to YouTube channels to which the app was granted access to.
The second part of the app, upon obtaining an instance of Google_Client class from makeChannelClient, makes actual API endpoint calls relative to the channel identified by the ID passed to that function.
function initChannelCredentials(
$auth_conf_path, $scopes, $redirect_uri, $client_code)
{
if (!is_dir($auth_conf_path))
throw new InvalidArgumentException(sprintf(
'Auth config path "%s" does not exist', $auth_conf_path));
$client = new Google_Client();
$client->setAuthConfigFile(
$auth_conf_path . DIRECTORY_SEPARATOR . 'client_secrets.json');
$client->setRedirectUri($redirect_uri);
$client->setScopes($scopes);
$cred = $client->fetchAccessTokenWithAuthCode($client_code);
$youtube = new Google_Service_YouTube($client);
$response = $youtube->channels->listChannels('id', array(
'mine' => 'true'
));
$channel_id = $response[0]['id'];
$cred_file = $auth_conf_path . DIRECTORY_SEPARATOR . $channel_id . '.json';
if (file_exists($cred_file))
throw new InvalidArgumentException(sprintf(
'Credentials file for channel "%s" already exists', $channel_id));
file_put_contents($cred_file, json_encode($cred));
return $channel_id;
}
function makeChannelClient($auth_conf_path, $channel_id)
{
if (!is_dir($auth_conf_path))
throw new InvalidArgumentException(sprintf(
'Auth config path "%s" does not exist', $auth_conf_path));
$cred_file = $auth_conf_path . DIRECTORY_SEPARATOR . $channel_id . '.json';
if (!file_exists($cred_file))
throw new InvalidArgumentException(sprintf(
'Credentials file for channel "%s" does not exist', $channel_id));
if (!$cred = json_decode(file_get_contents($cred_file), true))
throw new LogicException(sprintf(
'Invalid content of credentials file for channel "%s"', $channel_id));
$client = new Google_Client();
$client->setAccessType('offline');
$client->setScopes($cred['scope']);
$client->setAccessToken($cred);
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($cred_file, json_encode($client->getAccessToken()));
}
return $client;
}
Note that an app as described above is a bit more general than the one subsumed to the original post and to my conjecture above. The credentials JSON files -- equally the YouTube channels -- managed by the app are not required to work all under the umbrella of a single Google account (as was prescribed by my conjecture). These channels may well be relative to different Google accounts, as long as the concrete incarnation of such a PHP app is able to handle properly multiple Google accounts.
I tried setting '--channelId' in snippet object but that doesn't seem to work.
The solution is to generate different oauth2.json for different sub-channels.

How to get Business Locations (and Reviews) via Service Account authentication

I can't get the Locations list from my business under my code (PHP using the "Google APIs Client Library for PHP" together with "Google_Service_MyBusiness" Classes) when I use the "Service Account" authentication, the API returns an empty Location List.
I already have the Prerequisites and did the Basic setup, by the way, I got the information with success on OAuth Playground, under a specific AccountId, Eg: 1111111111, provided by another response there on the "OAuth Playground".
(PS: I tested with my "PERSONAL" and "LOCATION_GROUP" accounts and got success with both).
But when I try to do it over my code via Server Account authentication, I can't get all the information, just the Account data that return another AccoundId, Eg: 2222222222, different of the Accounts that I got on OAuth Playground.
I did the Authentication process on OAuth Playground, using the same project where I created the "Service Account", by the way, the Permission of this "Service Account" is OWNER.
Previously, my role in my company on the Google My Business was "SITE_MANAGER", so I saw a forum answer where just "MANAGER" level/role can list the Locations, so I requested to change my permission, but continues as not the success on Locations listing.
So, I saw another Google My Business support article recommending create a "Location Group" and put my current "Location" into this group to make easy handle it, I did it and no success again.
My code is simple, based on Google guide, OAuth 2.0 for Server to Server Applications, and some Forum Questions (BTW the author's question have the same issue than me):
<?php
putenv('GOOGLE_APPLICATION_CREDENTIALS=service-account-credentials.json');
$client = new Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope("https://www.googleapis.com/auth/plus.business.manage");
require_once('Google_Service_MyBusiness.php');
$mybusinessService = new Google_Service_MyBusiness($client);
$accounts = $mybusinessService->accounts;
$accountsList = $accounts->listAccounts()->getAccounts();
foreach ($accountsList as $accKey => $account) {
var_dump('$account->name', $account->name);
$locations = $mybusinessService->accounts_locations;
$locationsList = $locations->listAccountsLocations($account->name)->getLocations();
var_dump('$locationsList', $locationsList);
// Final Goal of my Code
if (empty($locationsList)===false) {
foreach ($locationsList as $locKey => $location) {
$reviews = $mybusinessService->accounts_locations_reviews;
$listReviewsResponse = $reviews->listAccountsLocationsReviews($location->name);
$reviewsList = $listReviewsResponse->getReviews();
var_dump('$reviewsList', $reviewsList);
}
}
}
I expected the Location of my business (also the reviews, but it a next step), but I just got the empty Location list.
Finally, I got success using the ClientId/ClientSecret keys together with Refresh Token previously received on Google OAuth 2 Playground on the first time that I give permission to (my) App, instead "Service Account" authentication way :)
$client = new Google_Client();
$client->setClientId($clientId);
$client->setClientSecret($clientSecret);
$client->addScope("https://www.googleapis.com/auth/plus.business.manage");
$client->setSubject('my email user on GMB');
$client->refreshToken(' ###### ')
Now I got all the needed data for my application.

Cannot add to another users calendar

I am attempting to allow a user add items to the calendars of other users.
A user logs in and get the token as follows
const AUTHORIZE_ENDPOINT = '/oauth2/v2.0/authorize';
const TOKEN_ENDPOINT = '/oauth2/v2.0/token';
const SCOPES = 'profile openid email User.Read Calendars.ReadWrite Calendars.Read Calendars.Read.Shared Calendars.ReadWrite Calendars.ReadWrite.Shared';
$graph = new Graph();
$graph->setAccessToken($token);
$response = $graph->createRequest("GET", "/me")->setReturnType(Model\User::class)->execute();
The logged in user can add to their own calendar using
$request = $graph->createRequest("post", '/me/events');
$request->attachBody($data);
$response = $request->execute();
But, when I try to add to another user with
$request = $graph->createRequest("post", '/anotheruser/events');
$request->attachBody($data);
$response = $request->execute();
I get the message
Resource not found for the segment
Have done the admin auth consent, so all should be fine.
Any suggestions?
If you want to access another user's data you have to use the following url:
/users/{id | userPrincipalName}
Your request was just in the wrong form and you ended up sending a request to an non existing resource, thus Graph didn't know what to do.
In your case you just need to prepend /users (for more information see documentation).
So your request could look like this:
$request = $graph->createRequest("post", '/users/anotheruser/events');
Keep in mind that if you are logged in as a user (token on behalf of a user), the calendar you try to access to must have been shared with the logged in user. Otherwise it will fail due to missing privileges as Graph only allows to edit Calendars that are shared with the user. You also need the Permissions Calendars.Read.Shared and/or Calendars.ReadWrite.Shared (which you seem to already have aquired).
Calendar sharing is unnecessary if you gain access without a user as you then automatically have full access to all users.
Currently the Graph API only supports access to shared Calendars but no operations to edit/change the sharing status or see which Calendars are shared with a user. However you can change the sharing status manually over outlook or the powershell.
Url should be something like Users('anotheruser')/events. Since you are directly saying anotheruser/events. The service is not recognizing another user as a valid segment and throwing the error.

Calling a google apps script execution api from PHP using a service account

I'm trying to call a very simple google apps script from php using a service account so that only my server can access it, not users of the website.
Here is how I do. I create the script here https://script.google.com
function get() {
return ContentService.createTextOutput('get method');
}
and a new project is automatically associated when i save it.
Then I open File > Project Properties to get the scriptId = MM8zQqofS1OIcnFiNSlm1CGEl5qMrMVBt
I access the developer console of the associated project threw Resources > Project Developers console by clicking on the project link at the top of the popup displayed.
Then I click 'Activate and manage API' and activate the 'Google Apps Script Execution API'. I click on 'Credentials' and see that the previous operation automatically created OAuth2 credentials. But what I need is service account credentials. Then I create one Add credentials > Service account and download generated p12 file. I get the clientId = 109160023321840004240 and clientMail = account-1#project-id-uokwrcpiqeewhwvpdhb.iam.gserviceaccount.com for this service account.
I go back to my script and share it with the service account email with read&write access File > Share. First of all i get an email in my personal mailbox which notifies me that
Delivery to the following recipient failed permanently:
account-1#project-id-uokwrcpiqeewhwvpdhb.iam.gserviceaccount.com
Then I publish the script as an execution API Publish > Publish as an execution API with access to everybody.
Now lets go on the PHP server side. Using the 'Google APIs Client Library for PHP' available here https://github.com/google/google-api-php-client I try to call my script function from PHP:
$client = new Google_Client();
$client->setClientId('109160023321840004240');
$client->setApplicationName('myScript');
$cred = new Google_Auth_AssertionCredentials(
'account-1#project-id-okwrcpiqeewhwvpdhb.iam.gserviceaccount.com',
[/*no scope nedeed for this simple script*/],
file_get_contents('path_to_myScript.p12')
);
$client->setAssertionCredentials($cred);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
$service = new Google_Service_Script($client);
$scriptId = 'MM8zQqofS1OIcnFiNSlm1CGEl5qMrMVBt';
// Create an execution request object.
$request = new Google_Service_Script_ExecutionRequest();
$request->setFunction('get');
$response = $service->scripts->run($scriptId, $request);
And here is the response I get all the time
Error calling POST https://script.googleapis.com/v1/scripts/MM8zQqofS1OIcnFiNSlm1CGEl5qMrMVBt:run: (403) The caller does not have permission
If, when I deploy the script, I choose to give access to 'Me only', i get the following response.
Error calling POST https://script.googleapis.com/v1/scripts/MM8zQqofS1OIcnFiNSlm1CGEl5qMrMVBt:run: (404) Requested entity was not found.
I would be so happy if one of you have an idea to help me :)
apps script does not yet support service accounts with execution api. see https://code.google.com/p/google-apps-script-issues/issues/detail?id=5461
google said they are looking into it but apparently wont happen soon (based on google replies on google+ posts about this like https://plus.google.com/+MartinHawksey/posts/Zquix9XqzkK)

AdSense Management API - Missing required parameter: redirect_uri With Service Account

I am getting the following Error when trying to connect with the AdSense Management API Example:
Missing required parameter: redirect_uri
I am using a service Account, because my Server handles all the interaction between the adSense api. The user is not involved. Here is my PHP Code:
$client = new Google_Client();
$client->setApplicationName("PeopleHelpingPeople"); // name of your app
// set assertion credentials
$client->setAssertionCredentials(
new Google_Auth_AssertionCredentials(
"...",
array('https://www.googleapis.com/auth/analytics.readonly'),
file_get_contents('client_data.json') // keyfile you downloaded
));
$client->setScopes(array(
'https://www.googleapis.com/auth/analytics.readonly'
));
$client->setClientId("..."); // from API console
$client->setAccessType('offline_access'); // this may be unnecessary?
// Create service.
$service = new Google_Service_AdSense($client);
Why am I getting this Error?
If you are trying to use a ServiceAccount from the developers console, the kind of account that gives you a p12 file, those will not work with Adsense.
Take a look at the note on this page https://developers.google.com/adsense/management/getting_started
$client->setRedirectUri() may get you past this error but it wont solve your ultimate issue

Categories