Google Server-to-Server OAuth2 PHP example not working - php

I am following this example to get server-to-server access working between my PHP application and Google Cloud API's,
https://developers.google.com/api-client-library/php/auth/service-accounts. In particular, I need to access the Drive API.
When I run the application though I get the following error:
Google_Service_Exception : {
"error": "unauthorized_client",
"error_description": "Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested."
}
Here's what I have done:
Created a GCP project
Added a service account to the project, with domain wide delegation, and a set of keys
Enabled the Google Drive API in the project
In my G Suite account, under 'Manage API client access', I have added the Client ID of my service account, with the permission of https://www.googleapis.com/auth/drive
Have I missed a step?
Here's my code:
putenv('GOOGLE_APPLICATION_CREDENTIALS=my_storage/secure/my-app-service-account.json');
$client = new \Google_Client();
$client->setScopes(\Google_Service_Drive::DRIVE_METADATA_READONLY);
$client->useApplicationDefaultCredentials();
$client->setSubject('my_email#my_domain.com');
$drive = new \Google_Service_Drive($client);
echo $drive->about->get();
The example does not include the setScopes() call, however I was getting a scope-related error without it. (The example is not based on the Drive API, so perhaps it's not required in that case?)
UPDATE: In the IAM settings for the GCP, I added the email address of the service account as a Project Owner, but that made no difference.

I found the problem.
In the setScopes() call above, the value passed needs to be the same as the value given when setting up the client in G Suite, in this case https://www.googleapis.com/auth/drive

Related

Use google drive API to change the owner of a file created with an account service

I used an service account to upload files to a shared folder in google drive.
After some time I discovered that files owned by service account consumed the service's account drive storage (my bad) and now I have run out drive space for the service account .
I already delegated domain-wide authority to the service account so new files will be owned by me and use my personal storage quota.
Did this: Delegating domain-wide authority to the service account
and this How to use the API Key for Google Drive API from PHP via the google/apiclient
To avoid errors and confusion in the future I'd like to change the owner of older files. I keep getting this error:
{ "error": {
"code": 400,
"message": "Bad Request. User message: \"You can't change the owner of this item.\"",
"errors": [ {
"message": "Bad Request. User message: \"You can't change the owner of this item.\"",
"domain": "global",
"reason": "invalidSharingRequest"
} ]
}
}
Here's my code using PHP Client
$client = new Google_Client();
$client->setApplicationName('My Name');
$client->setScopes(Google_Service_Drive::DRIVE);
$client->setAuthConfig($my_credentials);
$client->setAccessType('offline');
//$client->setSubject('my_personal_account');
$service = new Google_Service_Drive($client);
$newPermission = new Google_Service_Drive_Permission();
$newPermission->setEmailAddress('my_personal_account');
$newPermission->setType('user');
$newPermission->setRole('owner');
$service->permissions->create(
$fileId,
$newPermission,
array("fields" => "id", "transferOwnership" => true)
);
I've got the same error with or without setSubject in the client. I've tried using
$newPermission->setRole('writer');
$newPermission->setPendingOwner(true);
but it didn't work.
Transfering the file ownership can only be done between accounts from the same domain. The error occurs because the service account and your account don't belong to the same domain.
If you have access to a Shared Drive and are able to add users with add files privileges, add the service account and make it move the files to the Shared Drive.
Related
transfer file ownership in Google Drive API
Unable to transfer ownership of file from service account to google drive user
Other related
Google Drive API ownership of files uploaded from service account
Google Drive API - Transfer ownership from Service Account

Cannot connect MyBusiness with google-api-php-client

my goal is to receive the locations of a specific account.
I know the followed all instructions:
I downloaded and installed the google client in php
API Samples
I downloaded and installed MyBusiness.php from here
Business Samples
I created the project in the developer console (https://console.developers.google.com)
I requested access for Google My Business API and I received confirmation of activation and I enabled the API from the console.
I followed the tutorial to receive information about the accounts from which they can retrieve information
Unfortunately I always get the same error and I do not know what to do after hours of testing:
"Request is missing required authentication credential Expected OAuth 2 access token, login cookies or another valid authentication credential"
$client = new Google_Client();
$client->setHttpClient($httpClient);
$client->setApplicationName("project_id");
$client->setDeveloperKey('DEVELOPER KEY');
$client->setAuthConfig(plugin_dir_path( __FILE__ ).'oauth.json');
$client->setScopes("https://www.googleapis.com/auth/plus.business.manage");
$service = new Google_Service_Mybusiness($client);
$accounts = $service->accounts->listAccounts();
How can i solve it?
What am i missing?

Not able to configure change object notification for php application in google app engine

I am getting the following error when I try to setup notification using gsutil command:
gsutil notification watchbucket https://APPLICATION-ID.appspot.com/cron gs://bucket
Watching bucket gs://APPLICATION-ID.appspot.com/ with application URL https://APPLICATION-ID.appspot.com/cron ...
Watch bucket attempt failed:
AccessDeniedException: 403 Forbidden
You attempted to watch a bucket with an application URL of:
https://APPLICATION-ID.appspot.com/cron
which is not authorized for your project. Please ensure that you are using
Service Account authentication and that the Service Account's project is
authorized for the application URL. Notification endpoint URLs must also be
whitelisted in your Cloud Console project. To do that, the domain must also be
verified using Google Webmaster Tools. For instructions, please see:
https://cloud.google.com/storage/docs/object-change-notification#_Authorization
AccessDeniedException: 403 Forbidden
I have followed all the steps from the url below for Notification Authorization:
https://cloud.google.com/storage/docs/object-change-notification
But I am still getting the above error. What step am I missing ?
Thanks
I have fixed the issue myself. I had missed "https://" while adding the domain name.
Thanks

YouTube API call fails, even though server’s IP address is white-listed

I’ve a simple PHP component that fetches videos from a public playlist on YouTube. I’m using Google’s official PHP SDK and authenticated with a server key (as I only need to access public data, not data in a user context).
Throughout development and into staging, this component has worked fine. However, I’ve moved the application to the client’s production server (a GoDaddy hosting account) and the component’s suddenly stopped working, instead throwing the following error:
Google_Service_Exception in REST.php line 83:
Error calling GET https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId=PLAYLIST_ID&userIp=SERVER_IP&key=DEVELOPER_KEY: (403) There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed.
I don’t understand. The server’s IP address is white-listed in the Google API Console. I know it’s the correct IP address, as I’ve sent a HTTP POST request from the server to another PHP script and captured the REMOTE_ADDR server variable.
I’ve also tried specifying the IP address in the request itself. The full code:
$client = new Google_Client;
$client->setApplicationName($appName);
$client->setDeveloperKey($developerKey);
$service = new Google_Service_YouTube($client);
$service->playlistItems->listPlaylistItems('snippet', array(
'maxResults' => 50,
'playlistId' => $collectionId,
'userIp' => $serverIp,
));
So what’s going? Why is Google deciding it’s not playing ball with the production server?

Google Analytics API oauth exception "invalid_grant" with Service Account. Same code on two servers. Only one works

I'm querying the Analytics API via a Service Account.
I have written the code on the dev server and it works without issues.
When running the same code on the production server, it throws this:
Google_AuthException: Error refreshing the OAuth2 token, message: '{
"error" : "invalid_grant" }'
I've tried creating another Service account, and the behavior is the same.
The oAuth IETF draft (https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-31) says this about the error:
invalid_grant
The provided authorization grant (e.g. authorization
code, resource owner credentials) or refresh token is
invalid, expired, revoked, does not match the redirection
URI used in the authorization request, or was issued to
another client.
Here is the code I've written:
$GA_CLIENT_ID = 'XX.apps.googleusercontent.com';
$GA_APP_EMAIL = 'XX#developer.gserviceaccount.com';
$GA_APP_NAME = 'XX';
$GA_KEY_FILE = 'XX';
// create client object and set app name
$client = new Google_Client();
$client->setApplicationName($GA_APP_NAME); // name of your app
// set assertion credentials
$client->setAssertionCredentials(
new Google_AssertionCredentials(
$GA_APP_EMAIL, // email you added to GA
array('https://www.googleapis.com/auth/analytics.readonly'),
file_get_contents($GA_KEY_FILE) // keyfile you downloaded
));
// other settings
$client->setClientId($GA_CLIENT_ID); // from API console
$client->setAccessType('offline_access'); // this may be unnecessary?
// create service and get data
$service = new Google_AnalyticsService($client);
$result = $service->data_ga->get($ids, $startDate, $endDate, $metrics, $optParams);
return $result;
I've also tried a solution suggested here (https://groups.google.com/forum/?fromgroups#!topic/gs-discussion/3y_2XVE2q7U%5B1-25%5D) using authenticatedRequest() instead of Google_AnalyticsService:
$req = new Google_HttpRequest($apiUrl);
$resp = $client::getIo()->authenticatedRequest($req);
$result = json_decode($resp->getResponseBody(), true);
This alternative also works on the dev server, but not on the production one.
I am totally clueless on this one. Has anyone seen this/fixed it?
Thanks!
Apparently the problem was the system time being off. Worked by sync-ing via NTP with:
sudo ntpdate npt.ubuntu.com
sudo ntpdate pool.ntp.org
Edit
As #RafaSashi suggested below, the pool.ntp.org server is more reliable. Use that instead of ntp.ubuntu.com (which was the first working one I tried, thus the initial choice).
The invalid grant can also be caused if you use the wrong "ServiceAccountId". It should be the email associated with the client id in the service account client id in the google apis access page. You'd also have to add this user to the google analytics account that you're planning to access.
This tripped me up because I assumed the email address they were referring to was the email address of my google account, since I used the same google account to get api access as I do for google analytics. I know Vir's already figured his out, just thought I'd add this in case someone else comes across the same question and, like me, their computer seems to be in sync with NTP.
In addition to Valer's answer:
First, you’ll need to install NTP if it isn’t already installed. For Debian or Ubuntu, that would be this command:
sudo apt-get install ntp
For Redhat or CentOS, you’ll need to use this one:
yum install ntp
If the synchronization via npt.ubuntu.com doesn't work try :
sudo ntpdate pool.ntp.org
Resources
http://www.howtogeek.com/tips/how-to-sync-your-linux-server-time-with-network-time-servers-ntp/
https://www.digitalocean.com/community/tutorials/how-to-set-up-time-synchronization-on-ubuntu-12-04
There are two major reasons for invalid_grant error which you have to take care prior to the POST request for Refresh Token and Access Token.
Request header must contain "content-type: application/x-www-form-urlencoded"
Your request payload should be url encoded Form Data, don't send as json object.
RFC 6749 OAuth 2.0 defined invalid_grant as:
The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.
I found another good article, here you will find many other reasons for this error.
https://blog.timekit.io/google-oauth-invalid-grant-nightmare-and-how-to-fix-it-9f4efaf1da35
Google Playground is best tool which help you how to send request.
https://developers.google.com/oauthplayground

Categories