I am new to working with Google API but I have a project that requires me to access their domain to find a user's manager by email. Before I started on the code I wanted to set everything up so I followed the example file for PHP. I was able to get it to work but had some issues with refreshing the token once it expired and research pushed me towards using a Service Account, as this is a server cron script and I don't want to deal with any user interactions.
I created the Service Account, enabled G Suite Domain-wide Delegation, and added access for: https://www.googleapis.com/auth/admin.directory.user.readonly
I get a Google_Service_Exception with my script.
The response is:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "notFound",
"message": "Domain not found."
}
],
"code": 404,
"message": "Domain not found."
}
}
I am assuming this means it doesn't know the accounts domain but I don't see how I can resolve this. I assume that if this was a permissions issue, Google would tell me. I tried searching online but no luck as the issues I found were using a different method and the fixes weren't something that could be done on the Service Account. I am stuck right now so I hope a push in the right direction will get me on track.
This is the test script I am using:
<?php
require_once( __DIR__. '/vendor/autoload.php' );
define('CREDENTIALS_PATH', '/path/to/service_account.json');
define('SCOPES', implode(' ', array(
Google_Service_Directory::ADMIN_DIRECTORY_USER_READONLY)
));
date_default_timezone_set('America/New_York');
/**
* Returns an authorized API client.
* #return Google_Client the authorized client object
*/
function getClient() {
$client = new Google_Client();
$client->setApplicationName('TestingApp');
$client->setAuthConfig(CREDENTIALS_PATH);
$client->setScopes(SCOPES);
return $client;
}
// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Directory($client);
// Print the first 10 users in the domain.
$optParams = array(
'customer' => 'my_customer',
'maxResults' => 10,
'orderBy' => 'email',
);
$results = $service->users->listUsers($optParams);
if (count($results->getUsers()) == 0) {
print "No users found.\n";
} else {
print "Users:\n";
foreach ($results->getUsers() as $user) {
printf("%s (%s)\n", $user->getPrimaryEmail(),
$user->getName()->getFullName());
}
}
My service_account.json contains (cleaned obviously)
{
"type": "service_account",
"project_id": "PROJECT_ID",
"private_key_id": "PRIVATE_KEY_ID",
"private_key": "PRIVATE_KEY",
"client_email": "SERVICE_ACCOUNT_EMAIL.iam.gserviceaccount.com",
"client_id": "CLIENT_ID",
"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/SERVICE_ACCOUNT_IDENTIFIER.iam.gserviceaccount.com"
}
Thanks for any assistance on this.
Okay, this was a very easy step to overlook but it was an extremely simple fix.
The issue here was that the domain for the account was not identified. I was under the impression that the service account was already attached to the domain but that is not the case. So the fix is just one line of code to add to the client to set it to a user that is in the domain (for my case).
The fix for me was to add:
$client->setSubject('account#domain.com');
to my getClient method.
so now the method looks like:
/**
* Returns an authorized API client.
* #return Google_Client the authorized client object
*/
function getClient() {
$client = new Google_Client();
$client->setApplicationName('TestingApp');
$client->setAuthConfig(CREDENTIALS_PATH);
$client->setScopes(SCOPES);
$client->setSubject('account#domain.com');
return $client;
}
I saw this mentioned in the API but it states it as optional. Hopefully this will help someone else too.
for me was the same error, but i needed to share my calendar with service account email (that found in json auth file). After that, error dissapeared.
For my case it was the domain value I passed with listUsers() function caused this error. Let's say my domain for GSuite is xyz.com and I tried with something like this
$dir = new \Google_Service_Directory($googleClient);
$dir->users->listUsers(array('domain' => 'abc.com', 'maxResults' => 500));
Instead I should use the correct domain name for value of the 'domain' like below.
$dir = new \Google_Service_Directory($googleClient);
$dir->users->listUsers(array('domain' => 'xyz.com', 'maxResults' => 500));
Related
I would be really happy to get a solution for this.
This is the error:
{ "error": { "code": 403, "message": "Permission denied. Failed to
verify the URL ownership.", "status": "PERMISSION_DENIED" } }
As I have followed all the steps given in the google documentation.
I have verified the url ownership and added service account as owner. Here is the code snippet. Please check and reply with a solution, if you have.
include_once dirname(__FILE__)."/google-api-php-client_1/vendor/autoload.php";
$client = new Google_Client();
$client->setAuthConfig(dirname(__FILE__).'/xxxxxxxxxxxxxxxxxxxxx.json');
$client->addScope('https://www.googleapis.com/auth/indexing');
$httpClient = $client->authorize();
$endpoint = 'https://indexing.googleapis.com/v3/urlNotifications:publish';
$array= array("url"=>"https://www.mycoders.in/career","type"=>"URL_UPDATED");
$content= json_encode($array);
$response = $httpClient->post($endpoint, [ 'body' => $content ]);
$response2 = $response->getBody()->getContents();
Thanks in advance!
Rohit
Probably your service account is set to "Full" instead of Owner. If that is the case, you have to change your account to Owner. Use the Old Webmasters tool to do that.
https://support.google.com/webmasters/thread/4763732?hl=en
I am trying to build a very simplified piece of code that is to simply upload a local file from server to my personal drive account. Right now I am struggling with authentication issues, and not sure what kind of credential type I need.
Importantly, since this is only accessing my own private drive, I want to upload my credentials once and not have it ask in future. I am not trying to use oAuth to access my user's drives at all. It seems most documentation is for if we are trying to authenticate and access OTHER users drives?
I think I can manage the upload code once I can authenticate, but right now I can't even list my existing files.
Here is my code so far:
<?php
require_once 'google-api-php-client/vendor/autoload.php';
/**
* Returns an authorized API client.
* #return Google_Client the authorized client object
*/
function getClient($credentialsPath = ''){
$client = new Google_Client();
$client->setApplicationName('Google Drive API');
$client->setAuthConfig($credentialsPath); // saved some credentials from console, but not sure which ones to use?
$client->setScopes(Google_Service_Drive::DRIVE);
return $client;
}
// Get the API client and construct the service object.
$client = getClient($credentialsPath);
$service = new Google_Service_Drive($client);
// Print the names and IDs for up to 10 files.
$optParams = array(
'pageSize' => 10,
'fields' => 'nextPageToken, files(id, name)'
);
$results = $service->files->listFiles($optParams);
if (count($results->getFiles()) == 0) {
print "No files found.\n";
} else {
print "Files:\n";
foreach ($results->getFiles() as $file) {
printf("%s (%s)\n", $file->getName(), $file->getId());
}
}
When I run this code I get the following error code:
Fatal error: Uncaught exception 'Google_Service_Exception' with message '{ "error": { "errors": [ { "domain": "usageLimits", "reason": "dailyLimitExceededUnreg", "message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.", "extendedHelp": "https://code.google.com/apis/console" } ], "code": 403, "message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup." }
The few things I looked at suggest this code is not about daily limit, but in fact incorrect usage of credentials. Any idea how I can fix this?
I'm trying to create an automation script with php which adds a new row of information to a google sheet that I've shared. I've been scouring tutorials all morning trying to figure this out but each method is different and doesn't seem to be exactly what I need to do. Essentially this script will be triggers when a form is submitted on my site. Its going to take the form data and drop is into my google sheet.
I've created a service account under my project, which is stored inside the json file that was downloaded. Here's the script I have now. It's giving me the following error
{ "error": {
"code": 403,
"message": "The caller does not have permission",
"errors": [ {
"message": "The caller does not have permission",
"domain": "global",
"reason": "forbidden"
} ],
"status": "PERMISSION_DENIED"
}
and here's the code I'm running. (yes its incomplete because I can't get past the auth)
public function index()
{
$this->load->helper("url");
require APPPATH . 'third_party/GoogleAPI/vendor/autoload.php';
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . APPPATH . 'third_party/GoogleAPI/bdgsheets.json');
$client = new Google_Client;
$client->useApplicationDefaultCredentials();
$client->setApplicationName("Is this working");
$client->setScopes(['https://www.googleapis.com/auth/drive','https://spreadsheets.google.com/feeds']);
$client->setAccessType('offline');
if ($client->isAccessTokenExpired()) {
$client->refreshTokenWithAssertion();
}
$accessToken = $client->fetchAccessTokenWithAssertion()["access_token"];
$sheets = new Google_Service_Sheets($client);
$data = [];
$current_row = 2;
$spreadsheet_id = "{my spreadsheet id here}";
$range = 'A1:H';
$rows = $sheets->spreadsheets_values->get($spreadsheet_id, $range, ['majorDimension' => 'ROWS']);
}
Thanks in advance for the help
Have you put the right scope when adding creating the access token. If you had used the scope value
"https://www.googleapis.com/auth/spreadsheets.readonly" instead of
"https://www.googleapis.com/auth/spreadsheets" you won't have write permission to the google sheet.
If you can share the code piece which creates the bdgsheets.json file it is easy to understand whether you have the "write" permission.
Also, try changing this piece of code
$client->setScopes(['https://www.googleapis.com/auth/drive','https://spreadsheets.google.com/feeds']);
to
$client->setScopes(['https://www.googleapis.com/auth/spreadsheets']);
and give it a shot
I want to change all signatures from my Gmail domain. This domain has many accounts, and I need to change it from server-side.
I'm using php, and I started my project with:
php composer.phar require google/apiclient:2.0
I wrote one code, but when I try to update one email (like teste#mydomain.com), I receive:
{ "error": { "errors": [ { "domain": "global", "reason": "insufficientPermissions", "message": "Insufficient Permission" } ], "code": 403, "message": "Insufficient Permission" } }
My code (using API client library) is something like:
<?php
// initialize gmail
function getService() {
try {
include_once __DIR__ . '/vendor/autoload.php';
$client = new Google_Client();
$credentials_file = __DIR__ . '/credentials/gmailAPI.json';
// set the location manually. Credential server-side
$client->setAuthConfig($credentials_file);
$client->setApplicationName("GmailAPI");
$client->setScopes(['https://apps-apis.google.com/a/feeds/emailsettings/2.0/']);
$gmail = new Google_Service_Gmail($client);
return $gmail;
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
}
function updateSignature(&$gmail) {
try {
// Start sendAs
$signature = new Google_Service_Gmail_SendAs();
// Configure Signature
$signature->setSignature("Any HTML text here.");
// Update account and print answer
var_dump($gmail->users_settings_sendAs->update("someEmail#myDomain.com.br","someEmail#myDomain.com.br",$signature));
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
}
try {
$gmail = getService();
updateSignature($gmail);
} catch (Exception $e) {
echo $e->getMessage();
}
?>
My credential file (gmailAPI.json) is one service account key, and I'm using Google for Work.
I created this credential using one administrator account from this domain.
My credential file is:
{
"type": "service_account",
"project_id": "myProjectId",
"private_key_id": "myPrivateKeyid",
"private_key": "myPrivateKey",
"client_email": "gmailapi#projectid.iam.gserviceaccount.com",
"client_id": "myId",
"auth_uri": "url",
"token_uri": "url",
"auth_provider_x509_cert_url": "url",
"client_x509_cert_url": "url"
}
Edit 1
I changed the scopes as instructed, and now my scopes are:
$client->setScopes(['https://www.googleapis.com/auth/gmail.settings.basic','https://www.googleapis.com/auth/gmail.settings.sharing']);
I also added permision on Google (/AdminHome?chromeless=1#OGX:ManageOauthClients) to my service account key.
I tried API explorer and it works. When i changed the scopes, the error changed to:
{ "error": { "errors": [ { "domain": "global", "reason": "failedPrecondition", "message": "Bad Request" } ], "code": 400, "message": "Bad Request" } }
I'm using this command:
var_dump($gmail->users_settings_sendAs->update("someEmail#myDomain.com.br","someEmail#myDomain.com.br",$signature));
I tried also
var_dump($gmail->users_settings_sendAs->get("someEmail#myDomain.com.br","someEmail#myDomain.com.br"));
But I received same error.
Thank You everyone.
I tried a lot of codes, and finally found one that works.
include_once __DIR__ . '/vendor/autoload.php';
// credential file (service account)
$credentials_file = __DIR__ . '/credentials/gmailAPI.json';
putenv('GOOGLE_APPLICATION_CREDENTIALS='.$credentials_file);
// Initialize Google Client
$client = new Google_Client();
$client->useApplicationDefaultCredentials();
// scopes to change signature
$client->setScopes(['https://www.googleapis.com/auth/gmail.settings.basic','https://www.googleapis.com/auth/gmail.settings.sharing']);
// *important* -> Probably because delegated domain-wide access.
$client->setSubject("admEmailHere#test.com");
// Initialize Gmail
$gmail = new Google_Service_Gmail($client);
// set signature
$signature = new Google_Service_Gmail_SendAs();
$signature->setSignature("HTML code here.");
// update signature
$response = $gmail->users_settings_sendAs->update("admEmailHere#test.com","admEmailHere#test.com",$signature)->setSignature();
// get signature
$response = $gmail->users_settings_sendAs->get("admEmailHere#test.com","admEmailHere#test.com")->getSignature();
echo json_encode($response);
I commented all code, and I used https://developers.google.com/api-client-library/php/auth/service-accounts to create it.
Atention -> You need to give permission on Gmail, and create server key (with domain-wide access).
I think your access token doesn't contain all scopes you want. First try in API explorer. Check what are the scopes API explorer request from you and then add those scopes to your code(place where you get permission).
https://developers.google.com/apis-explorer
hope this solves your problem
Well, the error 403 or Insufficient Permission is returned when you have not requested the proper or complete scopes you need to access the API that you are trying to use. Here is the list of scopes with description that you can use with Gmail API.
To know the scope that you are using, you can verify it with this:
https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=xxxxxx
Note: You need to include all the scope that you are using and make
sure you enable all the API that you use in the Developer Console.
This Delegating domain-wide authority to the service
account
might also help.
For more information, check these related SO questions:
Gmail API: Insufficient Permission
How do I get around HttpError 403 Insufficient Permission?
I'm trying to set publish permissions for gmail to a pubsub topic in google cloud.
The application where I implemented this code is running in AWS.
It's a PHP application and I'm using version 2.0.0-RC7 of the google PHP api client.
In code, I implemented the flow as described in the documentation:
Create a topic (Works)
Create a subscription (works)
Grant publish rights to gmail (here I get stuck)
The first two actions are done with the same google client instance, that is authenticated with the service account credentials.
The code:
$scopes = [
'https://www.googleapis.com/auth/pubsub',
'https://mail.google.com',
];
$pushEndpoint = 'https://some.url/google_notifications/';
$client = new Google_Client();
$client->setScopes($scopes);
$client->setAuthConfig($serviceAccountInfo);
if ($client->isAccessTokenExpired()) {
$client->refreshTokenWithAssertion();
}
$service = new Google_Service_Pubsub($client);
// This part works
$topicObject = new Google_Service_Pubsub_Topic();
$topicObject->setName($this->getTopicName());
$service->projects_topics->create($this->getTopicName(), $topic);
// This part also works
$push = new Google_Service_Pubsub_PushConfig();
$push->setPushEndpoint($pushEndpoint);
$subscription = new Google_Service_Pubsub_Subscription();
$subscription->setName($this->getSubscriptionName());
$subscription->setTopic($this->getTopicName());
$subscription->setPushConfig($push);
$service->projects_subscriptions->create($this->getSubscriptionName(), $subscription);
// This part gives the error
$binding = new Google_Service_Pubsub_Binding();
$binding->setRole('roles/pubsub.publisher');
$binding->setMembers(['serviceAccount:gmail-api-push#system.gserviceaccount.com']);
$policy = new Google_Service_Pubsub_Policy();
$policy->setBindings([$binding]);
$setRequest = new Google_Service_Pubsub_SetIamPolicyRequest();
$setRequest->setPolicy($policy);
try {
$result = $service->projects_topics->setIamPolicy($this->getTopicName(), $setRequest);
var_dump($result);
} catch (\Exception $e) {
echo $e->getMessage();
}
The result is always:
{
"error": {
"code": 403,
"message": "User not authorized to perform this action.",
"errors": [
{
"message": "User not authorized to perform this action.",
"domain": "global",
"reason": "forbidden"
}
],
"status": "PERMISSION_DENIED"
}
}
Can someone tell me what I'm doing wrong ?
It's really annoying to set those permissions by hand all the time.
Thanks.
To use projects.topics.setIamPolicy method your service account must have a "Pub/Sub Admin" role. You can change a role of the account by visiting "IAM & admin" page for your project: https://console.cloud.google.com/iam-admin/iam