I am using codeigniter MVC framework for signing in to my site using google client library. Everything is working fine except $client->getAccessToken() when google redirects with code and I do the following code. $client->getAccessToken() return null value. Here is my code for controller function one. In this function I set my credentials to create authUrl.
public function login()
{
// Include two files from google-php-client library in controller
include_once APPPATH . 'third_party/google-api-php-client/vendor/autoload.php';
// Store values in variables from project created in Google Developer Console
$client_id = 'XXXXXX';
$client_secret = 'XXXXX';
$redirect_uri = 'path/to/mysite/login/loginGoogle';
$simple_api_key = 'XXXXXXX';
// Create Client Request to access Google API
$client = new Google_Client();
$client->setApplicationName("mysite");
$client->setClientId($client_id);
$client->setClientSecret($client_secret);
$client->setRedirectUri($redirect_uri);
$client->setDeveloperKey($simple_api_key);
$client->addScope("https://www.googleapis.com/auth/userinfo.email");
$authUrl = $client->createAuthUrl();
$data['authUrl'] = $authUrl;
$this->load->view('login',$data);
}
And after that when google authenticate and redirects to my redirect uri which is an other controller function which is given below. and problem is in this function.
public function loginGoogle()
{
// Include two files from google-php-client library in controller
include_once APPPATH . 'third_party/google-api-php-client/vendor /autoload.php';
$client_id = 'XXXXXX';
$client_secret = 'XXXXX';
$redirect_uri = 'path/to/mysite/login/loginGoogle';
$simple_api_key = 'XXXXXXX';
// Create Client Request to access Google API
$client = new Google_Client();
$client->setApplicationName("mysite");
$client->setClientId($client_id);
$client->setClientSecret($client_secret);
$client->setRedirectUri($redirect_uri);
$client->setDeveloperKey($simple_api_key);
$client->addScope("https://www.googleapis.com/auth/userinfo.email");
$objOAuthService = new Google_Service_Oauth2($client);
// Add Access Token to Session
if(!isset($_SESSION['access_token'])){
if (isset($_GET['code'])) {
$client->authenticate($_GET['code']);
$token = $client->getAccessToken();
$_SESSION['access_token'] = $token;
print_r($this -> session -> userdata());exit;
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
}
// Set Access Token to make Request
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$client->setAccessToken($_SESSION['access_token']);
}
// Get User Data from Google and store them in $data
if ($client->getAccessToken()) {
$userData = $objOAuthService->userinfo->get();
$data['userData'] = $userData;
$_SESSION['access_token'] = $client->getAccessToken();
}}
here in second function getAccessToken return nothing and google throws expection.
It looks like you never get the refresh token. There are two different tokens, the access token expires every few hours or so, but the refresh token is only sent the one time when the redirect asks the user for permission. It needs to be stored somewhere secure and is used in the future to refresh the access token.
Here's what my codeigniter code looks like to access the Google API (this would replace your if statements in the loginGoogle function:
if($refresh_token_accessed_from_my_database) {
//If session contains no valid Access token, get a new one
if ($client->isAccessTokenExpired()) {
$client->refreshToken($refresh_token_accessed_from_my_database);
}
//We have access token now, launch the service
$this->service = new Google_Service_Calendar($client);
}
else {
//User has never been authorized, so let's ask for the ok
if (isset($_GET['code'])) {
//Creates refresh and access tokens
$credentials = $client->authenticate($_GET['code']);
//Store refresh token for further use
//I store mine in the DB, I've seen others store it in a file in a secure place on the server
$refresh_token = $credentials['refresh_token'];
//refresh_token->persist_somewhere()
//Store the access token in the session so we can get it after
//the callback redirect
$_SESSION['access_token'] = $client->getAccessToken();
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
if (!isset($_SESSION['access_token'])) {
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
}
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$client->setAccessToken($_SESSION['access_token']);
$this->service = new Google_Service_Calendar($client);
}
If you are running on PLESK you might want to change the permission on /var/lib/php/session to 1777.
chmod 1777 /var/lib/php/sessions
Related
I am trying to create and save an access token that I can reference when other users in my organization (who do not have API access) log in. For instance I need to call Google Admin API to grab their orgUnit. When I get my access_token I can use this with other users but it expires after an hour and I have to re-log in with my account to get a new token.
In Short, I am not sure where or how to create the refresh token so I can save it in my datbase.
//Create Client Request to access Google API
$client = new Google_Client();
$client->setApplicationName(APPLICATION_NAME);
$client->setClientId(CLIENT_ID);
$client->setClientSecret(CLIENT_SECRET);
$client->setRedirectUri(REDIRECT_URL);
$client->setDeveloperKey(API_KEY);
$client->setAccessType('offline');
$client->addScope("https://www.googleapis.com/auth/userinfo.email");
$client->addScope("https://www.googleapis.com/auth/admin.directory.user.readonly");
//Send Client Request
if($client->isAccessTokenExpired()){
//not doing anything here at the moment
}
$objOAuthService = new Google_Service_Oauth2($client);
//Logout
if (isset($_REQUEST['logout'])) {
unset($_SESSION['access_token']);
unset($_SESSION['code']);
$client->revokeToken();
header('Location: ' . filter_var(REDIRECT_URL, FILTER_SANITIZE_URL)); //redirect user back to page
}else if (isset($_GET['code'])) {
//Authenticate code from Google OAuth Flow
//Add Access Token to Session
$client->authenticate($_GET['code']);
$_SESSION['code'] = $_GET['code'];
$_SESSION['access_token'] = $client->getAccessToken();
header('Location: ' . filter_var(REDIRECT_URL, FILTER_SANITIZE_URL));
}
//Set Access Token to make Request
if (isset($_SESSION['access_token'])) {
$client->setAccessToken($_SESSION['access_token']);
}
I was wondering if you have any thoughts on how to implement a website that can upload a file that would save on the google drive using PHP. I'm currently using this link https://github.com/google/google-api-php-client, but it gives me an error I'm not sure what did I do these are my codes:
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
$client = new Google_Client();
$client->setAuthConfig($oauth_credentials);
$client->setRedirectUri($redirect_uri);
$client->addScope("https://www.googleapis.com/auth/drive");
$service = new Google_Service_Drive($client);
$client->setClientId('sample.apps.googleusercontent.com');
$client->setClientSecret('_WwlE1Q0Nm_qkvOCLEtciRbj');
// add "?logout" to the URL to remove a token from the session
if (isset($_REQUEST['logout'])) {
unset($_SESSION['upload_token']);
}
/************************************************
* If we have a code back from the OAuth 2.0 flow,
* we need to exchange that with the
* Google_Client::fetchAccessTokenWithAuthCode()
* function. We store the resultant access token
* bundle in the session, and redirect to ourself.
************************************************/
if (isset($_GET['code'])) {
$token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
$client->setAccessToken($token);
// store in the session also
$_SESSION['upload_token'] = $token;
// redirect back to the example
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
I'm not sure what I can upload.
I tried in codeigniter.
Below I put this code in a construct
$this->google = new Google_Client();
$this->google->setClientId(GOOGLEID);
$this->google->setClientSecret(GOOGLESECRET);
$this->google->setDeveloperKey(GOOGLEAPIKEY);
$objOAuthService = new Google_Service_Oauth2($this->google);
then in a method1 I put the below
$this->google->setRedirectUri(site_url('auth/google-login?'));
$this->google->addScope("email");
$this->google->addScope("profile");
$data['content_data']['google_login_url'] = $this->google->createAuthUrl();
$this->load->view("test", $data);
then in method2 I put the below
if (isset($_GET['code'])) {
$this->google->authenticate($_GET['code']);
$token = $this->google->getRefreshToken();
echo $token;
}
You can see that I tried to print the $token but it's empty.
My Question is WHY is it empty?
EDIT:
echo $this->google->getAccessToken();
Even the getAccessToken returns empty.
I just fixed it.
My Solution is that in the construct I have
$this->google = new Google_Client();
$this->google->setClientId(GOOGLEID);
$this->google->setClientSecret(GOOGLESECRET);
$this->google->setDeveloperKey(GOOGLEAPIKEY);
$this->google->setRedirectUri(site_url('auth/google-login?'));
$this->google->addScope("email");
$this->google->addScope("profile");
in method1 I only have this
$data['content_data']['google_login_url'] = $this->google->createAuthUrl();
$this->load->view("test", $data);
and in method2 I have this
if (isset($_GET['code'])) {
$this->google->authenticate($_GET['code']);
$token = $this->google->getAccessToken();
var_dump($token);
}
and here the $token already now has value
Here is the working code which I'm using in Laravel and Codeigniter.
// Initial config
$client = new Google_Client();
$client->setApplicationName(APP_NAME);
$client->setClientId(CLIENT_ID);
$client->setClientSecret(CLIENT_SECRET);
$client->setRedirectUri(REDIRECT_URI);
$client->setScopes(array(SCOPE_A));
// To retrieve refresh token forcefully
// This will ask for permission everytime.
$client->setApprovalPrompt('force');
$client->setAccessType('offline');
// Return url data part
if (isset($_GET['code'])) {
// Log the user in
$client->authenticate($_GET['code']);
// Get acess token and refresh token
$getAccesToken = $client->getAccessToken();
$getRefreshToken = $client->getRefreshToken();
}
else
{
// Return to login
$googleAuthUrl = $client->createAuthUrl();
// Redirect user to authentication URI
}
I hope this helps.
i am in the situation that i have to use the zend framework along with oauth 2 for gmail.
all works fine and i get the messages and login just fine, my problem is that the token expire too fast.
am i able to set it so it will never expire or how should i implement a refresh token to the framework ? i use standard code when it comes to login.
what i basically need is an access-token that does not expire or a guide for how to implement a refresh token and how to use it in a program.
any help is appreciated.
thank you.
this is the login page.
include("../classes/Google/Client.php");
$client_id = "hidden";
$client_secret = "hidden";
$redirect_uri = "hidden";
$client = new Google_Client();
$client->setClientId($client_id);
$client->setClientSecret($client_secret);
$client->setRedirectUri($redirect_uri);
$client->addScope("https://www.googleapis.com/auth/userinfo.email");
$client->addScope("https://www.googleapis.com/auth/userinfo.profile");
$client->addScope("https://mail.google.com/");
$client->setRedirectUri($redirect_uri);
$authUrl = $client->createAuthUrl();
echo "Login";
this is the callback
$client_id = "hidden";
$client_secret = "hidden";
$redirect_uri = "hidden";
$client = new Google_Client();
$client->setClientId($client_id);
$client->setClientSecret($client_secret);
$client->setRedirectUri($redirect_uri);
session_start();
if (isset($_GET['code'])) {
$client->authenticate($_GET['code']);
$_SESSION['access_token'] = $client->getAccessToken();
$oauth2 = new Google_Service_Oauth2($client);
$user = $oauth2->userinfo->get();
$_SESSION['email'] = $user;
$redirect = 'hidden';
header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
}
i know the code is not great, but i wonder if i should get a refresh token along with the access token ?
if someone are interested i have done like this to fix it... now it works like it should.
this method is called every time i need to do something with the mails (if the access token is not valid then you will not have access, so this is to make sure access is always there.)
public function checktokenexpiry()
{
global $google_client; // this is global as we use it in our webservice.
session_start();
$time_created = json_decode($_SESSION['access_token']);
$t=time();
$timediff=$t-$time_created->created;
if($timediff>3500) // 3500 as i want to have a little time to connect if it is just about to need refreshing.
{
$user = json_decode($_COOKIE['user']);
$usermail = $user->email;
$refreshtoken = $this->model->getRefreshToken($usermail);
$refreshtoken = $refreshtoken[0]['google_refresh_token'];
$google_client->refreshToken($refreshtoken);
$_SESSION['access_token'] = $google_client->getAccessToken();
}
}
I am using the google Calendar API. This is what I want, once you give the app the permission, I can always use the app, without the need of giving access everyday. I keep hearing that I need to save the access token or use the refresh token to do what I want to do.. Here is the thing, how do you do it? How does the code look like? I've tried saving the token in a cookie, but after an hour, the access token has expired. How do I keep the user logged in?
PS: Please give me code examples with explanations.
Here is my code (using CakePHP):
$client = new Google_Client();
$client->setApplicationName("Wanda3.0 Agenda");
$cal = new Google_CalendarService($client);
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()) {
/************* Code entry *************/
}else{
/************* Not connected to google calendar code *************/
$authUrl = $client->createAuthUrl();
$returnArr = array('status' => 'false', 'message' => "<a class='login' href='$authUrl'>Connect Me!</a>");
return $returnArr;
}
Ok, after waiting for a few days, the suggestion from Terry Seidler(comments below) made it all happen! Here is my piece of code on how to automaticly refresh the access token without autenticating each time using cookies.
(NOTICE: It's safer to save the refresh token in your database)
This is the magic (using cookies):
$client = new Google_Client();
$client->setApplicationName("Wanda3.0 Agenda");
$cal = new Google_CalendarService($client);
$client->setAccessType('offline');
if (isset($_GET['code'])) {
$client->authenticate($_GET['code']);
$_SESSION['token'] = $client->getAccessToken();
header('Location: http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF']);
}
//Where the magic happends
if (isset($_SESSION['token'])) {
//Set the new access token after authentication
$client->setAccessToken($_SESSION['token']);
//json decode the session token and save it in a variable as object
$sessionToken = json_decode($_SESSION['token']);
//Save the refresh token (object->refresh_token) into a cookie called 'token' and make last for 1 month
$this->Cookie->write('token', $sessionToken->refresh_token, false, '1 month');
}
//Each time you need the access token, check if there is something saved in the cookie.
//If $cookie is empty, you are requested to get a new acces and refresh token by authenticating.
//If $cookie is not empty, you will tell the client to refresh the token for further use,
// hence get a new acces token with the help of the refresh token without authenticating..
$cookie = $this->Cookie->read('token');
if(!empty($cookie)){
$client->refreshToken($this->Cookie->read('token'));
}
And thats it! IF you have any questions, feel free to leave a comment below and I will answer the best I can. Goodluck and Cheers!
Instead of using cookies and sessions you should save it in the database and use it.
A similar implementation for drupal site is at Google OAuth2 sandbox at http://drupal.org/sandbox/sadashiv/1857254 This module allows you to handle the authentication from admin interface of drupal. You can then use the fetched access token from google and then use the api function of google_oauth2_account_load or google_oauth2_client_get to get the Google_Client and carry your api call.
Much the same as hope industries but after testing I only wanted to refresh the token when I had to. Full source just change the keys etc at the top:
require_once 'google-api-php-client/src/Google_Client.php';
require_once 'google-api-php-client/src/contrib/Google_CalendarService.php';
session_start();
$client = new Google_Client();
$client->setApplicationName("Google Calendar PHP Starter Application");
// Visit https://code.google.com/apis/console?api=calendar to generate your
// client id, client secret, and to register your redirect uri.
$client->setClientId('your_id');
$client->setClientSecret('your_secret');
$client->setRedirectUri("http://localhost/your_redirect.php");
$client->setDeveloperKey('your_key');
$cal = new Google_CalendarService($client);
if (isset($_GET['code'])) {
$client->authenticate($_GET['code']);
$_SESSION['token'] = $client->getAccessToken();
header('Location: http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . $query_string);
}
if (isset($_SESSION['token'])) {
$client->setAccessToken($_SESSION['token']);//update token
//json decode the session token and save it in a variable as object
$sessionToken = json_decode($_SESSION['token']);
//Save the refresh token (object->refresh_token) into a cookie called 'token' and make last for 1 month
if (isset($sessionToken->refresh_token)) { //refresh token is only set after a proper authorisation
$number_of_days = 30 ;
$date_of_expiry = time() + 60 * 60 * 24 * $number_of_days ;
setcookie('token', $sessionToken->refresh_token, $date_of_expiry);
}
}
else if (isset($_COOKIE["token"])) {//if we don't have a session we will grab it from the cookie
$client->refreshToken($_COOKIE["token"]);//update 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'>Select a calendar!</a>";
}