Another USER_PERMISSION_DENIED code 7

215 views
Skip to first unread message

effective world

unread,
Jun 26, 2023, 12:46:18 PM6/26/23
to Google Ads API and AdWords API Forum
Hi
I'm trying to replicate the GetAccountHieararchy.php example on my Laravel application and I keep getting this aparently very common permissions error but I can't see whats the problem:

{ "message": "The caller does not have permission", "code": 7, "status": "PERMISSION_DENIED", "details": [ { "@type": "type.googleapis.com\/google.ads.googleads.v13.errors.GoogleAdsFailure", "errors": [ { "errorCode": { "authorizationError": "USER_PERMISSION_DENIED" }, "message": "User doesn't have permission to access customer. Note: If you're accessing a client customer, the manager's customer id must be set in the 'login-customer-id' header. See https:\/\/developers.google.com\/google-ads\/api\/docs\/concepts\/call-structure#cid" } ], "requestId": "HvUJs9KXJuoUXsX1rySSZg" } ] }

Using a refresh token generated with the playground app and then placing it in th google_ads_php.ini works.
But it doesn't with my implementation of the oauth2 login
Is there something wrong or missing here? I see in the playground some parameters in the first step that I don't see here. This is not my implementation I'm just looking to understand and fix the permissions issue here.
class MCCHierarchy
{

public function all()
{
$efGoogleAds = new EfGoogleAds();
return $this->createCustomerClientHierarchy($efGoogleAds);
}

private function createCustomerClientHierarchy(EfGoogleAds $efGoogleAds)
{

// First, fetch the list of accessible customers
$outputArray = $this->getAccessibleCustomers($efGoogleAds->getGoogleAdsClient());

$selects = ['customer_client.client_customer', 'customer_client.level', 'customer_client.manager', 'customer_client.descriptive_name', 'customer_client.currency_code', 'customer_client.time_zone', 'customer_client.id', 'customer_client.status'];
$wheres = [
['customer_client.level', '= 1'],
['customer_client.status', '= "ENABLED"'],
['customer_client.manager', '= true']
];

// Now, we fetch subClients againsts each customer
foreach ($outputArray as $key => $mccClient) {
try{
$subAccountsStreamReport = new StreamReportGoogleAds('customer_client', $efGoogleAds->serviceClient, intval($mccClient['clientId']), $selects, $wheres, '');
}catch(\Google\ApiCore\ApiException $e){
Log::error('Client id failing: '.$mccClient['clientId']);
if (isset($e->getMetadata()[0]["errors"][0]["errorCode"]["authorizationError"]) && $e->getMetadata()[0]["errors"][0]["errorCode"]["authorizationError"] === 'CUSTOMER_NOT_ENABLED') {
// The customer account can't be accessed because it is not yet enabled or has been deactivated.
// You may want to log this or handle differently in your application.
continue;
} else {
throw $e;
}
}
$subClientArray = [];
$subClientIdsArray = [];
try{
foreach ($subAccountsStreamReport->stream->iterateAllElements() as $subAccount) {
$customerClient = $subAccount->getCustomerClient();
$subClientArray[] = [
'clientName' => $customerClient->getDescriptiveName(),
'clientId' => $customerClient->getId(),
'manager' => $customerClient->getManager(),
'clientStatus' => CustomerStatus::name($customerClient->getStatus())
];
$subClientIdsArray[] = [
"subClientName" => $customerClient->getDescriptiveName(),
"subClientId" => $customerClient->getId()
];
}
}catch(\Google\Ads\GoogleAds\Lib\V13\GoogleAdsException $e){
Log::error('Client id failing in second loop: '.$mccClient['clientId']);
throw $e;
}
$outputArray[$key]['subClients'] = $subClientArray;
$outputArray[$key]['subClientsIds'] = json_encode($subClientIdsArray);
}
//dd($outputArray);
return $outputArray;
}
/**
* Retrieves a list of accessible customers with the provided set up credentials.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @return int[] the list of customer IDs
*/
private function getAccessibleCustomers(GoogleAdsClient $googleAdsClient): array
{
$outputArray = [];
// Issues a request for listing all customers accessible by this authenticated Google
// account.
$customerServiceClient = $googleAdsClient->getCustomerServiceClient();
$accessibleCustomers = $customerServiceClient->listAccessibleCustomers(['customer.status' => 'ENABLED']);
foreach ($accessibleCustomers->getResourceNames() as $customerResourceName) {
$customer = CustomerServiceClient::parseName($customerResourceName)['customer_id'];
$outputArray[] = [
'clientName' => $customerResourceName,
'clientId' => intval($customer),
];
}

return $outputArray;
}

class GoogleAuthController extends Controller
{
private $client;

public function __construct()
{
$this->client = new Google_Client();
$this->client->setClientId(env('GOOGLE_ADS_CLIENT_ID'));
$this->client->setClientSecret(env('GOOGLE_ADS_CLIENT_SECRET'));
$this->client->setRedirectUri(env('GOOGLE_ADS_REDIRECT_URI'));
$this->client->addScope('https://www.googleapis.com/auth/adwords');
}

public function login()
{
$authUrl = $this->client->createAuthUrl();
return redirect($authUrl);
}

public function callback(Request $request)
{
if (!$request->has('code')) {
return redirect()->route('login')->withErrors('Authorization failed.');
}
$accessToken = $this->client->fetchAccessTokenWithAuthCode($request->get('code'));
session([
'google_ads_access_token' => $accessToken
]);
return redirect()->route('keywordurls');
}

public function logout()
{
session()->forget('google_ads_access_token');
return redirect()->route('login');
}
}

class EfGoogleAds
{

public $serviceClient = null;
public $fieldServiceClient = null;
private GoogleAdsClient $googleAdsClient;
public function __construct()
{
$this->setGoogleAdsClient();
$this->serviceClient = $this->googleAdsClient->getGoogleAdsServiceClient();
$this->fieldServiceClient = $this->googleAdsClient->getGoogleAdsFieldServiceClient();
}

private function setGoogleAdsClient()
{
$oAuth2Credential = (new OAuth2TokenBuilder())
->withClientId(env('GOOGLE_ADS_CLIENT_ID'))
->withClientSecret(env('GOOGLE_ADS_CLIENT_SECRET'))
->withRefreshToken(session('google_ads_access_token')['access_token']) // Use the stored refresh token
->build();

$this->googleAdsClient = (new GoogleAdsClientBuilder())
->withDeveloperToken(env('GOOGLE_ADS_DEVELOPER_TOKEN'))
->withOAuth2Credential($oAuth2Credential)
->build();
}

public function getGoogleAdsClient(): GoogleAdsClient{
return $this->googleAdsClient;
}
}

Google Ads API Forum Advisor

unread,
Jun 27, 2023, 9:16:35 AM6/27/23
to m...@effective-world.com, adwor...@googlegroups.com

Hi,

Thank you for reaching out to Google Ads API Forum.

I can see that you've already raised this same concern in another thread with the subject Yet another PERMISSION_DENIED question. We have already replied to the other thread. For better tracking of the issue, kindly continue discussion only in a single thread instead. 

To reiterate, it appears that you've encountered the USER_PERMISSION_DENIED error which occurs when the authorized customer does not have access to the operating customer. This is an authorization error (https://developers.google.com/google-ads/api/docs/best-practices/common-errors#authorizationerror) and its common cause is when authenticating as a user with access to a manager account but not specifying login-customer-id in the request. It also occurs when the OAuth2 credentials (https://developers.google.com/google-ads/api/docs/oauth/cloud-project) you are using were generated by a user / email address that does not have access (https://support.google.com/google-ads/answer/9978556?visit_id=638028230738600037-122357065&rd=1) to the account (customer_id) specified in your request. You can manage user access by referring to this article (https://support.google.com/google-ads/answer/6372672).

If the issue persists even after doing the above details, you may send us the below complete API logs generated on your end and the user / email address that you used in your authentication process for further investigation.

You may then send the requested logs via the Reply privately to author option. If this option is not available, you may send the details directly to our googleadsa...@google.com alias instead.

 
This message is in relation to case "ref:_00D1U1174p._5004Q2mXeYq:ref"

Thanks,
 
Google Logo Google Ads API Team


Reply all
Reply to author
Forward
Message has been deleted
0 new messages