I'm using codeigniter 3.x and php 5.5+. I've been trying to get this to work with no luck. I want to call methods inside a youtube controller class I created that will do different things based on communicating with the google or youtube. The problem is with the Google_Client I believe or it's with how to store $client variable maybe so you can use it in second function. When I try calling this from another function it gives a not login required error even thought the user already did the google verification. How can I tell my second function that the user has already done the authorization and got the token. Everything seems to work very well when both functions are in the same function(I mean just using one function). Also I don't want to verify user on every function or method I execute.
So after first function is done, I get redirected with an access token in the url to the second function but then I get an error Message: Error calling GET https://www.googleapis.com/youtube/analytics/v1/reports?ids=channel%3D%3DMINE&start-date=2014-01-01&end-date=2016-01-20&metrics=views&filters=video%3D%3DpC900o6JaMc: (401) Login Required
First function in the controller Youtubeverify:
class Youtubeverify extends CI_Controller{
public function youtube_consent(){
$this->load->library('google');
$OAUTH2_CLIENT_ID = 'MY_ID';
$OAUTH2_CLIENT_SECRET = 'MY_KEY';
$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->setScopes(array('https://www.googleapis.com/auth/yt-analytics-monetary.readonly','https://www.googleapis.com/auth/youtube.readonly'));
$redirect = filter_var('http://' . $_SERVER['HTTP_HOST'] . "/ci/youtubeverify/display_report",
FILTER_SANITIZE_URL);
$client->setRedirectUri($redirect);
$youtubeReporting = new Google_Service_YouTubeReporting($client);
if (isset($_REQUEST['logout'])) {
$this->session->unset_userdata('youtube_token');
}
if (isset($_GET['code'])) {
if (strval($_SESSION['state']) !== strval($_GET['state'])) {
die('The session state did not match.');
}
$client->authenticate($_GET['code']);
$youtube_token = $client->getAccessToken();
//trying to store the access token in a session
$newdata = array('youtube_token'=>$youtube_token);
$this->session->set_userdata($newdata);
header('Location: ' . $redirect);
}
if ($this->session->userdata('youtube_token')) {
$client->setAccessToken($this->session->userdata('youtube_token'));
}
if ($client->getAccessToken()) {
$client->getAccessToken();
}
else {
// If the user hasn't authorized the app, initiate the OAuth flow
$state = mt_rand();
$client->setState($state);
$_SESSION['state'] = $state;
$authUrl = $client->createAuthUrl();
redirect($authUrl);
}
}
Second function in the controller Youtubeverify:
public function display_report(){
$this->load->library('google');
$client = new Google_Client();
$client->getAccessToken();
$youtubeAnalytics = new Google_Service_YouTubeAnalytics($client);
$id = 'channel==MINE';
$start_date = '2014-01-01';
$end_date = '2016-01-20';
$optparams = array('filters' => 'video==*********');
$metrics = array('views');
$api_response = $metrics;
$api = $youtubeAnalytics->reports->query($id, $start_date, $end_date, $metric,$optparams);
$data['api_response'] = $api_response['views'];
$this->load->view('layouts/mainlay',$data);
}
I have never worked with YouTube API before, but here's a step in the right direction.
class Youtubeverify extends CI_Controller {
// Google API Keys
const CLIENT_ID = '';
const CLIENT_SECRET = '';
// We'll store the client in a class property so we can access it between methods.
protected $Client;
public function __construct () {
parent::__construct();
// setup google client.
$this->Client = new Google_Client();
$this->Client->setClientId(self::CLIENT_ID);
$this->Client->setClientSecret(self::CLIENT_SECRET);
// we call the authenication method for each request
$this->_authenticate_client();
}
// Authentication method
protected function _authenticate_client () {
//if we already have a token then we just set it in the client
//without going through authentication process again
if( $accessToken = $this->session->userdata('youtube_token') ) {
$this->Client->setAccessToken($accessToken);
}else{
// preform authentication as usual with a redirect ...etc
}
}
}
Related
I am creating google client instance and authenticating it once and fetching required data. Afterwards if I want to use that same instance of Google client for some other service , how can I achieve it ?
webmasterMain route is my redirect uri registered in google webmaster .
public function webmasterMain(Request $request)
{
$requestData = $request->all();
if ($request->isMethod('POST') || isset($requestData['code'])) {
$google_redirect_url = env('APP_URL') . '/user/webmasterMain';
$gClient = new \Google_Client();
$gClient->setAccessType("offline");// to get refresh token after expiration of access token
$gClient->setIncludeGrantedScopes(true); // incremental auth
$gClient->setApplicationName(config('services.google.app_name'));
$gClient->setClientId(config('services.google.client_id'));
$gClient->setClientSecret(config('services.google.client_secret'));
$gClient->setRedirectUri($google_redirect_url);
$gClient->setDeveloperKey(config('services.google.api_key'));
$gClient->setScopes(array(
'https://www.googleapis.com/auth/plus.me',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/webmasters.readonly',
'https://www.googleapis.com/auth/webmasters',
));
$google_oauthV2 = new \Google_Service_Oauth2($gClient);
if ($request->get('code')) {
$gClient->authenticate($request->get('code'));
$request->session()->put('token', $gClient->getAccessToken());
}
if ($request->session()->get('token')) {
$gClient->setAccessToken($request->session()->get('token'));
}
if ($gClient->getAccessToken()) {
$inst = new Google_Service_Webmasters($gClient);
$res = $inst->sites->listSites();
$sites = $res->getSiteEntry();
$siteUrl = [];
foreach ($sites as $key => $site) {
$siteUrl = array_add($siteUrl, $key, ['site_name'=>$site['siteUrl'], 'site_permission_level' => $site['permissionLevel']]);
}
$sites = (((array)$siteUrl));
return view('User::webmasterMain')->with(['data' => $sites]);
} else {
//For Guest user, get google login url
$authUrl = $gClient->createAuthUrl();
return redirect()->to($authUrl);
}
}
return view('User::webmasterMain');
}
Now suppose I want to get the authenticated $gClient for service like Google_Service_Webmasters_SearchAnalyticsQueryRequest , then how can I make $client = $gClient for this next request ?
public function query(Request $request){
//suppose $client is the same instance which was previously authenticated and stored in $gClient
$website = "http://example.com/";
$searchAnalytics = new \Google_Service_Webmasters_SearchAnalyticsQueryRequest();
$searchAnalytics->setStartDate('2017-03-01');
$searchAnalytics->setEndDate('2017-03-31');
$searchAnalytics->setDimensions(['page']);
$searchAnalytics->setSearchType('web');
`$results = $client->searchanalytics->query($website, $searchAnalytics);`
return $results->getRows();
I got the answer , no need to save the instance or do anything but, follow this :
Create a Google Client Object.
At first time authenticating save the accessToken from google client object by getAccessToken().
Use the same access token and set Access token in this google client.
now you can use this google client object for any service.
First time authenticating:
$gClient = new \Google_Client();
//after authenticating
$request->session()->put('token', $gClient->getAccessToken());
Now we can use this access token in any google service call:
$gClient = new \Google_Client();
if ($request->session()->get('token')) {
$gClient->setAccessToken($request->session()->get('token'));
}
$client = new Google_Service_Webmasters($gClient);
I'm using Google Calendar API to display events on fullcalendar(so using a json object in my view). I'm using codeignitor php framework, and I have a few functions in my controller to create a new client then I use that in the oauth2callback() function to exchange my code for an access_token then I start calling the service in gcalendar() and gcalendar_events. I have set the accessType to offline but that doesn't seem to make me access the events offline. It works great except that I'm redirected to log in again every time the session ends. I don't want that, I want them to display all the time after the session ends. I am trying to use a refresh token in case the access_token expires to see if that would fix the problem.
this is the code in my controller
function getClient() {
$client = new Google_Client();
$client->setApplicationName("DL Calendar");
$client->setAuthConfig('application/client_secrets.json');
$client->addScope('profile');
$client->setIncludeGrantedScopes(true);
$client->setAccessType('offline');
return $client;
}
function gcalendar() {
$this->load->add_package_path(APPPATH . 'vendor/autoload');
$client = $this->getClient();
//$client->setRedirectUri(site_url('calendar/index'));
$client->addScope(Google_Service_Calendar::CALENDAR);
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$client->setAccessToken($_SESSION['access_token']);
$access_token = $_SESSION['access_token'];
$service = new ]Google_Service_Calendar($client);
$calendar = new Google_Service_Calendar_Calendar();
//$calendarList = $service->calendarList->listCalendarList();
$calendar = $service->calendars->get('primary');
$params = array(
'owner_id' => get_current_user_id(),
'title' => get_current_user(). ' ' .'Google Calendar',
'type' => 'gcal',
'url' => $calendar->id,
);
$calendar_id = $this->Calendar_model->add_calendar($params);
redirect('calendar/index');
} else {
$redirect_uri = site_url('calendar/oauth2callback');
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
$this->session->set_flashdata('success', 'Event Successfully Added');
}
function oauth2callback() {
//Build the client object
$client = $this->getClient();
$client->addScope(Google_Service_Calendar::CALENDAR);
$service = new Google_Service_Calendar($client);
$url = parse_url($_SERVER['REQUEST_URI']); parse_str($url['query'], $params);
$code = $params['code'];
//To exchange an authorization code for an access token, use the authenticate method:
if (! isset($code)) {
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
$token = $client->fetchAccessTokenWithAuthCode($code);
$client->setAccessToken($token);
$client->authenticate($code);
$_SESSION['access_token'] = $client->getAccessToken();
$redirect_uri = site_url('calendar/gcalendar');
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
}
function gcalendar_events() {
$client = $this->getClient();
$client->addScope(Google_Service_Calendar::CALENDAR);
// $client->setRedirectUri(site_url('calendar/gcalendar'));
$client->setAccessType('offline'); //need calendar events to appear even if not logged in to google
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$client->setAccessToken($_SESSION['access_token']);
$access_token = $_SESSION['access_token'];
$service = new Google_Service_Calendar($client);
$id = 'primary';
$calendar = new Google_Service_Calendar_Calendar();
$calendar = $service->calendars->get('primary');
$event = new Google_Service_Calendar_Event();
$events = $service->events->listEvents($id);
foreach ($events->getItems() as $event) {
$startTime = strtotime($event->getStart()->dateTime) ;
$endTime = strtotime($event->getEnd()->dateTime);
$start = date('Y-m-d H:i:s', $startTime);
$end = date('Y-m-d H:i:s', $endTime);
$eventsArr[] = array(
'title' => $event->getSummary(),
'start'=> $start,
'end' => $end,
);
}
// Return a single `events` with all the `$eventsArr`
echo json_encode($eventsArr);
}
}
Is the problem in my session ending? or does the access token expire and I need a refresh token? where do I set the refresh token cause I tried putting it in more that one place and I get an error message that refresh token has to be set as part off setAccessToken. I put it all over and still got error messages.
Here is the code I used
if ($client->isAccessTokenExpired()) {
$refresh_token = $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$client->setAccessToken($refresh_token);
$_SESSION['access_token'] = $refresh_token;
$this->load->helper('file');
write_file('application/client_secrets.json', json_encode($client->getAccessToken()));
} else {
$access_token = $_SESSION['access_token'];
}
I just noticed that it once used to say 'grant offline access' in my authorization but now it no longer mentions that while google documentation says
After a user grants offline access to the requested scopes, you can
continue to use the API client to access Google APIs on the user's
behalf when the user is offline. The client object will refresh the
access token as needed.
I think this Offline access in OAuth guide might help you. Since you're using PHP, try setting the access type to "offline".
If your application needs offline access to a Google API, set the API client's access type to offline:
$client->setAccessType("offline");
After a user grants offline access to the requested scopes, you can continue to use the API client to access Google APIs on the user's behalf when the user is offline. The client object will refresh the access token as needed.
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
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.
Hi I would like to learn something from here, basically I want the access of my system to be in google account somehow I manage to do the following
get client id, redirect uris, secret keys
authentication from google account
get token
but I i felt I was doing wrong all in some part, this is the Oauth2callback
class Oauth2callback extends CI_Controller {
function __construct(){
parent::__construct();
$this->load->helper('url');
$this->load->library('session');
require_once APPPATH.'libraries/Google/Client.php';
session_start();
}
public function index()
{
$client_id = $this->config->item('client_id');
$client_secret = $this->config->item('client_secret');
$redirect_uri = $this->config->item('redirect_uri');
$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");
if (isset($_GET['code'])) {
$client->authenticate($_GET['code']);
$_SESSION['access_token'] = $client->getAccessToken();
$redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
}
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$client->setAccessToken($_SESSION['access_token']);
} else {
$authUrl = $client->createAuthUrl();
}
if ($client->getAccessToken()) {
$_SESSION['access_token'] = $client->getAccessToken();
}
if(isset($authUrl)) {
header('location:'. base_url());
}else{
header('location:'. base_url().'dashboard');
}
}
but this is my index controller the Login it only has button sign in with Google
class Login extends CI_Controller {
function __construct(){
parent::__construct();
$this->load->helper('url');
$this->load->library('session');
require_once APPPATH.'libraries/Google/Client.php';
session_start();
}
public function index()
{
//$this->checkSession();
$client_id = $this->config->item('client_id');
$client_secret = $this->config->item('client_secret');
$redirect_uri = $this->config->item('redirect_uri');
$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");
$authUrl = $this->data['authUrl'] = $client->createAuthUrl();
$this->load->view('login/index.php',$this->data);
$this->load->view('template/pre_footer');
$this->load->view('template/footer');
}
}
what would be the right process of this using MVC PHP I need to do the ff. :
A. click button sign in to google
B. get token and save it to session
C. used the token to my entire system (in every controller)
what I have right now is A & B but the C i totally don't know what to do.
could anyone help me with this. any suggestion comment is well appreciated. thanks in advance.
The code you have might be a bit confusing because it handles authorization url, redirect to Google, callback to your site, and save the access token at the same time.
When it comes to use the access token to perform authenticated call to the api, it's much simpler. If you have a valid access token stored in you session, you can really use it anywhere to initialize the Google Application, this way:
// client
$client = new Google_Client();
$client->setApplicationName('Google Application');
$client->setClientId($clientId);
$client->setClientSecret($clientSecret);
$client->setRedirectUri($redirectUri);
// token
$client->setAccessToken($token);
Now if you want this to be available across several controllers, the most appropriate way in CodeIgniter would be to create a new library wrapping the code above.
The advantage of using a library is that they can be auto-loaded in CodeIgniter config, and are easily accessible anywhere in your code.
Example library:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Someclass {
private $client;
public function __construct()
{
...
// client
$client = new Google_Client();
$this->client->setApplicationName('Google Application');
$this->client->setClientId($clientId);
$this->client->setClientSecret($clientSecret);
$this->client->setRedirectUri($redirectUri);
// token
$this->client->setAccessToken($token);
}
}
?>
Then you just have to do this to use it in your controller:
$this->load->library('someclass');
You could also create shortcuts to specific APIs. For example, if you wanted a quick access to Google Analytics API, you could do this:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Someclass {
private $client;
public function __construct()
{
...
// client
$client = new Google_Client();
$this->client->setApplicationName('Google Application');
$this->client->setClientId($clientId);
$this->client->setClientSecret($clientSecret);
$this->client->setRedirectUri($redirectUri);
// token
$this->client->setAccessToken($token);
}
public function analytics()
{
return new Google_Service_Analytics($this->client);
}
}
?>
And then use it this way in your controller:
$this->load->library('someclass');
$this->someclass->analytics();
Learn more about CodeIgniter libraries:
http://ellislab.com/codeigniter/user-guide/general/creating_libraries.html