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

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.

Related

Service Account Domain Delegation unauthorized_client

I am trying to use service account with domain delegation so I can automate some tasks of google classroom via cron. For this I need service account with domain delegation.
I am working and struggling in it for 3 days. I have properly read documentation so many times. You can imagine the 3 days research. Now I am getting exhaust and finally come here in the hope.
I am using php library provided by google for google classroom.
https://github.com/googleapis/google-api-php-client
I am getting this error
Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested.
Which means in google documentation enter image description here
I tried that several times but still getting this errror.
Here is my php code
require_once plugin_dir_path(__FILE__).'../../xf-google-classroom/vendor/autoload.php';
$this->scopes = [
Google_Service_Classroom::CLASSROOM_COURSES,
//Google_Service_Classroom::CLASSROOM_ROSTERS,
//Google_Service_Classroom::CLASSROOM_COURSES_READONLY,
//Google_Service_Classroom::CLASSROOM_COURSEWORK_ME,
//Google_Service_Classroom::CLASSROOM_COURSEWORK_ME_READONLY,
//Google_Service_Classroom::CLASSROOM_COURSEWORK_STUDENTS,
Google_Service_Classroom::CLASSROOM_COURSEWORK_STUDENTS_READONLY,
//Google_Service_Classroom::CLASSROOM_PROFILE_EMAILS,
];
$this->credentials = plugin_dir_path(__FILE__) . '/sufi-new-2.json';
//$this->redirect_uri = site_url( 'wp-admin/admin.php?page=bp-groups' );
$this->client = new Google_Client();
//$this->client->useApplicationDefaultCredentials();
$jsonKey = [
"type"=> "service_account",
"project_id"=> "edufix-upgraded",
"client_email"=> "newsufyan#edufix-upgraded.iam.gserviceaccount.com",
"client_id"=> "115746479435703189142",
"auth_uri"=> "https://accounts.google.com/o/oauth2/auth",
"token_uri"=> "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url"=> "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url"=> "https://www.googleapis.com/robot/v1/metadata/x509/newsufyan%40edufix-upgraded.iam.gserviceaccount.com"
];
$this->client->setAuthConfig( $jsonKey );
$this->client->setSubject('clases#krugerschool.edu.ec');
//$this->client->setRedirectUri( $this->redirect_uri );
$this->client->addScope( $this->scopes );
$this->client->setAccessType( 'offline' );
Let me tell you that my OAuth2 authentication with conscent screen application is working good on frontend for users. I am not able to run my cron scripts because of this domain delegation.
Also my OAuth Consent screen is in test mode and I have added test users in it. And working good with users on frontend with consent screen.
Also I always generate new key after any new changes and deploy that new credentials as well everytime. I tried to remove and add again with client id and proper scopes and domain delegation again and again but not working.
Also I have added that my administrator account in service account and grant access to owner. But not not worked.
Kindly help
I am trying to solve my problem and expecting a poper solution

Google Ads Api Developer Token Error - even though it is validated

