I am trying to use the Google Translate API on my Laravel project. I followed this tutorial https://cloud.google.com/translate/docs/quickstart-client-libraries?authuser=2#client-libraries-install-php
But when I try to run the code to translate, I get this error -
Your application has authenticated using end user credentials from Google Cloud SDK. We recommend that most server applications use service accounts instead. If your application continues to use end user credentials from Cloud SDK, you might receive a "quota exceeded" or "API not enabled" error. For more information about service accounts, see https://cloud.google.com/docs/authentication/. To disable this warning, set SUPPRESS_GCLOUD_CREDS_WARNING environment variable to "true".
This is my code:
public static function gcloud(){
# Your Google Cloud Platform project ID
$projectId = 'mybot';
# Instantiates a client
$translate = new TranslateClient([
'projectId' => $projectId
]);
# The text to translate
$text = 'Hello, world!';
# The target language
$target = 'ru';
# Translates some text into Russian
$translation = $translate->translate($text, [
'target' => $target
]);
echo 'Text: ' . $text . '
Translation: ' . $translation['text'];
}
I don't know what the problem might be.
Most likely the credentials you set the client library to use your gcloud credentials at ~/.config/gcloud/application_default_credentials.json. These are End User Credentials, which are tied to YOU, a specific user. The client library requires Service Account Credentials, which are not tied to a specific user.
Create Service Account Credentials by going to APIs and Services > Credentials and selecting Create Credentials > Service Account Key. Create a new service account, and in your case assign it the role Cloud Translation API Admin. This will download a JSON file with the following fields:
{
"type": "service_account",
"project_id": "YOUR_PROJECT_ID",
"private_key_id": "...",
"private_key": "...",
"client_email": "...",
"client_id": "...",
"auth_uri": "...",
"token_uri": "...",
"auth_provider_x509_cert_url": "...",
"client_x509_cert_url": "..."
}
Now set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path to this file. Notice the "type" field is "service_account". In the credentials which are throwing the error, the "type" field is "authorized_user".
Related
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
I am using the accounts.signInWithIdp endpoint as documented here to retrieve information about a user who has signed in using an identity provider (facebook, google, twitter).
When I perform a login, I expect to retrieve an idToken, which from my understanding is the token that is used to identify and verify the logged in user. However, I only receive this token when logging in with Google, not Facebook or Twitter. I'm not sure if this has anything to do with the fact that Google is a trusted provider and Facebook and Twitter are not, though I couldn't find any documentation about this.
My desired workflow is that the client makes a request to my server using the IDP credentials, and I give them back the idToken. The client can then use this idToken to make additional requests to my server, which verifies the token with Firebase on each request.
This is implemented this way because there is information specific to each user that is stored in my own database, not on Firebase. I identify the user in my database using their Firebase ID. Is my use case reasonable and if so why can I not receive an idToken for the user?
Edit:
The code I am using comes from the firebase-php library - specifically the signInWithIdpAccessToken function documented here. The request uses Guzzle client to make the request. Here is a code snippet:
$uri = uri_for('https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp');
$postBody = [
'access_token' => $action->accessToken(),
'id_token' => $action->idToken(),
'providerId' => $action->provider(),
];
if ($action->oauthTokenSecret()) {
$postBody['oauth_token_secret'] = $action->oauthTokenSecret();
}
$body = stream_for(\json_encode(\array_merge(self::$defaultBody, [
'postBody' => \http_build_query($postBody),
'returnIdpCredential' => true,
'requestUri' => $action->requestUri(),
])));
$headers = self::$defaultHeaders;
return new Request('POST', $uri, $headers, $body);
When I print the response, I get this for a request using Facebook (some values redacted):
{
"federatedId": "http:\/\/facebook.com\/...",
"providerId": "facebook.com",
"email": "...",
"emailVerified": false,
"firstName": "...",
"fullName": "...",
"lastName": "...",
"photoUrl": "...",
"localId": "...",
"displayName": "...",
"verifiedProvider": [
"google.com"
],
"needConfirmation": true,
"oauthAccessToken": "...",
"rawUserInfo": "...",
"kind": "identitytoolkit#VerifyAssertionResponse"
}
But as you can see, no idToken field is provided.
In a project I am provided with API endpoints from a Firebase DB.
To retrieve data I authenticate a user with email and password (https://firebase.google.com/docs/reference/rest/auth/#section-sign-in-email-password) and then sign every API call with the token. (These users are set up in Firebase DB)
Now one of the API endpoints returns Firebase Storage objects like this:
"fileReferences": [
{
"id": "",
"name": "images\/-s0m31D\/picture.jpg",
"mediaLink": "https:\/\/www.googleapis.com\/download\/storage\/v1\/b\/BUCKET.appspot.com\/o\/images%2F-s0m31D%2Fpicture.jpg?generation=1537959346600572&alt=media",
"selfLink": "https:\/\/www.googleapis.com\/storage\/v1\/b\/BUCKET.appspot.com\/o\/images%2F-s0m31D%2Fpicture.jpg",
"updated": 1537959346,
"size": 7759448
}
],
when I try to access fileReferences.0.mediaLink, I get an auth error.
If I send my token along with the request to mediaLink I have no luck either (https://cloud.google.com/storage/docs/downloading-objects#download-object-json)
I tried to use the Google API PHP client https://github.com/googleapis/google-api-php-client, but had no idea how I setup the new Google_Client() (I already have my auth token and I expected it to work somehow)
$client = new \Google_Client();
$client->setAccessToken(['access_token' => $token]);
How can I access the media files with my existing auth token? (or do I need a different one?)
To handle the files, I would like to use https://github.com/googleapis/google-api-php-client how can I make that work? Any hint is appreciated
Edit: I got some results in debugging the JavaScript SDK
"All" the SDK does is creating the following URL Schema
printf('https://firebasestorage.googleapis.com/v0/b/bucket.appspot.com/o/%s', urlencode('projects/-id/logo.png'));
//http[s]://firebasestorage.googleapis.com/<api-version>/b/<bucket>/o/<object-path>
You have to sign the call to https://firebasestorage.googleapis.com/v0/b/bucket.appspot.com/o/projects%2F-id%2Flogo.png with your Auth Bearer token header![1]
This returns meta data like this:
{
"name": "projects/-id/logo.png",
"bucket": "bucket.appspot.com",
"generation": "1537960188874518",
"metageneration": "1",
"contentType": "image/png",
"timeCreated": "2018-09-26T11:09:48.874Z",
"updated": "2018-09-26T11:09:48.874Z",
"storageClass": "STANDARD",
"size": "40437",
"md5Hash": "MxkOU+6feyYtdEAgKbDgp5A==",
"contentEncoding": "identity",
"contentDisposition": "inline; filename*=utf-8''logo.png",
"crc32c": "o89Y9dQ==",
"etag": "CJae8pXE2N0CEAE=",
"downloadTokens": "32c339ff9-7e4a-42a2-890a-428f8f45d378"
}
To publicly share your image, add ?alt=media&token=32c339ff9-7e4a-42a2-890a-428f8f45d378
https://firebasestorage.googleapis.com/v0/b/bucket.appspot.com/o/projects%2F-id%2Flogo.png?alt=media&token=32c339ff9-7e4a-42a2-890a-428f8f45d378
You don't need the token, if you send the Auth Header!
I couldn't find any mention of firebase or how to deal with my authentication in https://github.com/googleapis/google-api-php-client, so I have no idea if this would have helped me. But I got down to the basics...
Hope this helps somebody and any clearification is greatly appreciated.
QUESTION for me to better understand this all:
What are mediaLink and selfLink pointing to?
[1] if the access to storage is public you don't need to sign it.
Calling Google API got this message:
{
"error": {
"errors": [
{
"domain": "androidpublisher",
"reason": "permissionDenied",
"message": "The current user has insufficient permissions to perform the requested operation."
}
],
"code": 401,
"message": "The current user has insufficient permissions to perform the requested operation."
}
}
or this error message (ADDED):
{
"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 follow all indications I found and I keep having this error.
ON MY SYSTEM
My code
try {
ini_set('max_execution_time', 3000);
$client = new Google_Client();
if ($credentials_file = $this->checkServiceAccountCredentialsFilePlay()) {
// set the location manually
$client->setAuthConfig($credentials_file);
} elseif (getenv('GOOGLE_APPLICATION_CREDENTIALS')) {
// use the application default credentials
$client->useApplicationDefaultCredentials();
} else {
$rv= "missingServiceAccountDetailsWarning()";
return [$rv];
}
$client->addScope("https://www.googleapis.com/auth/androidpublisher");
$serviceAndroidPublisher = new \Google_Service_AndroidPublisher($client);
$servicePurchaseSubscription = $serviceAndroidPublisher->purchases_subscriptions;
$rv = $servicePurchaseSubscription->get(
"com.my.app",
"sub1month",
"ajgbkxxxxxxxxx.AO-J1OxTOKENTOKENTOKEN-"
);
} catch (\Exception $e) {
return $e->getMessage();
}
The credential file
{
"type": "service_account",
"project_id": "project-id",
"private_key_id": "abababababababababababababababababa",
"private_key": "-----BEGIN PRIVATE KEY-----KEYBASE64=\n-----END PRIVATE KEY-----\n",
"client_email": "google-play-account#project-id.iam.gserviceaccount.com",
"client_id": "123450000000000000000",
"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/google-play-account%40project-id.iam.gserviceaccount.com"
}
ON GOOGLE PLAY CONSOLE
I link the project to the google play console
I add the Service account to the google play console
It's present in the user menu of google play console
And I give him all permission:
ON GOOGLE API DEVELOPER CONSOLE
ADD FYI: my "project-id" is under an organization.
In google developer console I gave all possible permission to the service account:
And of course I've enabled the google Play Android Developer Api (showing my failures):
I had the same problem.
In my case, I was using the google app engine (python) as a backend service. In the beginning, I linked a new Google cloud project in the Google Play Console. I'm not entirely sure if it's the main reason that I got a 401 'insufficient permissions' error, but after switching the linked project to my cloud project (which I used for the app engine) it worked the next day. Right after switching accounts, I received the 403 'projects not linked' error. So, I'm guessing that Google doesn't recognize the change of the linked projects immediately and you need to wait for a few hours.
If you are using app engine, you have to make sure that your default service account for the app engine has a JSON credential file. It's not created by default.
Here is the python code:
if os.getenv('SERVER_SOFTWARE', '').startswith('Google App Engine/'):
# production environment
credentials = oauth2client.contrib.appengine.AppAssertionCredentials(scope='https://www.googleapis.com/auth/androidpublisher')
http = credentials.authorize(httplib2.Http(memcache))
response = googleapiclient.discovery.build('androidpublisher', 'v3').purchases().subscriptions()\
.get(packageName=package_name, subscriptionId=subscription.product_id, token=subscription.token)\
.execute(http)
else:
# local environment
# setting the scope is not needed because the api client handles everything automatically
credentials = google.oauth2.service_account.Credentials.from_service_account_file('local_dev.json')
response = googleapiclient.discovery.build('androidpublisher', 'v3', credentials=credentials).purchases().subscriptions()\
.get(packageName=package_name, subscriptionId=subscription.product_id, token=subscription.token)\
.execute()
First of all I've never worked with google analytics before and now when I need to its a bit confusing to grasp the flow.
I did a lot of research online. What I come across is that, you need to have secret key which is created at developer console to authenticate. If I have this key, I can follow the standard examples found to retrieve any data I want for a site.
However I have a few doubts:
I'm working on freelance basis. So my client has given me access to their site's google analytics. So how to I read the analytical data like number of visitors and so on? Since my email already been allowed to access the data, I can query or do I still need the authentication key which should be in json format?
If I need to have the json key, how does it work? Is it like I create a key in my developer console https://console.developers.google.com and use this key to read the client data? Does this key act like a one stop center to authenticate myself in accessing any api from any site as long as they have added me inside their account?
I access my client's google analytical data here: https://analytics.google.com/analytics/web
Please explain to me the correct flow on how to read someone else's site data via PHP..I just need the overall idea.
Thank you in advance.
I try with an example
First of all the google client
composer require "google/apiclient"
In console.developers.google.com:
enable analytics api
define a project (eg: project-id)
2) the credentials_file
Create a service account at:
https://console.developers.google.com/iam-admin/serviceaccounts?project=project-id
By wich you will create the credential file at "path/to/the/service-account-credentials.json"
{
"type": "service_account",
"project_id": "project-id",
"private_key_id": "1234567890abcderf1234567890abcderf1234567890abcderf",
"private_key": "-----BEGIN PRIVATE KEY-----\nBASE64KEY=\n-----END PRIVATE KEY-----\n",
"client_email": "service-user#some.domain.gserviceaccount.com",
"client_id": "000000000000000000000000000000",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/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/cront-reriever-search-stats%40redooc-dot-com.iam.gserviceaccount.com"
}
3) defining what you want ($infos), for witch view you want ($viewId) and a credentials file ($credentials_file) and a date range, you will query the API and got results in $response
$infos= [
'users' => 'ga:users',
'pageviews' => 'ga:pageviews',
'pageviewsPerSession' => 'ga:pageviewsPerSession',
'unique page view' => 'ga:uniquePageviews',
'organicSearches' => 'ga:organicSearches',
'avgSessionDuration' => 'ga:avgSessionDuration',
'avgTimeOnPage' => 'ga:avgTimeOnPage',
];
$credentials_file='path/to/the/service-account-credentials.json';
$viewId='1600000'; // the view ID see imgae
$client = new \Google_Client();
$credentials_file = $this->checkServiceAccountCredentialsFile()) {
$client->setAuthConfig($credentials_file);
$client->addScope("https://www.googleapis.com/auth/analytics.readonly");
$analytics = new \Google_Service_AnalyticsReporting($client);
$response = getReport($viewId, $analytics, $infos, $DateStart, $DateEnd);
ADD getReport funtion
function getReport($viewId, $analytics, $dataAnalytics, $startDate, $endDate)
{
$dateRange = new \Google_Service_AnalyticsReporting_DateRange();
$dateRange->setStartDate($startDate);
$dateRange->setEndDate($endDate);
// Create the ReportRequest object.
$request = new \Google_Service_AnalyticsReporting_ReportRequest();
$request->setViewId($viewId);
$request->setDateRanges($dateRange);
// Create the Metrics object.
$_metrics = [];
foreach ($dataAnalytics as $gaLabel => $gaValue) {
$metric = new \Google_Service_AnalyticsReporting_Metric();
$metric->setExpression($gaValue);
// $metric->setAlias($gaLabel);
$_metrics[] = $metric;
}
$request->setMetrics($_metrics);
$body = new \Google_Service_AnalyticsReporting_GetReportsRequest();
$body->setReportRequests(array($request));
return $analytics->reports->batchGet($body);
}
You have two options to use Site Search for POST-based search engines:
Option 1: Configure your web application to append the query keywords to the end of the URL (e.g., http://www.example.com/search_results.php?q=keyword) and then set up Site Search as described in the previous section.
Option 2: Customize the tracking code on your results page to dynamically specify a virtual page path that includes the query keywords. The tracking code on the results page would look something like:
analytics.js: ga('send', 'pageview', '/search_results.php?q=keyword');
reference: https://support.google.com/analytics/answer/1012264?hl=en