How to authenticate anyone ADWORDS API OAuth2 PHP

1,814 views
Skip to first unread message

Christian Gibbs

unread,
Nov 14, 2013, 11:38:30 AM11/14/13
to adwor...@googlegroups.com
I keep getting, AuthorizationError.USER_PERMISSION_DENIED

What is the point of them logging in, if you need to get their permission again.

I want anyone to be able to access their adwords account, via our platform. Like so many other apps and websites do.

I have refresh tokens and I can access my own account just fine, but with other account logins, I get this error AuthorizationError.USER_PERMISSION_DENIED

It make the app pointless, if I have to manually add ever client in and then allow them to login.

So many apps allow this kind of access. How is it possible?

I made a google app, that has a google login authorization prompt screen, then once the user consents, the login is successful but I can not access their data.

Im stuck in a circle and its driving me crazy. Please HELP!


Christian Gibbs

unread,
Nov 14, 2013, 2:19:46 PM11/14/13
to adwor...@googlegroups.com
My code is as follows:

 ////AUTH PAGE

               $clientId = "PROVIDED_HIDDEN";
$clientSecret = "PROVIDED_HIDDEN";
$access = "PROVIDED_HIDDEN";
$refresh = "PROVIDED_HIDDEN";
$callbackUrl = base_url().index_page()."google/authCallback";
 
// Create a new user and set the oAuth settings
$user = new AdWordsUser();
$user->SetOAuth2Info(array(
   "client_id" => $clientId,
   "client_secret" => $clientSecret,
   "access_token" => $access,
   "refresh_token" => $refresh
));
 
// Generate an authorization URL given the callback URL
$authUrl = $user->GetOAuth2AuthorizationUrl($callbackUrl, true);
 
header("Location: $authUrl");

    

////////CALL BACK URL PAGE 

                $clientId = "PROVIDED_HIDDEN";
$clientSecret = "PROVIDED_HIDDEN";
$access = "PROVIDED_HIDDEN";
$refresh = "PROVIDED_HIDDEN";

// Create a new user and set the oAuth settings
$user = new AdWordsUser();
$user->SetDeveloperToken(ADWORDS_DEV_TOKEN);
$user->SetClientCustomerId(ADWORDS_ACCOUNT_ID);
 
$user->SetOAuth2Info(array(
   "client_id" => $clientId,
   "client_secret" => $clientSecret,
   "access_token" => $access,
   "refresh_token" => $refresh
));
$authCode = $_REQUEST["code"];
echo "<pre>";
$token = $user->GetOAuth2AccessToken($authCode, $callbackUrl);
 
$oauth2Info = $user->GetOAuth2Info();
print "OAuth2 authorization successful.\n";
 
if($user->CanRefreshOAuth2AccessToken())    /// <----  is returning true
echo "CAN REFRESH";
else
echo "CAN NOT REFRESH";

//// NEXT URL TO ACCESS CAMPAIGNS

              $tokenFilename = "./application/tmpAuth/". session_id() .".txt";
 
// Create a new user
$user = new AdWordsUser();
 
// Load the oAuth settings
$user->SetOAuth2Info($this->Google_model->loadAuth($tokenFilename));
//$user->RefreshOAuth2AccessToken();
//$this->Google_model->saveAuth($user, $tokenFilename);
 
echo "<pre>";
//print_r($user); 
 
// Get a list of campaigns
//$camps = $this->Google_model->GetCampaignsExample($user);
$campaignService = $user->GetService('CampaignService', ADWORDS_VERSION);
FAILS HERE
AuthorizationError.USER_PERMISSION_DENIED

Christian Gibbs

unread,
Nov 15, 2013, 10:53:28 AM11/15/13
to adwor...@googlegroups.com
My specific error is

Fatal error: Uncaught SoapFault exception: [soap:Server] [AuthorizationError.USER_PERMISSION_DENIED @ ; trigger:''] in /var/www/html/dev/application/libraries/src/Google/Api/Ads/Common/Lib/AdsSoapClient.php:201
Stack trace:
#0 /var/www/html/dev/application/libraries/src/Google/Api/Ads/Common/Lib/AdsSoapClient.php(201): SoapClient->__soapCall('get', Array, NULL, Array, Array)
#1 /var/www/html/dev/application/libraries/src/Google/Api/Ads/AdWords/v201306/CampaignService.php(6454): AdsSoapClient->__soapCall('get', Array)
#2 /var/www/html/dev/application/controllers/google.php(216): CampaignService->get(Object(Selector))
#3 [internal function]: Google->accessAuth()
#4 /var/www/html/dev/system/core/CodeIgniter.php(359): call_user_func_array(Array, Array)
#5 /var/www/html/dev/index.php(206): require_once('/var/www/html/d...')
#6 {main}
  thrown in /var/www/html/dev/application/libraries/src/Google/Api/Ads/Common/Lib/AdsSoapClient.php on line 201



On Thursday, November 14, 2013 11:38:30 AM UTC-5, Christian Gibbs wrote:

Paul Matthews (AdWords API Team)

