When using the below code to attempt to list messages received by a brand new gmail account I just set up, I get
[Google_Service_Exception] Error calling GET https://www.googleapis.com/gmail/v1/users/myGmailAccount%40gmail.com/messages: (500) Backend Error
I know the validation portion is working correctly because I'm able to make minor modifications and query the books api as shown in this example. Below is the code I'm using to attempt to query recent messages received...
const EMAIL = 'myGmailAccount#gmail.com';
private $permissions = [
'https://www.googleapis.com/auth/gmail.readonly'
];
private $serviceAccount = 'xxxxxxxxxxxxxxxxx#developer.gserviceaccount.com';
/** #var Google_Service_Gmail */
private $gmail = null;
/** #var null|string */
private static $serviceToken = null;
public function __construct()
{
$client = new Google_Client();
$client->setApplicationName($this->applicationName);
$this->gmail = new Google_Service_Gmail($client);
//authentication
if (isset(self::$serviceToken)) {
$client->setAccessToken(self::$serviceToken);
}
$credentials = new Google_Auth_AssertionCredentials(
$this->serviceAccount,
$this->permissions,
$this->getKey()
);
$client->setAssertionCredentials($credentials);
if($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($credentials);
}
self::$serviceToken = $client->getAccessToken();
}
public function getMessages()
{
$this->gmail->users_messages->listUsersMessages(self::EMAIL);
}
I have granted API access to gmail:
The 500 makes me believe this is an internal error with the gmail API or I'm missing something the PHP client isn't validating.
This one work for me. My understanding is service account doesn't have a mailbox and it's not too sure which mailbox it should work on. So you can't use listUsersMessages() function to get all messages.
So you will need to specify which email address that the service account need to work on.
Make sure that the scope has been allowed on Web App API to
1. Add this line:
$credentials->sub = self::EMAIL;
Before:
$client->setAssertionCredentials($credentials);
2. Then Update your getMessages() to:
$this->gmail->users_messages->listUsersMessages("me");
Hope this helps!
I imagine the account has logged in to the web interface already, right? Have you tried with a separate user? How about doing something like labels list instead? Did you try using the APIs explorer site? https://developers.google.com/apis-explorer/#p/gmail/v1/
Can you provide the first 5 digits of the developer's client ID (it's not secret anyway) so I can try to track down the error?
For this to work you have to impersonate an user account (the service account doesn't have a mailbox, as lthh89vt points out).
If you try to access the mailbox directly you will get the (500) Back End error.
The full code is:
$client_email = '1234567890-a1b2c3d4e5f6g7h8i#developer.gserviceaccount.com';
$private_key = file_get_contents('MyProject.p12');
$scopes = array('https://www.googleapis.com/auth/gmail.readonly');
$user_to_impersonate = 'user#example.org';
$credentials = new Google_Auth_AssertionCredentials(
$client_email,
$scopes,
$private_key,
'notasecret', // Default P12 password
'http://oauth.net/grant_type/jwt/1.0/bearer', // Default grant type
$user_to_impersonate,
);
$client = new Google_Client();
$client->setAssertionCredentials($credentials);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion();
}
$service = new Google_Service_Gmail($client);
$results = $service->users_messages->listUsersMessages('me');
Full instructions can be found on Google APIs Client Library for PHP
Related
I am trying to access to a calendar created by my application via cron, and I get a calendar with the same name that the calendar the application creates, but the id is absolutely different... This is my code:
public function cronTest()
{
$this->g_client = new Google_Client();
$this->g_client->setApplicationName($this->config->item("APPLICATION_NAME"));
$service = $this->getCronService("CalendarTest-46bde015a16.p12");
$calendar = $this->getCalendar($service);
}
private function getCronService($file)
{
$key = file_get_contents(CREDENTIALS_PATH.$file);
$cred = new Google_Auth_AssertionCredentials($this->config->item("google_service_id"), SCOPES, $key);
$this->g_client->setAssertionCredentials($cred);
if($this->g_client->getAuth()->isAccessTokenExpired())
$this->g_client->getAuth()->refreshTokenWithAssertion($cred);
return new Google_Service_Calendar($this->g_client);
}
private function getCalendar($service)
{
$calendarList = $service->calendarList->listCalendarList();
echo "getCalendar<br>";
foreach ($calendarList->getItems() as $calendarListEntry)
{
echo $calendarListEntry->getSummary()." with id:".$calendarListEntry->getId()."<br>";
echo "<br>";
if($calendarListEntry->getSummary()=="Auto-Citas")
echo "found";
//return $calendarListEntry->getId();
}
die;
}
When I execute it from the command line (simulating the cron):
wget www.domain.com/prototipo/alien/cronTest
I get this:
Calendar
Auto-Citas with id:h0gefmo7vjqlr4lp0r2n93vk9c#group.calendar.google.com
found
But, the id of calendar created with this application doesn´t match with this id...
Before this attempt with ron, I had to learn how to use the API, in this way I needed to remove sometimes the same calendar. So what I do, was remove one more time the Auto-Citas on my calendar, and call the function on my app to create a new calendar with a different name, then I made again the request of the "simulated cron" (wget www.domain.com/prototipo/alien/cronTest) and the result is the same than before: only one calendar called Auto-Citas, but nothing about the new calendar.
The functionality is to create a module anti-absenteeism, sending an email or sms to the user two hours before the appointment(cita=appointment)
For this tasks I have to function more... but they aren´t important for the case:
$events = $this->getDates($service,$calendar,$min,$max);
$this->transformDates($events, $service, ",phone");
Ok... I find solution just here (the google official docs). I need to use the option of user_to_impersonate.
$client_email = '1234567890-a1b2c3d4e5f6g7h8i#developer.gserviceaccount.com';
$private_key = file_get_contents('MyProject.p12');
$scopes = implode(' ', array(Google_Service_Calendar::CALENDAR));
$user_to_impersonate = 'user#example.org';
$credentials = new Google_Auth_AssertionCredentials(
$client_email,
$scopes,
$private_key,
'notasecret', // Default P12 password
'http://oauth.net/grant_type/jwt/1.0/bearer', // Default grant type
$user_to_impersonate,
);
I have a web app and trying to find out which users in google domain have installed my app. I've tried to use code from here: Determine if a google user's domain has my marketplace app installed, but it doesn't works. I am still getting error "(403) Not authorized to access the application ID" in response.
Code:
$private_key = file_get_contents('path_to_p.12_key');
$service_account_name = '{service_acc_name}'; // name from developers console
$cred = new Google_Auth_AssertionCredentials($service_account_name, array('https://www.googleapis.com/auth/appsmarketplace.license'), $private_key);
$client = new Google_Client();
$client->setAssertionCredentials($cred);
$url = "https://www.googleapis.com/appsmarket/v2/licenseNotification/{appID}";
$httpRequest = new Google_Http_Request($url, 'GET');
$httpRequest->setBaseComponent($client->getBasePath());
$httpRequest = $client->getAuth()->sign($httpRequest);
try
{
$result = $client->execute($httpRequest);
}
catch (Exception $e)
{
echo $e->getMessage();
}
I've also added https://www.googleapis.com/auth/appsmarketplace.license scope in project settings in developers console.
I can't get what's wrong.
OK, I've solved it. You must add all scopes to your service account object that used by your app (not just that scopes you are really want to use by service account):
$cred = new Google_Auth_AssertionCredentials($service_account_name, array('https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/admin.directory.user.readonly', 'https://www.googleapis.com/auth/admin.directory.user', 'https://www.googleapis.com/auth/appsmarketplace.license'), $private_key);
I am trying to list emails from a standard Gmail account (not a Google Apps account) using OAuth2 and a Service Account (actually, I want to send emails – but that can wait).
I have created the Project, created the service account, downloaded the private key, and enabled the Gmail API (and the Calendar API). I can successfully access my calendar using code very similar to the code below. However, I am receiving the following error when attempting to list mail messages.
Error refreshing the OAuth2 token, message: error_description "Unauthorized client or scope in request."
(For info. If I comment out the $credential->sub = … line, I get the following error: “(500) Backend Error” and I can see that this is logged in the Usage tab of the Developers API page).
Can anyone confirm that what I am trying to do is possible? And if so, any ideas where to go next?
Here is my code:
class mail
{
private $service;
public function __construct($clientid, $keyfile, $account_name, $app_name)
{
$client = new Google_Client();
$client->setApplicationName($app_name);
$this->service = new Google_Service_Gmail($client);
// Load the key in PKCS 12 format
$key = file_get_contents($keyfile);
$client->setClientId($clientid);
$credentials = new Google_Auth_AssertionCredentials(
$account_name, array('https://mail.google.com/'),$key);
$credentials->sub = 'myemailaddress...#gmail.com';
$client->setAssertionCredentials($credentials);
}
public function list_mail()
{
try
{
$result = $this->service->users_messages->listUsersMessages("me");
}
catch (Exception $e)
{
throw new Exception("Gmail API error: ".$e->getMessage()."<br />");
}
return $result;
}
}
$mail_obj = new mail(CLIENT_ID, KEY_FILE, SERVICE_ACCOUNT_NAME, APP_NAME);
$result = $mail_obj->list_mail();
I'm having a problem implementing Google Admin SDK in PHP. It always give error
Fatal error: Uncaught exception 'Google_Service_Exception' with message 'Error calling POST
https://www.googleapis.com/admin/directory/v1/users: (403) Not Authorized to access this
resource/api' in ..\google-api-php-client\src\Google\Http\REST.php on line 79
Here is my code :
<?php
session_start();
/* * **********************************************
Make an API request authenticated with a service
account.
* ********************************************** */
set_include_path("google-api-php-client/src" . PATH_SEPARATOR . get_include_path());
require_once 'Google/Client.php';
require_once 'Google/Service/Directory.php';
/* * **********************************************
ATTENTION: Fill in these values! You can get
them by creating a new Service Account in the
API console. Be sure to store the key file
somewhere you can get to it - though in real
operations you'd want to make sure it wasn't
accessible from the webserver!
The name is the email address value provided
as part of the service account (not your
address!)
Make sure the Books API is enabled on this
account as well, or the call will fail.
* ********************************************** */
$client_id = 'my_client_id'; //Client ID
$service_account_name = 'email'; //Email Address
$key_file_location = 'key.p12'; //key.p12
if ($client_id == '<YOUR_CLIENT_ID>' || !strlen($service_account_name) || !strlen($key_file_location)) {
echo missingServiceAccountDetailsWarning();
}
$client = new Google_Client();
$client->setApplicationName("appname");
$service = new Google_Service_Directory($client);
/* * **********************************************
If we have an access token, we can carry on.
Otherwise, we'll get one with the help of an
assertion credential. In other examples the list
of scopes was managed by the Client, but here
we have to list them manually. We also supply
the service account
* ********************************************** */
if (isset($_SESSION['service_token'])) {
$client->setAccessToken($_SESSION['service_token']);
}
$key = file_get_contents($key_file_location);
$cred = new Google_Auth_AssertionCredentials(
$service_account_name, array('https://www.googleapis.com/auth/admin.directory.user'), $key
);
$client->setAssertionCredentials($cred);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
$_SESSION['service_token'] = $client->getAccessToken();
/* * **********************************************
We're just going to make the same call as in the
simple query as an example.
* ********************************************** */
$familyName = filter_input(INPUT_GET, 'familyname');
$givenName = filter_input(INPUT_GET, 'givenname');
$password = filter_input(INPUT_GET, 'password');
$primaryEmail = filter_input(INPUT_GET, 'email');
$user = new Google_Service_Directory_User();
$name = new Google_Service_Directory_UserName();
$name->setFamilyName($familyName);
$name->setGivenName($givenName);
$user->setName($name);
$user->setHashFunction("MD5");
$user->setPrimaryEmail($primaryEmail);
$user->setPassword(hash("md5", $password));
$result = $service->users->insert($user);
There is no documentation and I'm very confused with this error.
I had a similar problem until I set the "sub" account on the credentials object which is the email address for the administrative user that you want to perform the API action as.
So in Google Apps Admin for your domain I assume you've created a user and added them to and admin role that has API access to users right? In your code above you just need to add (with correct email address of course):
$cred->sub = "adminuser#domain.com";
Add that right before:
$client->setAssertionCredentials($cred);
I did a full example for someone else that you might be able to reference too: https://gist.github.com/fillup/9fbf5ff35b337b27762a
I had a similar problem but found a solution to this by going through this blog
http://michaelseiler.net/2014/12/16/google-admin-sdk-api-with-php/
Assuming you have done all the necessary setting up on the Admin Console (i.e. delegating domain authority), then pay particular attention to the line
`$cred = new Google_Auth_AssertionCredentials($service_account_name, array('https://www.googleapis.com/auth/admin.directory.user'), $key);`
this should be:
`$user_to_impersonate = 'adminaccount#example.com';$scopes =array('https://www.googleapis.com/auth/admin.directory.user');$cred = new Google_Auth_AssertionCredentials(
$service_account_name,
$scopes,
$key,
'notasecret', // Default P12 password
'http://oauth.net/grant_type/jwt/1.0/bearer', // Default grant type
$user_to_impersonate);`
I changed that and boom....
I think i was receiving this error when i tried to query a user.
During the creation of the JWT_CLAIM portion of the assertion, you must specify a domain admin account that your service account can impersonate... this part was poorly documented, i thought.
i dont know exactly how the google php library does it, but i didnt see anywhere in your code where you specify that account email address. if you have looked at the oauth2 documentation, in the jwt_claim secion, there is an "additional claims" subsection that says:
To obtain an access token that grants an application delegated access to a resource, include the email address of the user in the JWT claim set as the value of the sub field.
I had to include that admin email account in the creation of my assertion before i could even query the directory.users API.
i apologize if this isnt helpful, but im not using the library for php, im building my own (with php).
i am using php 5.3.3, and codeigniter 2.1.0.
what i want to do is set up a service account, so a user can add an appointment in a text entry field on my website, then have that appointment added to a shared shared google calendar.
i have a google account, and using : https://code.google.com/apis/console I created a new project called 'pqp'
on services: enabled the calendar api
on api access: i created an oath 2.0 client id… product name = pqp, application type = service account.
downloaded the key 46… -privatekey.p12. there is a screenshot of the settings:
I got an svn checkout of the google-api-php-client (28/6/2012)
In the google-api-php-client/src/config.php I changed lines:
25: 'application_name' => 'pqp',
28: 'oauth2_client_id' => '373xxx730.apps.googleusercontent.com',
57: 'ioFileCache_directory' => 'tmp/apiClient', // my apache user does not have access to the system /tmp folder. + tmp/apiClient has permissions of 777 on the server.
using this link:
http://code.google.com/p/google-api-php-client/source/browse/trunk/examples/prediction/serviceAccount.php?spec=svn445&r=395
I modified it to:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Test extends CI_Controller{
function __construct()
{
parent::__construct();
}
function index()
{
set_include_path(get_include_path() . PATH_SEPARATOR .dirname(__FILE__).'/../libraries/google-api-php-client/src');
ini_set('error_reporting',E_ALL);
ini_set('display_errors','1');
// Set your client id, service account name, and the path to your private key.
// For more information about obtaining these keys, visit:
// https://developers.google.com/console/help/#service_accounts
define('CLIENT_ID','3731xxx44730.apps.googleusercontent.com');
define('SERVICE_ACCOUNT_NAME','373xxx244730#developer.gserviceaccount.com');
// Make sure you keep your key.p12 file in a secure location, and isn't
// readable by others.
define('KEY_FILE',dirname(__FILE__).'/../../461290xxx796c0b7db9582c-privatekey.p12');
require_once "apiClient.php";
require_once "contrib/apiCalendarService.php";
$client = new apiClient();
$client->setApplicationName("pqp");
// Set your cached access token. Remember to replace $_SESSION with a
// real database or memcached.
session_start();
if (isset($_SESSION['token'])) {
$client->setAccessToken($_SESSION['token']);
echo 'client access token is set.<br/>';
}
// Load the key in PKCS 12 format (you need to download this from the
// Google API Console when the service account was created.
$key = file_get_contents(KEY_FILE);
$creds = new apiAssertionCredentials(SERVICE_ACCOUNT_NAME,array('https://www.googleapis.com/auth/calendar'),$key);
$client->setAssertionCredentials($creds);
$client->setClientId(CLIENT_ID);
$service = new apiCalendarService($client);
echo 'client:<br/>';
var_dump($client);
echo 'service:<br/>';
var_dump($service);
// We're not done yet. Remember to update the cached access token.
// Remember to replace $_SESSION with a real database or memcached.
if ($client->getAccessToken()) {
$_SESSION['token'] = $client->getAccessToken();
echo 'token is good!, so creating an event....';
echo $this->insert_event($service,'testing summary','my location','2012-06-29T10:00:00.000+10:00','2012-06-29T10:00:00.000+10:00');
}
}
function insert_event($service,$summary,$location,$from,$to){
$event = new Event();
$event->setSummary($summary);
$event->setLocation($location);
$start = new EventDateTime();
$start->setDateTime($from);
$event->setStart($start);
$end = new EventDateTime();
$end->setDateTime($to);
$event->setEnd($end);
$attendee1 = new EventAttendee();
$attendee1->setEmail('test#example.com');
$attendees = array($attendee1);
$event->attendees = $attendees;
$createdEvent = $service->events->insert('primary', $event);
return $createdEvent->getId();
}
}
a pastie of the output is here:
the $client object is not authenticated, the getAccessToken is not set, and the event is not inserted.
i have found it difficult to work out which settings in the $config file to change because there is different nomenclature. i guess this is an artifact of how the code has progressed.
are the settings in src/config.php correct? do i need to alter any more settings?
it is my understanding that if i create the service account, download the key file, and the contents of this file with my developer id, it should return a token, and there is no need to set up a redirection uri.. is that correct? this is the functionality i want. i don't want the user to have to authorise access because the website will only ever interact with one google account.
So, the question is, how do i get this calendar api to authenticate using a google service account?
You can try this one if you not already...
EDIT: this one intresting but if you still feel like to write one yourself then try this THE mother of the oauth2. helpful
About Service Account at google-api-php-client that you use(always take the trunk's one with SVN) I can't found in that code manipulations any reference apiAssertionCredentials::generateAssertion()
definitely there is no call to auth in there
public function __construct(
$serviceAccountName,
$scopes,
$privateKey,
$privateKeyPassword = 'notasecret',
$assertionType = 'http://oauth.net/grant_type/jwt/1.0/bearer',
$prn = false) {
$this->serviceAccountName = $serviceAccountName;
$this->scopes = is_string($scopes) ? $scopes : implode(' ', $scopes);
$this->privateKey = $privateKey;
$this->privateKeyPassword = $privateKeyPassword;
$this->assertionType = $assertionType;
$this->prn = $prn;
}
and this method should be called I guess...
public function generateAssertion() {
$now = time();
$jwtParams = array(
'aud' => apiOAuth2::OAUTH2_TOKEN_URI,
'scope' => $this->scopes,
'iat' => $now,
'exp' => $now + self::MAX_TOKEN_LIFETIME_SECS,
'iss' => $this->serviceAccountName,
);
if ($this->prn !== false) {
$jwtParams['prn'] = $this->prn;
}
return $this->makeSignedJwt($jwtParams);
}
EDIT:
Pardon. In fresh ver. look's like it's Google_OAuth2::refreshTokenWithAssertion() actualy who should start the real proces