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
Related
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
Hello fellow developers,
I am working with a friend on a Search Console Application. We are using Laravel and google/apiclient package.
I did implement the login with google with authenticating with OAuth2, and all workes fine.
The main issue here is that when i query search console i was able to get some websites data, but for some reasons for other websites i get this error.
Google\Service\Exception: {
"error": {
"code": 403,
"message": "User does not have sufficient permission for site 'https://example-site.com'. See also: https://support.google.com/webmasters/answer/2451999.",
"errors": [
{
"message": "User does not have sufficient permission for site 'https://examplesite.com'. See also: https://support.google.com/webmasters/answer/2451999.",
"domain": "global",
"reason": "forbidden"
}
]
}
}
https://example-site.com i used my real website.
Here are the steps that i did:
I created a project in google cloud api, activate the google search console api, i have project permission as owner, i got the credentials in json format.
In Laravel i implemented the apis (Controller and Api Routes) for google authentications(code exchange), refresh token , etc.
I also set the scope like this.
$client->setScopes(
[
\Google\Service\Oauth2::USERINFO_PROFILE,
\Google\Service\Oauth2::USERINFO_EMAIL,
\Google\Service\Oauth2::OPENID,
\Google\Service\SearchConsole::WEBMASTERS
]
);
This is the method that i used to query Analitics
public function getSearchConsoleData(Request $request)
{
$client = GoogleController::getUserClient();
$service = new \Google\Service\Webmasters($client);
$request = new \Google\Service\Webmasters\SearchAnalyticsQueryRequest;
$request->setStartRow(0);
$request->setStartDate('2022-11-01');
$request->setEndDate('2022-11-15');
$request->setSearchType('web');
$request->setDimensions(array('query','country','device','country','device',));
$query_search = $service->searchanalytics->query("https://website-that-i-own.com", $request);
$rows = $query_search->getRows();
return $rows;
}
All the site are verified, i did check in Search Console Site.
I also searched online, looked at documentation from google search console api, google api issue forum.
All the site are verified, i did check in Search Console Site.
I also searched online, looked at documentation from google search console api, google api issue forum.
Please let me know what i missed here.
Thank you so much for you help in advance.
Issue
I'm trying to build an app to integrate with the Microsoft Graph API.
I have an admin account in Azure, and have set up a new app through the portal.
I've downloaded and installed the PHP SDK, and have managed to set everything up so that I can get a user successfully.
I can sign into the app and grant permissions to use my information (the permission I'm requesting is Directory.ReadWrite.All, but even just requesting User.ReadWrite.All is not working for me), however, my issue seems to be that I cannot access other users.
The following only returns my own user:
$graph = new Graph();
$graph->setAccessToken('/* SOMETOKEN */');
$users = $graph->createRequest('GET', '/users')
->setReturnType(User::class)
->execute();
POSTing a new user returns me a 404 error:
$newUser = new User();
$newUser->setAccountEnabled(true);
$newUser->setGivenName('first_name');
$newUser->setSurname('last_name');
$newUser->setUserPrincipalName('some.email#address.com');
$password = new PasswordProfile();
$password->setPassword('some_password');
$newUser->setPasswordProfile($password);
$user = $graph->createRequest('POST', '/users')
->attachBody($newUser)
->execute();
Returns:
{
"error": {
"code": "",
"message": "No HTTP resource was found that matches the request URI 'https://outlook.office365.com:444/profile/v1.0/users('CID:a8ef4446a149de4d')/profile?api-version=AGSV1-internal'.",
"innerError": {
"date": "/* timestamp */",
"request-id": "/* an id */",
"client-request-id": "/* an id */"
}
}
}
Even trying to use Microsoft's Graph Explorer is getting these same errors.
Am I right in thinking this could be an account setup issue?
Update
Here is the error message the Graph Explorer is returning
{
"error": {
"code": "",
"message": "No HTTP resource was found that matches the request URI 'https://outlook.office365.com:444/profile/v1.0/users('CID:a8ef4446a149de4d')/profile?api-version=AGSV1-internal'.",
"innerError": {
"date": "2020-11-30T16:51:41",
"request-id": "743030b4-8835-4a9f-9e3e-d35919a1c289",
"client-request-id": "c40cd440-d873-ba38-dce7-8669bc561e64"
}
}
}
I have resolved this.
Issue
The issue was in the permission request.
My app was set up to allow personal accounts as well as work/school ones.
Logging in with a personal account, my user was not able to grant the *.ReadWrite or *.All permissions.
While I was getting a token back from the auth request, it only had the User.Read permission.
Steps needed to get access to all users working
Change the app in Azure to only accept work/school accounts
When my app tries to authenticate, I needed to log in with a work/school account
Granting the permissions for User.Read.All should now work
Hitting the /users endpoint should return all users
To get write working, I needed to register for a Partner Center MPN ID and associate that with my app in Azure.
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.
When I'm using Google API v2, to get an inapp listing, I'm getting the following error when I'm making the API call:
{
"error": {
"errors": [
{
"domain": "androidpublisher",
"reason": "projectNotLinked",
"message": "The project id used to call the Google Play Developer API has not been linked in the Google Play Developer Console."
}
],
"code": 403,
"message": "The project id used to call the Google Play Developer API has not been linked in the Google Play Developer Console."
}
}
I then researched this error and ended up seeing the suggestions on this page, this page, and on this page as well. I followed and double-checked the way the projects get linked there but it did not help.
This is what I did...
In Google Developer Console:
Used an existing project.
Went to APIs & auth > APIs.
Ensured "Google Play Android Developer API" was turned ON.
Used my existing credentials for CLIENT ID, CLIENT SECRET, and REDIRECT URIS. Application type was "native application".
Created an API KEY as well, but did not use it.
In Google Play Developer Console:
Went to SETTINGS > API access.
Under LINKED PROJECT, I ensured the above project from the Google Developer Console was linked.
In my PHP script:
<?php
require_once('/var/www/html/common/include.php');
require_once realpath(dirname(__FILE__) . '/lib/Google/autoload.php');
$refreshToken = '1/sometoken';
$packageName = 'com.somepackage';
$client_id = GOOGLE_CLIENT_ID;
$client_secret = GOOGLE_CLIENT_SECRET;
$redirect_uri = 'http://localhost';
$client = new Google_Client();
$client->setClientId($client_id);
$client->setClientSecret($client_secret);
$client->setRedirectUri($redirect_uri);
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
$client->setScopes(['https://www.googleapis.com/auth/androidpublisher']);
$client->refreshToken($refreshToken);
$service = new Google_Service_AndroidPublisher($client);
$response = $service->inappproducts->listInappproducts($packageName);
var_dump($service);
Which led to the above error.
Any other suggestions to resolve this error with using refresh tokens?
Hey I was having a similar issue as you, I figured out the problem was I was the authenticating a user did not have the right permissions.
First go into your Google Play Console, go under Settings> API Access. Make sure that you have a linked "Google Play Android Developer" (which is sounds like you do and I did as well).
Next go into Settings>User Accounts and Rights, make sure the user has the proper rights to view subscriptions or whatever you need it to. For testing purposes just give it all the rights.
Then make sure to Authenticate this user via Oauth(ie select their email from the list) and then get typical refresh/access token
Really seems so painfully obvious to me now, but it still took a day of frustration. I hope this solves your issue :)