Unable to get Google OAuth Token - php

I'm trying to add calendar events to my Google calendar from a php script. Note that I can do this successfully directly from a Google test page so I think that my calendar is set up correctly. However, when I attempt do this from a php script, I'm not able to get the OAuth2 token.
The following script, mostly taken from a Google example, runs without error, but it always winds up with a "Connect Me!" link. When I click on this link, it takes me to a validation screen that warns me that this app would like to manage my calendars. I click 'Accept' and a then see my calendar. A little inconvenient, but if this gets the OAuth token, fine.
I then go back and run the script again, hoping that the access token will now be available, but I get exactly the same result. No matter how many times I run this script, I never get the token, which I need in order to expand the script to add events to the calendar.
I've been at this for days, and I'm just not getting anywhere. Can anyone help? Thanks.
<?php
require_once '../../src/Google_Client.php';
require_once '../../src/contrib/Google_CalendarService.php';
require_once '../../src/auth/Google_OAuth2.php';
session_start();
$client = new Google_Client();
$client->setApplicationName("Add Google Calendar Entries");
// Visit https://code.google.com/apis/console?api=calendar to generate your
// client id, client secret, and to register your redirect uri.
$client->setClientId('843319906820-1s1d737e77o71a3vaskf434k3ape1fk5.apps.googleusercontent.com');
$client->setClientSecret('AP5imn3e0TEWNyLTCNm8YJj6');
$client->setRedirectUri('https://www.google.com/calendar/');
$client->setDeveloperKey('AIzaSyDIw3ks7AmrIrRxjO9y2gWBhQDYHFWd-uc');
$client->setUseObjects(true);
$cal = new Google_CalendarService($client);
if (isset($_GET['logout'])) {
unset($_SESSION['token']);
}
if (isset($_GET['code'])) {
$client->authenticate($_GET['code']);
$_SESSION['token'] = $client->getAccessToken();
header('Location: http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']);
}
if (isset($_SESSION['token'])) {
$client->setAccessToken($_SESSION['token']);
}
if ($client->getAccessToken()) {
$calList = $cal->calendarList->listCalendarList();
print "<h1>Calendar List</h1><pre>" . print_r($calList, true) . "</pre>";
$_SESSION['token'] = $client->getAccessToken();
} else {
$authUrl = $client->createAuthUrl();
print "<a class='login' href='$authUrl'>Connect Me!</a>";
}
?>
EDIT: Attempting to implement the suggestion from Vinicius Pinto. I've changed my redirect to point directly back to this script. Now I get this error:
Fatal error: Uncaught exception 'Google_ServiceException' with message
'Error calling GET
https://www.googleapis.com/calendar/v3/users/me/calendarList?key=AIzaSyDIw3ks7AmrIrRxjO9y2gWBhQDYHFWd-uc:
(403) Access Not Configured. Please use Google Developers Console to
activate the API for your project.' in
D:\Hosting\11347607\html\scripts\google-api-php-client\src\io\Google_REST.php:66
Stack trace: #0
D:\Hosting\11347607\html\scripts\google-api-php-client\src\io\Google_REST.php(36):
Google_REST::decodeHttpResponse(Object(Google_HttpRequest)) #1
D:\Hosting\11347607\html\scripts\google-api-php-client\src\service\Google_ServiceResource.php(186):
Google_REST::execute(Object(Google_HttpRequest)) #2
D:\Hosting\11347607\html\scripts\google-api-php-client\src\contrib\Google_CalendarService.php(205):
Google_ServiceResource->__call('list', Array) #3
D:\Hosting\11347607\html\scripts\google-api-php-client\examples\calendar\simple.php(43):
Google_CalendarListServiceResource->listCalen in
D:\Hosting\11347607\html\scripts\google-api-php-client\src\io\Google_REST.php
on line 66
It would appear that I don't have the correct APIs activated in the developer console. I have the Calendar API and the Google Cloud Storage JSON API activated and nothing else. I don't see any other APIs that would be relevant, and I don't think that this message is telling me which APIs it wants.
EDIT 2: Looks like I was using the wrong developer key. I've changed it to the key for server applications. Now my error is this:
Fatal error: Uncaught exception 'Google_AuthException' with message
'Error refreshing the OAuth2 token, message: '{ "error" :
"invalid_client" }'' in
D:\Hosting\11347607\html\scripts\google-api-php-client\src\auth\Google_OAuth2.php:288
Stack trace: #0
D:\Hosting\11347607\html\scripts\google-api-php-client\src\auth\Google_OAuth2.php(248):
Google_OAuth2->refreshTokenRequest(Array) #1
D:\Hosting\11347607\html\scripts\google-api-php-client\src\auth\Google_OAuth2.php(225):
Google_OAuth2->refreshToken('1/6ZdJyZALqcbwW...') #2
D:\Hosting\11347607\html\scripts\google-api-php-client\src\service\Google_ServiceResource.php(167):
Google_OAuth2->sign(Object(Google_HttpRequest)) #3
D:\Hosting\11347607\html\scripts\google-api-php-client\src\contrib\Google_CalendarService.php(205):
Google_ServiceResource->__call('list', Array) #4
D:\Hosting\11347607\html\scripts\google-api-php-client\examples\calendar\simple.php(47):
Google_CalendarListServiceResource->listCalendarList() in
D:\Hosting\11347607\html\scripts\google-api-php-client\src\auth\Google_OAuth2.php
on line 288