unread,
Nov 25, 2013, 7:08:56 AM11/25/13
to adwor...@googlegroups.com
Hi Christian,

Firstly, when you authenticate the user, you need to ensure you include scope=offline, otherwise you'll need the user to be present for all requests.

Secondly, it seems as though you're not using the most recent version of the php client library, as we've moved many of the OAuth2 methods out of the AdWordsUser class to the OAuth2Handler class.

Thirdly, you'd need to ensure you've registered the callback URL you supply, when you retrieve the access code.

Finally & Most likely: there's no link between the authorized MCC and the account you're attempting to retrieve campaigns for. The error code you're receiving is mostly connected to this error. The OAuth2 flow only authorizes your access to an account, that account needs to be linked to all other accounts it wishes to access.

Regards,

- Paul, AdWords API Team.

Christian Gibbs

unread,
Nov 27, 2013, 3:15:08 PM11/27/13
to adwor...@googlegroups.com
Ok I will revisit this based on your info.

The URL is registered.

Ill use the new OAuth2Handler , thank you.

But this works, when I use my MCC login.

But what is the point of the person going to the login page and give authorization using OAuth?

Why have them authenticate and give permission if I already have access? They have already given permission prior to this event.

How do other companies allow access. For example, if I download the AdStage app I can login to my ADwords account and look at my data.

This is what I want to achieve.

Thank you

Ilya steem

unread,
Nov 28, 2013, 2:37:28 AM11/28/13
to adwor...@googlegroups.com
Can be conflict $refresh & ADWORDS_ACCOUNT_ID ?

четверг, 28 ноября 2013 г., 0:15:08 UTC+4 пользователь Christian Gibbs написал:

Christian Gibbs

unread,
Dec 9, 2013, 9:33:34 AM12/9/13
to adwor...@googlegroups.com
Google, can you respond to my question?




On Monday, November 25, 2013 7:08:56 AM UTC-5, Paul Matthews (AdWords API Team) wrote:

Christian Gibbs

unread,
Dec 9, 2013, 9:54:38 AM12/9/13
to adwor...@googlegroups.com
Can someone please respond to my questions.

Your explanation is like a catch22.


On Monday, November 25, 2013 7:08:56 AM UTC-5, Paul Matthews (AdWords API Team) wrote:

Derrick Pelletier

unread,
Dec 9, 2013, 12:29:29 PM12/9/13
to adwor...@googlegroups.com
Christian, you might be referring to an old feature, which is being deprecated; it allowed you to capture an email/password to authorize with.

Christian Gibbs

unread,
Dec 9, 2013, 6:21:48 PM12/9/13
to adwor...@googlegroups.com
Im using OAUTH2 and Ive done many  changes today.

This is what Im getting now.

[message:protected] => [AuthenticationError.OAUTH_TOKEN_INVALID @ ; trigger:'']

Christian Gibbs

unread,
Dec 9, 2013, 6:32:19 PM12/9/13
to adwor...@googlegroups.com
This is the new favorite thing its doing now.


Uncaught exception 'OAuth2Exception' with message '{ "error" : "invalid_request" }'

Christian Gibbs

unread,
Dec 9, 2013, 6:43:19 PM12/9/13
to adwor...@googlegroups.com
Now I am back to here,


[message:protected] => [AuthorizationError.USER_PERMISSION_DENIED @ ; trigger:'']

Paul Matthews (AdWords API Team)

unread,
Dec 10, 2013, 10:44:13 AM12/10/13
to adwor...@googlegroups.com
Hi Christian,

When you say you've done many changes, what kind of changes? Are you able to get authentication working as per the screencast? Using the video is the easiest way to get the authentication working.

The USER_PERMISSION_DENIED is served when you're attempting to access an unlinked account.

Regards,

- Paul, AdWords API Team.

Christian Gibbs

unread,
Dec 10, 2013, 11:30:26 AM12/10/13
to adwor...@googlegroups.com
I updated everything over like you said with the OAuthHandler class.

One of your staff said this. 


Takeshi Hagikura (AdWords API Team)Google Employee 
Nov 12
Hi Bikram,

If the accounts are not linked to your MCC, you need to get a separate access token (and a refresh token) for each client account. 
In that case, I think an installed application mechanism is not practical because it requires manual process for each account. 

You can use the web application flow by preparing a web server that doesn't require manual process in your side when a client grants your application access to their data. 



Please give some insight in regards to accessing unlinked accounts. This is what I am interested in. Please understand my goal.

I need this to be able to authorize Adwords account users, that have nothing to do with my MCC account.


Christian Gibbs

unread,
Dec 10, 2013, 11:33:29 AM12/10/13
to adwor...@googlegroups.com
The OAuth login works fine, when I login myself. I can pull the data. But when I use another google account of mine I get the authorization error.

I need to achieve this. Please dont say this is the result because the account is unlinked. Please give me some direction on how to achieve this.

One of your colleague is saying it is possible. 

Christian Gibbs

unread,
Dec 10, 2013, 2:50:53 PM12/10/13
to adwor...@googlegroups.com
I GOT IT!!!!!!!!!



