Reputation: 1354
I'm building a small app on Google App Engine(PHP) that aim at synchronising an external source with a google group to have an up to date mailing list. (it should run as a GAE cron task)
The Google App Engine project and the google group are inside a GSuite domain.
The sources are here, See firestore2ggroup.php
The issue that I'm having is security related, when I try to call an API, I get a 403 error with no other details.
{
"error": {
"errors": [
{
"domain": "global",
"reason": "forbidden",
"message": "Not Authorized to access this resource/api"
}
],
"code": 403,
"message": "Not Authorized to access this resource/api"
}
}
I've followed the steps described here as a start point as it was close to my need:
https://medium.com/@Skaaptjop/access-gsuite-apis-on-your-domain-using-a-service-account-e2a8dbda287c
So I did the following :
In Google Cloud Console:
In GSuite admin :
update: I've even tried to add more rights, but it still doesn't work:
In my project, I've copied the JSON private key and I've set in app.yaml the variable GOOGLE_APPLICATION_CREDENTIALS with the name of the file.
I used this Google lib to access the Google group:
composer require google/apiclient:^2.0
try
{
$client = new Google_Client();
$client->setApplicationName('Pegass2GGroup');
$client->setScopes(
[
Google_Service_Directory::ADMIN_DIRECTORY_GROUP,
Google_Service_Directory::ADMIN_DIRECTORY_GROUP_MEMBER,
Google_Service_Directory::ADMIN_DIRECTORY_USER
]);
$client->useApplicationDefaultCredentials(true);
$access_token = $client->fetchAccessTokenWithAssertion();
print_r($access_token);
$service = new Google_Service_Directory($client);
/** @var $members Google_Service_Directory_Members */
$members = $service->members->listMembers($MAILING_LIST);
/** @var $member Google_Service_Directory_Member */
foreach ($members as $member)
{
print_r($member->getEmail());
}
echo "</pre>";
}
catch(Exception $e)
{
print_r($e);
echo "</pre>";
}
I can tell the private key is loaded, because the print_r($e) gives a long exception and the key is listed.
print_r($access_token); gives the following:
Array
(
[access_token] => dag2qssffdVpRZEr...0BsM_QUgQ
[expires_in] => 3599
[token_type] => Bearer
[created] => 1586787451
)
$MAILING_LIST : is the full email address of the mailing list
Upvotes: 3
Views: 122
Reputation: 1354
So the code above was missing the impersonation.
$client->setSubject($EMAIL_TO_IMPERSONATE); //[email protected]
to act as this email when touching data of other members of the domain.
Then I got this error :
(
[errors:protected] =>
[message:protected] => {
"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."
}
It was because I was requesting :
Google_Service_Directory::ADMIN_DIRECTORY_GROUP,
Google_Service_Directory::ADMIN_DIRECTORY_GROUP_MEMBER,
Google_Service_Directory::ADMIN_DIRECTORY_USER
but I forgot to add in GSuite API Security Management the following :
Google_Service_Directory::ADMIN_DIRECTORY_USER
after adding it, it worked. So if you request a set of role, all must be granted. Even If I didn't use Google_Service_Directory::ADMIN_DIRECTORY_USER, the fact that I ask it at connection time and one of it is not granted, block the whole connection.
I think I only need Google_Service_Directory::ADMIN_DIRECTORY_GROUP_MEMBER
So far my working scope to just list the members of a group was :
184920....0484899 (the client id)
Upvotes: 0