The $client->setRedirectUri() should receive a URL pointing to your application, because this is the URL that you'll be redirected to after you authorize the application in the Google page. That's why you are being redirect to the calendar, because you are using the calendar URL.
It seems like your script is already expecting a $_GET['code'], so try setting the redirect URL to the url of this script. You'll also need to set the same URL in the Developers Console, under API -> Credentials.
You only get a token when you call $client->authenticate($_GET['code']); with a value code.
Take a look at this lib I just commited to Github, it's an early version, but it's working fine (I'm using to access YouTube). It's using the new official library.
Update: as said in the comments, the developer key isn't actually required for this to work, even though all Google sample code sets it.

Related

How do I connect to private google calendar with PHP

I'm not very good with PHP, and I am trying to create a webpage where I will navigate to the page and it will show a list of events from my private google calendar. This used to work years ago, but Google has changed the API so my old solution is broken. I saw this thread:
How do I connect to the Google Calendar API without the oAuth authentication?
and I tried it, but it looks like that method also doesn't work anymore. (When I say "doesn't work" I mean that I currently have the latest google-api-php-client-2.0.3 installed at public_html/includes/google-api-php-client-2.0.3/. I found the client.php referenced in the above link, but the other files are not in the new API.
Basically, I am trying to figure out what the PHP would look like to achieve what you can do on this page when you put in your calendar ID:
https://developers.google.com/google-apps/calendar/v3/reference/events/list#request
So I think this is a two step process: Authenticate and then print the output. The trouble I'm having is in authenticating.
I have tried this:
<?php
session_start();
require_once "/includes/google-api-php-client-2.0.3/src/Google/client.php";
require_once "/includes/google-api-php-client-2.0.3/src/contrib/Google_CalendarService.php";
const CLIENT_ID = '...';
const SERVICE_ACCOUNT_NAME = 'my service account name';
// Make sure you keep your key.p12 file in a secure location, and isn't
// readable by others.
const KEY_FILE = '...';
$client = new Google_Client();
$client->setApplicationName("...");
if (isset($_SESSION['token'])) {
$client->setAccessToken($_SESSION['token']);
}
// 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);
$client->setAssertionCredentials(new Google_AssertionCredentials(
SERVICE_ACCOUNT_NAME,
array('https://www.googleapis.com/auth/calendar', "https://www.googleapis.com/auth/calendar.readonly"),
$key)
);
$client->setClientId(CLIENT_ID);
$service = new Google_CalendarService($client);
//Save token in session
if ($client->getAccessToken()) {
$_SESSION['token'] = $client->getAccessToken();
}
//And now you can use the code in their PHP examples, like: $service->events->listEvents(...)
?>
But I get error:
Warning: require_once(/includes/google-api-php-client-2.0.3/src/Google_Client.php): failed to open stream: No such file
Because the API seems to have changed.
I found this link:
https://developers.google.com/identity/protocols/OAuth2ServiceAccount
I have created a service account, and downloaded a private key but I don't know what to do with it :-/
I tried this:
https://developers.google.com/api-client-library/php/auth/web-app
But when I navigate to the index.php I get this error:
Fatal error: Uncaught exception 'InvalidArgumentException' with message 'file does not exist' in /home/xxx/public_html/includes/google-api-php-client-2.0.3/src/Google/Client.php:841 Stack trace: #0 /home/xxx/public_html/testing_oauth.php(7): Google_Client->setAuthConfig('client_secrets....') #1 {main} thrown in /home/xxx/public_html/includes/google-api-php-client-2.0.3/src/Google/Client.php on line 841
I tried hard coding this into the index.php example (line 103-107):
// https://developers.google.com/console
'client_id' => 'My service accounts project name',
'client_secret' => 'url link to my client_secret.json file',
'redirect_uri' => null,
'state' => null,
But I get the same error...

Google Calendar API error redirect_uri_mismatch

I am trying to use the google API to manage the user´s calendar, and I am finding a problem. I created and configured a google project on the Google Developers Console. One of the settings was the allowed redirecting uris... and I think it is ok, because after some test where google threw the same error (redirect_uri_mismatch), I got that google ask me for permissions... the problem I think is this line: $this->client->authenticate($_GET['code']);
I am going to show the code and explain what it does
function __construct()
{
parent::__construct();
require __DIR__ . '/vendor/autoload.php';
define('APPLICATION_NAME', 'Google Calendar API PHP Quickstart');
define('CLIENT_SECRET_PATH', __DIR__ . '/credentials/client_secret.json');
define('CREDENTIALS_PATH', __DIR__ .'/credentials/');
define('SCOPES', implode(' ', array(Google_Service_Calendar::CALENDAR_READONLY)));
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/calendar-php-quickstart.json
$this->client = new Google_Client();
$this->client->setApplicationName(APPLICATION_NAME);
$this->client->setScopes(SCOPES);
$this->client->setAuthConfigFile(CLIENT_SECRET_PATH);
if (!file_exists(CLIENT_SECRET_PATH.$this->session->userdata("identity").".json") && !$this->input->get("code"))
$this->getCredentials();
}
public function responseCredentials()
{
$authCode = $this->input->get("code");
$this->client->authenticate($_GET['code']);
$accessToken = $this->client->client->getAccessToken();
$credentialsPath = CLIENT_SECRET_PATH.$this->session->userdata("identity").".json";
mkdir(dirname($credentialsPath), 0700, true);
file_put_contents($credentialsPath, $accessToken);
redirect(base_url("dashboard"));
}
private function getCredentials()
{
$this->client->setRedirectUri(base_url('calendar/responseCredentials'));
$authUrl = $this->client->createAuthUrl();
header('Location: ' . filter_var($authUrl, FILTER_SANITIZE_URL));
}
Ok... the first... the constructor it load the google api autoloader, and the constants, creates a new Google_Client object, and inspect if exists a permissions file for the user and there is no "code" index on the get.
If not it invokes the getCredentials function that redirect to google.
After give permissions, the user is redirect to http://domain.com/calendar/responseCredentials (that it is configured on the console.developers.google)
The error thrown is this:
Fatal error: Uncaught exception 'Google_Auth_Exception' with message
'Error fetching OAuth2 access token, message: 'redirect_uri_mismatch'' in
/var/www/html/prototipo/application/controllers/vendor/google/apiclient/src/Google/Auth/OAuth2.php:126
Stack trace:
#0 /var/www/html/prototipo/application/controllers/vendor/google/apiclient/src/Google/Client.php(128): Google_Auth_OAuth2->authenticate('4/rkAKNAmiVgs1Z...', false)
#1 /var/www/html/prototipo/application/controllers/calendar.php(52): Google_Client->authenticate('4/rkAKNAmiVgs1Z...')
#2 [internal function]: Calendar->responseCredentials()
#3 /var/www/html/prototipo/system/core/CodeIgniter.php(360): call_user_func_array(Array, Array)
#4 /var/www/html/prototipo/index.php(202): require_once('/var/www/html/p...')
#5 {main} thrown in/var/www/html/prototipo/application/controllers/vendor/google/apiclient/src/Google/Auth/OAuth2.php on line 126
What am I doing wrong??
Thank you.
EDIT
I just realized that at the end of the code variable on the return uri there always is a pad... something like this:
http://pedro.eatec.es/prototipo/calendar_test_stack/responseCredentials?code=4/PL7nK1s9m5vpBow7HScaPmkpWpoW3J4uzUxlD7NE49g#
The example here: https://developers.google.com/identity/protocols/OAuth2WebServer#handlingresponse doesn´t show this pad... I tried to do this:
$this->client->authenticate($_GET['code']."#");
But... of course, doesn´t work.
PS: I tried to do it because with echo $_GET['code']; didn´t show the pad.
Hello and Thanks #thepieterdc finally you were reason...
I was setting up correctly the project on console.developers... but my mistake was that I need make some trying to get a correct configuration and when I got to make disappear the error 400 (with the broken robot) and it ask me for permission, on the redirecting function when I make $this->g_client->authenticate($_GET['code']); the code try to make other request (on OAuth2.php) to https://accounts.google.com/o/oauth2/token and it use the client_id.json that you need to refresh... and I didn´t. I WAS USING THE FIRST EDITION OF THE CLIENT_ID.JSON I need to re-download (or re-write) if you change something on the console.
Thanks.

Unauthorized 401 on Google+ API moments.insert with PHP

I want to create a small bot, which can push G+ moments to G+ page under certain conditions. Want to try it with PHP. So I have: registered web app in Google Console, Google+ API turned on, small PHP-script on my Apache server and 401 Unathorized in result. I'm using google-api-php-client from https://github.com/google/google-api-php-client
I've searched answer through the Internet, but nothing've found. Everywhere everyone have had their own happy end and all worked, but I've try all of it - and only 401 came to me.
My script:
<?
header("Content-Type: text/html; charset=utf-8");
session_start();
ini_set("display_errors", 1);
require_once 'Google/Client.php';
require_once 'Google/Service/Plus.php';
$client = new Google_Client();
$client->setClientId("MY_CLIENT_ID");
$client->setClientSecret("MY_CLIENT_SECRET");
$client->setRedirectUri("REDIRECT_URL");
$client->setAccessType('offline');
$client->addScope("https://www.googleapis.com/auth/plus.login");
$client->addScope("https://www.googleapis.com/auth/plus.me");
$client->addScope("https://www.googleapis.com/auth/userinfo.profile");
$client->addScope("https://www.googleapis.com/auth/userinfo.email");
$requestVisibleActions = array('http://schemas.google.com/AddActivity');
$client->setRequestVisibleActions($requestVisibleActions);
if (!isset($_GET['code'])) {
if (isset($_SESSION['access_token'])) {
$client->setAccessToken($_SESSION['access_token']);
$moment_body = new Google_Service_Plus_Moment();
$plus = new Google_Service_Plus($client);
$moment_body->setType("http://schemas.google.com/AddActivity");
$item_scope = new Google_Service_Plus_ItemScope();
$item_scope->setId("target-id-214wdefsadf1");
$item_scope->setType("http://schemas.google.com/AddActivity");
$item_scope->setName("The Google+ Platform");
$item_scope->setDescription("A page that describes just how awesome Google+ is!");
$item_scope->setImage("https://developers.google.com/+/plugins/snippet/examples/thing.png");
$moment_body->setTarget($item_scope);
$momentResult = $plus->moments->insert('me', 'vault', $moment_body);
} else {
$authUrl = $client->createAuthUrl();
header("Location: ".$authUrl);
exit;
}
} else {
$client->authenticate($_GET['code']);
$_SESSION['access_token'] = $client->getAccessToken();
header("Location: REDIRECT_URL");
exit;
}
So script succefully requests all needed access accordingly to scopes registered in client, gets a token, writes it into session, but when it try to insert new moment it gets Fatal error: Uncaught exception 'Google_Service_Exception' with message 'Error calling POST https://www.googleapis.com/plus/v1/people/me/moments/vault: (401) Unauthorized' in /var/www/rico/Google/Http/REST.php:79
What is wrong? And I've try some solutions placed here, on stackoveflow, but they didn't help. I also checked my authURL - it seems OK, with correct request_visible_actions and other... I don't know what is wrong...
You may be missing a few things. Maybe your example assumes you are putting the real values for some of these you have set. However you will want ApplicationName and DeveloperKey set. Many api calls will return not authorized if you don't have the developer key set for sure.
$client->setApplicationName($plApp->authenticationData->applicationName);
$client->setDeveloperKey($authData->apiKey);
I presume you are actually setting these below. Return url must match that which was set for the application on the google developer site for the specific application
$client->setClientId($authData->clientId);
$client->setClientSecret($authData->clientSecret);
$client->setRedirectUri($returnUrl);

Create google calendar events with php and service account - authenticate issue

Is it possible to access google calendar service while using service-account-method?
Google says indirectly, it is not possible, because calendar-service is not on the list of supported services in the documentation of service-account-method, but I personally think, it IS possible.
But how?
I am writing a calendar application in php, and there I want to create calendar events into my google-calendar without user-action (e.g. login).
I learned, that first the application has to authenticate itself against google server, using the service-account-method with a key-file .p12
I am using the following code for authentication:
(downloaded fom here: http://code.google.com/p/google-api-php-client/source/browse/trunk/examples/prediction/serviceAccount.php )
session_start();
require_once 'google-api/src/Google_Client.php';
require_once 'google-api/src/contrib/Google_CalendarService.php';
require_once 'google-api/src/contrib/Google_PredictionService.php';
$client = new Google_Client();
$client->setApplicationName(GOOGLE_APPLICATION_NAME);
$client->setClientId(GOOGLE_CLIENT_ID);
$keyfile = file_get_contents(GOOGLE_KEY_FILE);
$client->setAssertionCredentials(new Google_AssertionCredentials(
GOOGLE_SERVICE_ACCOUNT_NAME,
array('https://www.googleapis.com/auth/prediction'),
$keyfile)
);
But this login seems not to work.
How do I find out, if server is logged in at that moment?
I want to continue with this:
$cal = new Google_CalendarService($client);
if (isset($_SESSION['token'])) {
$client->setAccessToken($_SESSION['token']);
}
if ($client->getAccessToken()) {
$calList = $cal->calendarList->listCalendarList(); // <- this is line 55
print "<h1>Calendar List</h1><pre>" . print_r($calList, true) . "</pre>";
$_SESSION['token'] = $client->getAccessToken();
} else {
$authUrl = $client->createAuthUrl();
print "<a class='login' href='$authUrl'>Connect Me!</a>";
}
But in line 55 there comes this error:
Fatal error: Uncaught exception 'Google_ServiceException' with message
'Error calling GET
https://www.googleapis.com/calendar/v3/users/me/calendarList: (403)
Insufficient Permission' in
/usr/www/users/leuchtk/html/google-api/src/io/Google_REST.php:66
Stack trace: #0
/usr/www/users/leuchtk/html/google-api/src/io/Google_REST.php(36):
Google_REST::decodeHttpResponse(Object(Google_HttpRequest))
#1 /usr/www/users/leuchtk/html/google-api/src/service/Google_ServiceResource.php(186):
Google_REST::execute(Object(Google_HttpRequest))
#2 /usr/www/users/leuchtk/html/google-api/src/contrib/Google_CalendarService.php(205):
Google_ServiceResource->__call('list', Array)
#3 /usr/www/users/leuchtk/html/i_termine_admin.php(55): Google_CalendarListServiceResource->listCalendarList()
#4 /usr/www/users/leuchtk/html/termine_admin.php(113): include('/usr/www/users/...')
#5 {main} thrown in /usr/www/users/leuchtk/html/google-api/src/io/Google_REST.php on line 66
So it looks like, the application is not logged in.
I am completely lost in this code for now.
Thank you for some little light, what is missing there...
Marco
You may want to refer to this question. Your issue could be just to add the
array('https://www.googleapis.com/auth/calendar', 'https://www.googleapis.com/auth/calendar.readonly'),
in where you call the
$client->setAssertionCredentials();
Google PHP Client API: Insufficient Permission
Hope this helps

Google Analytics API 401 Invalid Credentials

I'm wracking my brain trying to figure out how to use the Google API PHP Client to access Google Analytics. Specifically, I want to upload cost data from other campaigns. My code does work to get information from GA, I can view traffic data for profiles, but I cannot figure out how to upload.
Here's the code that I'm using for auth:
require_once 'google-api-php-client/src/Google_Client.php';
require_once 'google-api-php-client/src/contrib/Google_AnalyticsService.php';
session_start();
$client = new Google_Client();
$client->setApplicationName("GA-Tester");
$client->setClientId('xxx.apps.googleusercontent.com');
$client->setClientSecret('xxx');
$client->setRedirectUri('http://www.site.com/indext.php');
$client->setDeveloperKey('xxx');
$analyticsService = new Google_AnalyticsService($client);
$dailyUploads = $analyticsService->management_dailyUploads;
if (isset($_GET['logout'])) {
unset($_SESSION['token']);
}
if (isset($_GET['code'])) {
$client->authenticate();
$_SESSION['token'] = $client->getAccessToken();
$redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
}
if (isset($_SESSION['token'])) {
$client->setAccessToken($_SESSION['token']);
}
if (!$client->getAccessToken()) {
header ('Location:http://www.site.com/indext.php');
} else {...
This code does work for requesting data. I can get a list of accounts, profiles, download traffic data for a specific profile, etc. No errors or issues.
When I try to upload my CSV file containing cost data I get a '401 Invalid Credentials' error. Here's the code that sends the file:
$send = $dailyUploads->upload(
$accountId,
$webPropertyId,
$customDataSourceId,
$start_date,
1,
'cost',
array(
"reset" => true,
"data" => $cont,
"mimeType" => "application/octet-stream",
"uploadType" => "media"));
I've double checked all of my variables that I'm passing, they're sending the correct information.
So here's my question. If all of my GET requests work without issue, why would my POST request throw an error? I can't tell if this is an error with my code, or with settings in the API console. Can anyone steer me in the right direction?
EDIT:
Here's the error code generated (minus identifiable bits).
Fatal error: Uncaught exception 'Google_ServiceException' with message
'Error calling POST https://www.googleapis.com/upload/analytics/v3/man
agement/accounts/1234567/webproperties/UA-1234567-1/customDataSources/
xXxXxX/dailyUploads/2013-01-17/uploads?appendNumber=1&type=cost&reset=
true&uploadType=media&key=xXxXxX: (401) Invalid Credentials' in /../pub
lic_html/proj/google-api-php-client/src/io/Google_REST.php:66 Stack tra
ce: #0 /../public_html/proj/google-api-php-client/src/io/Google_REST.ph
p(36): Google_REST::decodeHttpResponse(Object(Google_HttpRequest)) #1 /
../public_html/proj/google-api-php-client/src/service/Google_ServiceRes
ource.php(186): Google_REST::execute(Object(Google_HttpRequest)) #2 /..
/public_html/proj/google-api-php-client/src/contrib/Google_AnalyticsSer
vice.php(82): Google_ServiceResource->__call('upload', Array) #3 /../pu
blic_html/proj/dailyUpload_send.php(60): Google_ManagementDailyUploadsS
erviceResource->upload('1234567', 'UA-1234567-1', 'xXxXxXxXxXxXxXx...',
' in /../public_html/proj/google-api-php-client/src/io/Google_REST.php
on line 66
I just successfully uploaded cost data for the first time. In trading comments with Nicholas Pickering I came across the documentation for Management API Authorization which states that:
You will get a 401 status code if your access_token has expired or if you are using the wrong scope for the API.
The default for scope is read only, which is why all of my GET requests were working without difficulty, but I couldn't complete any POST requests through the API. I can't remember how I found it, but the way to accomplish this within the PHP client library is to append the following line to the client declaration:
$client->setScopes('https://www.googleapis.com/auth/analytics');
As soon as I added that line to my project, I was able to successfully upload cost data. I'm really glad to have cleared this hurdle. I still have a long way to go to complete my project, but at least I know that it's going to work.
I kept geting this error until I went to Google Console -> APIs & auth ->
APIs and turned on this API usage.

Categories