15

I have a problem just using an example of actual version of PHP api, and using the "service-account.php" file of examples folder.

the original is for show the "Books API", and with my personal credentials configuration it works well, but in my xcase I need to access by directory.groups.get service to have the list of members accounts of a google groups mail list, so I change the original code in this:

<?php

session_start();
include_once "templates/base.php";

/************************************************
  Make an API request authenticated with a service
  account.
 ************************************************/
require_once realpath(dirname(__FILE__) . '/../autoload.php');

/************************************************
 ************************************************/

// MY ACCOUNT DATA HERE
$client_id = 'xxx';
$service_account_name = 'xxx'; //Email Address 
$key_file_location = 'xxx.p12'; //key.p12
$groupKey = 'xxx';

echo pageHeader("My Service Account Access");
if ($client_id == '<YOUR_CLIENT_ID>'
    || !strlen($service_account_name)
    || !strlen($key_file_location)) {
  echo missingServiceAccountDetailsWarning();
}

$client = new Google_Client();
$client->setApplicationName("Client_Library_Examples");
//$service = new Google_Service_Books($client); //ORIGINAL
$service = new Google_Service_Directory($client);

/************************************************
 ************************************************/
if (isset($_SESSION['service_token'])) {
  $client->setAccessToken($_SESSION['service_token']);
}
$authArray = array(
                'https://www.googleapis.com/auth/admin.directory.group',
                'https://www.googleapis.com/auth/admin.directory.group.readonly',
                'https://www.googleapis.com/auth/admin.directory.group.member',
                'https://www.googleapis.com/auth/admin.directory.group.member.readonly'
);
$key = file_get_contents($key_file_location);
$cred = new Google_Auth_AssertionCredentials(
    $service_account_name,
    $authArray, //array('https://www.googleapis.com/auth/books'), //ORIGINAL
    $key
);
$client->setAssertionCredentials($cred);
if($client->getAuth()->isAccessTokenExpired()) {
  $client->getAuth()->refreshTokenWithAssertion($cred);
}
$_SESSION['service_token'] = $client->getAccessToken();


/************************************************
 ************************************************/
//$optParams = array('filter' => 'free-ebooks'); //ORIGINAL
$optParams = array('fields' => 'id');
//$results = $service->volumes->listVolumes('Henry David Thoreau', $optParams); //ORIGINAL
$results = $service->groups->get($groupKey, $optParams);
echo "<h3>Results Of Call:</h3>";
foreach ($results as $item) {
  //echo $item['volumeInfo']['title'], "<br /> \n"; //ORIGINAL
    echo "<pre>".print_r ($item, true)."</pre>";
}

echo pageFooter(__FILE__);

whatever I do, providing authorization for API SDK, and using file and credentials just created in API Credentials panel of the console's developer, I receive alwais the 403 error.

Here's the error stack:

#0 /var/www/html/google_local/google-api-php-client-master/src/Google/Http/REST.php(41): 
Google_Http_REST::decodeHttpResponse(Object(Google_Http_Request)) 
#1 /var/www/html/google_local/google-api-php-client-master/src/Google/Client.php(546): 
Google_Http_REST::execute(Object(Google_Client), Object(Google_Http_Request)) 
#2 /var/www/html/google_local/google-api-php-client-master/src/Google/Service/Resource.php(190): 
Google_Client->execute(Object(Google_Http_Request)) 
#3 /var/www/html/google_local/google-api-php-client-master/src/Google/Service/Directory.php(1494): 
Google_Service_Resource->call('get', Array, 'Google_Service_...') 
#4 /var/www/html/google_local/googl in /var/www/html/google_local/google-api-php-client-master/src/Google/Http/REST.php on line 76

Any suggestions?

Thanks, Roberto

djthoms
  • 3,026
  • 2
  • 31
  • 56
Roberto
  • 191
  • 1
  • 1
  • 12
  • 2
    Do you have the right permissions on your account to execute that method? I would recommend you try their console here: https://developers.google.com/apis-explorer/#p/admin/directory_v1/directory.groups.list -- that way, you can see a verbose and easy to understand explanation of why you're getting a 403. – mansilladev Oct 16 '14 at 17:30
  • hi, thanks for the answer! yes, the console give me 200 OK response in the page you indicate, and I receve also a 200 response in the test for members (the data that I want obtain by programming way) in https://developers.google.com/apis-explorer/#p/admin/directory_v1/directory.members.get – Roberto Oct 17 '14 at 09:05
  • Roberto, when you OAuth approve the Google console, check the scopes that it's asking permission for. They're likely visible in the URI. Ask for those same scopes in your array. – mansilladev Oct 17 '14 at 09:11
  • yes, I think that the scope is ok, in the code posted above I put everything in $authArray array for that. other suggestions? – Roberto Oct 17 '14 at 09:40
  • 1
    Are you certain that your google account is marked as an admin for your domain/group? – mansilladev Oct 17 '14 at 09:43
  • I understand now... ok the domain admin will create credentials for a project of his console, and I just need to add these datas in the configuration of my script, without be also my a domain admin. thanks, I will update about the success or not of my script! – Roberto Oct 17 '14 at 10:56
  • not working anyway.. :( it works with Book API, not with Admin SDK API... – Roberto Oct 17 '14 at 15:30
  • Ask your domain admin to try the console with their credentials. – mansilladev Oct 17 '14 at 15:30
  • yes, I tryied with a new project created from him and associated also to me (I'm now the co-owner of the project), I create in his project the new Client ID, and the result doesn't change – Roberto Oct 17 '14 at 15:35

1 Answers1

35

The root of the problem is that the service account is not an administrator on the domain, so it cannot access the Admin SDK Directory API. Instead, you need to enable domain-wide delegation for your service account, and then have the service account impersonate a domain admin when it makes the request:

$cred = new Google_Auth_AssertionCredentials(
    $service_account_name,
    $authArray,
    $key
);
$cred->sub = "admin@yourdomain.com";
Eric Koleda
  • 12,420
  • 1
  • 33
  • 51
  • it works!! yes, following exactly this way, the piece of code posted works perfectly, I can read all datas! thanks a lot! – Roberto Oct 21 '14 at 10:23
  • 3
    Life saver! Thank you! In C# you'd do it by making a copy of the GoogleCredential object: googleCredential = googleCredential.CreateWithUser("user@domain.com"); – Naner Nov 29 '17 at 22:02
  • 2
    I could finally finish my two days of authorization failure. Thank you so much. – eonil Oct 16 '19 at 13:42
  • 1
    @Elliptica You can look at [this answer](https://stackoverflow.com/questions/60262432/service-account-not-authorized-to-access-this-resource-api-while-trying-to-acces/60262433#60262433) for a Python solution – hilsenrat Feb 17 '20 at 12:27
  • 1
    100+ likes to this! Great answer. – Ravi Maniyar Jun 19 '20 at 10:50