After getting the ?code=   from the URL


    $params = array(
"code" => $authCode,
"client_id" => $clientId,
"client_secret" => $clientSecret,
"redirect_uri" => $callbackUrl,
"grant_type" => "authorization_code"
    );
 
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_HEADER, false);
    curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
    curl_setopt($curl, CURLOPT_ENCODING, "");
    $curlData = curl_exec($curl);
    curl_close($curl);
$result = json_decode ($curlData);
print_r( $result );
 
 $access_token = $result->access_token;



$user = new AdWordsUser();
$user->SetOAuth2Info(array(
    "client_id" => $clientId,
    "client_secret" => $clientSecret,
    "access_token" => $access_token,
    "refresh_token" => ""
));

I save the Auth Info and I was able to pull the other account data!

Christian Gibbs

unread,
Dec 10, 2013, 3:58:26 PM12/10/13
to adwor...@googlegroups.com
By the way, your video helped. Because I didnt know there was a new Auth.ini file.

Now Im getting this error.

The client customer ID must be specified for report downloads.'

When I run the campaign service, I can do that and view all the campaigns but I cannot download the reports because I dont have the clientCustomerId.


How is this suppose to work when using OAuth2?

I have a refresh token. Everything is working ok, when just viewing the campaigns but not for downloading reports. The Id is required.

Any idea?

Thanks

Paul Matthews (AdWords API Team)

unread,
Dec 10, 2013, 8:52:35 PM12/10/13
to adwor...@googlegroups.com
The clientCustomerId is the identifier for the account you wish to access. You need to specify this in the AdWordsUser to access that account.

The OAuth2 layer is purely to permit access, the clientCustomerId specifies which sub account you're accessing.

For more information on this please read the README.

Regards,

- Paul, AdWords API Team.

Christian Gibbs

unread,
Dec 11, 2013, 2:00:12 PM12/11/13
to adwor...@googlegroups.com
Thank you for your continued support.

I figures this out this morning.

Once I pull the account I want to view,

I use 

$user->SetClientCustomerId( $account_id );

I can get it from the accountId of the campaign object for example.




Also I realized, my initial problem with USER_DENIED was that since I didnt update the Auth.ini, I was logging in ok but the logged in user was trying to access the Account of the MCC who owns the API access.

So instead of the User accessing their data, they were trying to access the MCCs data.

I had to remove the clientId from the Auth.ini and that made it work.



I just wanted to post this, I figure someone may find it helpful for pulling accounts under and MCC.


function getAccounts(AdWordsUser $user)
{
 
       $managedCustomerService =
  $user->GetService('ManagedCustomerService', ADWORDS_VERSION);
 
$selector = new Selector();
 $selector->fields = array('CustomerId','Name');
 $selector->ordering[] = new OrderBy('Name', 'ASCENDING');

 
 
$selector->paging = new Paging(0, AdWordsConstants::RECOMMENDED_PAGE_SIZE);
 
// $page = $managedCustomerService->get($selector);
 
 
 
$accounts = array();
 
     do {
// Make the get request.
$page = $managedCustomerService->get($selector);
// Display results.
if (isset($page->entries)) {
  
 return $page->entries;
 
} else {
return array();
}

// Advance the paging index.
$selector->paging->startIndex += AdWordsConstants::RECOMMENDED_PAGE_SIZE;
 } while ($page->totalNumEntries > $selector->paging->startIndex);
}

Christian Gibbs

unread,
Dec 11, 2013, 2:43:32 PM12/11/13
to adwor...@googlegroups.com
Actually this is what I used to pull the ClientId


$customerService = $user->GetService('CustomerService', ADWORDS_VERSION);
$cust = $customerService->get();
$user->setCustomerClientId( $cust->customerId );

Clik Ofertas

unread,
May 23, 2017, 9:42:26 AM5/23/17
to AdWords API Forum

Hi, I saw your problem. I'm starting to develop with the API. Is it possible to make the code completely available?
Capturar.PNG

Ali Texa

unread,
Jul 24, 2017, 2:37:57 AM7/24/17
to AdWords API Forum
Hi, Paul.
I encountered the same issue.
I want to every users get their campaign datas from our site.
So in first step, I generated auth url with user's id from google api.
And then, I got code from google and generate access_token, stored refresh_token in db per user.
And in second step, I created AdwordSession from refresh_token, and tried to use this session to get each user's campaign datas.
But in this case, I got permission_denied errors.
How can I solve this? 

Sreelakshmi Sasidharan (AdWords API Team)

unread,
Jul 24, 2017, 3:47:28 PM7/24/17
to AdWords API Forum
Hi Ali, 

Are you getting AuthorizationError.USER_PERMISSION_DENIED? If so, it means that the OAuth credentials used are for a user who does not have access to the client customer ID specified or any of its manager accounts or the link between the manager and client account was removed. Could you share the email Id of the user who is authenticating and the failure SOAP logs corresponding to that user? 

You could use Reply privately to the author while responding.

Thanks,
Sreelakshmi, AdWords API Team
Reply all
Reply to author
Forward
0 new messages