I am developing an application which integrates with Google Ads and syncing Ad/Campaign etc. data into my servers. I am getting authorization related error when I try to request some data from Google Ads API. Here is the steps I have done by now:
Applied to Google in terms of validating an OAuth application and scopes (Done, we got verification from Google and can ask for AdWords scope)
Applied to Google Ads for getting a developer token and got it. (Basic Access)
We are able to connect test accounts and successfully getting the response. But when we try it with real accounts we get the error below.
The code is also from the original Google Ads API example. I have tried with tons of different accounts but none of them seems to be working. When I try to obtain those data with same parameters from AdWords API instead of Google Ads API, it works. But Google AdWords PHP SDK is no longer maintained so I have to keep trying with Google Ads API. I share my code below:
{
$this->customerId = $customerId;
$this->clientId = $clientId;
$this->clientSecret = $clientSecret;
$this->accessToken = $accessToken;
$oAuth2Credential = (new OAuth2TokenBuilder())
->withClientId($this->clientId)
->withClientSecret($this->clientSecret)
->withRefreshToken($this->accessToken)
->build();
$this->googleAdsClient = (new GoogleAdsClientBuilder())
->withOAuth2Credential($oAuth2Credential)
->withDeveloperToken(env("GOOGLE_DEVELOPER_TOKEN"))
->withLoginCustomerId((int) $this->customerId)
->build();
}
public function getCampaigns(): array
{
try {
$campaigns = [];
$services = $this->googleAdsClient->getGoogleAdsServiceClient();
$results = $services->search($this->customerId, $this->campaignQuery(), ['pageSize' => self::PAGE_SIZE]);
foreach ($results->iterateAllElements() as $row) {
$campaigns[] = (new Campaign())->transform($row);
}
return $campaigns;
} catch (GoogleAdsException $googleAdsException) {
// TODO add error log
return [];
}
}```
The error:
```Google\ApiCore\ApiException: {
"message": "The caller does not have permission",
"code": 7,
"status": "PERMISSION_DENIED",
"details": [
{
"#type": 0,
"data": "type.googleapis.com\/google.ads.googleads.v6.errors.GoogleAdsFailure"
},
{
"#type": 0,
"data": [
{
"errorCode": {
"authorizationError": "DEVELOPER_TOKEN_PROHIBITED"
},
"message": "Developer token is not allowed with project '691752477594'."
}
]
}
]}```
Are you using the same cloud console project credentials for the login on your site as you are for the API calls?
The very first call to the Google Ads API permanently associates a developer token to a cloud project. If this is different to the one you're using on your site, you may have to switch them.
some developer token is already associated with project that you are trying with,
to resolve this You have to create one more App project in console and re configure your secrate key, and client id with new project that you have created dont forget to use the latest developer token i.e (your current developer token) and make a first API call, then your developer token will get paired forever, once it get bound it will never be changed later on.
As said before you need to create a new google cloud project, this is related with how Google organises users through their products.
If you are a company that is advertising through Google Ads, Google wants you to organise all your campaigns under a single master user account. That master user account should have a single developer token which you use within the Google Cloud Project associated to the same company.
For Google you should not have multiple master user accounts for the same company and therefore multiple developer tokens.
Of course there are edge cases that do not fit this rule, like advertising agencies however there is not a large incentive for Google to change this.
You can follow this thread for updates, but I do not expect things to change any time soon, https://groups.google.com/g/adwords-api/c/O8_y2xt0nGo

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)

{ "error" : "invalid_grant" } error with Google Directory API PHP Client SDK

So I am trying all day already and I just can't seem to correctly authenticate to the google API. This is what I did to set up a connection so far:
I first created a service account for my application
Then I added that service account in the third party client access settings on the admin page for our Google Apps domain. I added the scopes for users and groups
I generated a new Client ID for web applications
I downloaded the .p12 file, the secret JSON file for my web Client ID and stored them locally
So I think that's all I need to succesfully authenticate.. I then used the following code to set everything up:
$this->client = new Google_Client();
$this->client->setAuthConfigFile(STORAGE_PATH.'client_secrets.json');
$this->client->addScope(static::$scopes);
$cred = new Google_Auth_AssertionCredentials(
static::$service_account_email,
static::$scopes,
file_get_contents(STORAGE_PATH.'TRICS-key.p12'));
$cred->sub = static::$delegated_admin;
$this->client->setAssertionCredentials($cred);
$this->directory_service = new Google_Service_Directory($this->client);
Does someone know if I am forgetting something?
Oops. I was a fool. I accidentally used the email of the Web Client instead of the service account email. :') The rest of the code seems to function as it should.

Connecting to the Google Sites API as a "Service Account"

I am trying to read a feed from a Google Sites account (Google apps).
I don't need my app to require every user to login so i created my ClientID as a "Service Account" in the "Google API console".
I have added this Client ID and the scope (https://sites.google.com/feeds/) to the "Mange API client access" page in my google apps control panel.
I connect using the code below, all constants are defined in my code with the right values.
// api dependencies
require_once(GOOGLE_API_PATH);
// create client object and set app name
$client = new Google_Client();
$client->setApplicationName(GOOGLE_API_NAME);
// set assertion credentials
$client->setAssertionCredentials(
new Google_AssertionCredentials(
GOOGLE_API_EMAIL,
array(GOOGLE_API_SCOPE),
file_get_contents(GOOGLE_API_PK)
));
$client->setClientId(GOOGLE_API_CLIENTID);
// create service
$req = new Google_HttpRequest("https://sites.google.com/feeds/content/<herismydomainname.com>/intranet");
$val = $client->getIo()->authenticatedRequest($req);
// The contacts api only returns XML responses.
$response = json_encode($val->getResponseBody());
print "<pre>" . print_r(json_decode($response, true), true) . "</pre>";
The response i get is "Not authorized to access this feed "
When i try to get this feed in the OAuth2.0 playground logging in using my google apps account i get the expected response.
What am i overlooking here?
Service accounts and Google Sites can't be used together currently. Google Apps provides a consumer secret that can be used to access data across your domain as Two-Legged OAuth within OAuth 1.0a.
Check out http://support.google.com/a/bin/answer.py?hl=en&answer=162105 for how to configure your Apps account, and the sample code at https://developers.google.com/gdata/docs/auth/oauth#2LeggedOAuth.

Categories