I've set up an OAuth2 web project as well as a Service Account. Both IDs have been added with domain-wide delegation with the adwords scope in my Google Workspace.

I have a Google Ads Manager account with a Developer Key (it's in test mode, if that matters?). The email I'm trying to authenticate with for either method is an Admin in the domain and on the relevant Ads Manager and Ads accounts.

No matter what I do, I get the following error.

{     "message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https:\/\/developers.google.com\/identity\/sign-in\/web\/devconsole-project.",     "code": 16,     "status": "UNAUTHENTICATED",     "details": [         {             "@type": "type.googleapis.com\/google.ads.googleads.v16.errors.GoogleAdsFailure",             "errors": [                 {                     "errorCode": {                         "authenticationError": "OAUTH_TOKEN_HEADER_INVALID"                     },                     "message": "Oauth token HTTP header is malformed."                 }             ],             "requestId": "9QCN5RO9mRkmS1ULtDAKMA"         }     ] } 

If I try to use the service account email as the impersonateEmail parameter, I get a NOT_ADS_USER. I've invited it to the Ads Manager account, but am not sure how to accept that invite. I think it would result in the same OAUTH_TOKEN_HEADER_INVALID, anyways.

This is within a Laravel project.

$oauth2 = (new OAuth2TokenBuilder())                 ->withClientId(config('google.client_id'))                 ->withClientSecret(config('google.client_secret'))                 ->withRefreshToken(config('googleads.refresh_token'))                 ->build(); 
$oauth2 = (new OAuth2TokenBuilder())                 ->withJsonKeyFilePath(realpath(config('google.service.file')))                 ->withScopes('https://www.googleapis.com/auth/adwords')                 ->withImpersonatedEmail(config('googleads.impersonated_email'))                 ->build(); 

What's strange is that, using either OAuth2Token instance, I can run fetchAuthToken(), and I see that the object gets its access_token. I can also see in Google\ApiCore\CredentialsWrapper::getAuthorizationHeaderCallback that it is added as the authorization Bearer token.

Here's how my GoogleAdsClient is built:

$this->client = (new GoogleAdsClientBuilder())                 ->withOAuth2Credential($oauth2)                 ->withDeveloperToken(config('google.developer_key'))                 ->usingGapicV2Source(true)                 ->build(); 

And here's the request that fails with the OAUTH_TOKEN_HEADER_INVALID:

$requestArgs = [             // Set the language resource using the provided language ID.             'language' => $this->getLanguageConstant(),             'customer_id' => $this->getCustomerId(),             // Add the resource name of each location ID to the request. - currently an empty array             'geo_target_constants' => $this->getGeoTargetConstants(),             // Set the network. To restrict to only Google Search, change the parameter below to             'keyword_plan_network' => KeywordPlanNetwork::GOOGLE_SEARCH,         ] + $requestOptionalArgs;         $response = $ideaClient->generateKeywordIdeas(             new GenerateKeywordIdeasRequest($requestArgs)         ); 

I've been going in circles on this for over a day. Thank you in advance!

Tag:google-ads-api, php, google-api-php-client, google-oauth, unauthorized

Add a new comment.