Google_Auth_Exception: Error refreshing the OAuth2 token - php

I am trying to fetch user's data from google plus using PHP.
I'm using below tutorial
https://www.youtube.com/watch?v=-65R420rIUA
Situation:
User login into my app android using google plus button i fetch the access token using googleSignInResult.googleSignInAccount.getIdToken()
I send this token to my server which runs php to fetch users data using google php client (as described in the video)
below is my code
try{
$gClient = new Google_Client();
$gClient->setApplicationName('pixyfi');
$gClient->setClientId($config['google']['appid']);
$gClient->setClientSecret($config['google']['secret']);
$token = json_encode(array("access_token"=>$lptoken,"refresh_token"=>$lptoken,"token_type"=>"Bearer","expires_in"=>3600,"id_token"=>$lptoken,"created"=>1320790426));
$gClient->setAccessToken($token);
$gClient->addScope(Google_Service_Plus::PLUS_ME);
$plus = new Google_Service_Plus($gClient);
$gpUserProfile = $plus->people->get('me');
echo "User Fetched as:".$gpUserProfile['id'];
}
catch(Google_Auth_Exception $x){
echo "Error:".$x;
}
But i am getting error:
Error:Google_Auth_Exception: Error refreshing the OAuth2 token, message: '{
"error" : "invalid_client"
}' in /var/www/html/api/auth/vendor/google/apiclient/src/Google/Auth/OAuth2.php:364
Could you please let me know what mistake i am making here?

this is some of my code which handles token thing. Implement this logic and let me know if you are still getting errors.
$row is is fetched from database and contains token information
$client->setAccessToken($row['token']);
if(time()>$row['created']+$row['expires_in'])
{
$client->refreshToken($row['refresh_token']);
$token=$client->getAccessToken();
DB::Query("-----UPDATE DB TOKEN INFO-------");
$client->setAccessToken($token);
}

Related

Storing the Google OAuth Authorization Token in Database

I am building a portal where multiple users can log in to their multiple Gmail accounts. I have successfully retrieved the token value, However, I want to store that in my database but I am unable to store it.
Below is the code I am using:
function mInititalize(){
$client = new Google_Client();
$client->addScope('https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email https://mail.google.com/');
$client->setClientId(Config('gmail.client_id'));
$client->setClientSecret(Config('gmail.client_secret'));
$client->setRedirectUri('http://localhost:81'.Config('gmail.redirect_url'));
$loginURL = $client->createAuthUrl();
return redirect($loginURL);
}
After Redirection or user login
function mGetToken(){
$token = $client->fetchAccessTokenWithAuthCode( 'code'); // here i get the 'code' from login URL
I pass this code to get token I successfully get token
$oAuth = new Google_Service_Oauth2( $client);
$userData = $oAuth->userinfo_v2_me->get(); // get current user detail
}
I want to store $token value in database, but I am getting error message
>Serialization of 'Closure' is not allowed
Please anyone help me to solve this issue. Thanks.
I would suggest storing OAuth credential information for the Google API, not in your database, but through the API itself. If you're intending to use it any authentication manner, you'll run into problems, as the docs state:
Access tokens periodically expire and become invalid credentials for a related API request. Google Identity Platform: Using OAuth 2.0 for Web Server Applications
But, the same docs also show a way that you can set or retrieve the token natively within the API. Since it's data relating to google's auth'ing process, and since it might go stale if you store it, it seems best to just let them handle it and work with the API. The same source:
If you need to apply an access token to a new Google_Client object—for example, if you stored the access token in a user session—use the setAccessToken method:
$client->setAccessToken($access_token);
$client->getAccessToken();

"unauthorized_client" error when using PHP client to refreshToken with Google API client?

I am requesting access to the user's data from an IOS app using this code from the GoogleSignIn pod
[GIDSignIn sharedInstance].uiDelegate = self;
[[GIDSignIn sharedInstance] setScopes:#[ ... ];
[[GIDSignIn sharedInstance] signInSilently];
I then receive the accessToken and the refreshToken in the appDelegate and I send that to the server running PHP and using this google client library (https://github.com/googleapis/google-api-php-client) ... for the first hour everything is working fine and the access token is valid and allowing me access to all the scopes. Then after an hour the access token expires and I try to refresh it using this code
$client = new Google_Client();
$client->setApplicationName(<app name>);
$client->setDeveloperKey(<google_oauth_developer_key>);
$client->setClientSecret(<google_oauth_client_secret>);
$client->setClientId(<google_oauth_client_id>);
$client->refreshToken("1/12ju3ZZim-r6co195lIVNNvzBq9x5G64GJCWkYsOQ18");
and the "refreshToken" function above returns this error
=> [
"error" => "unauthorized_client",
"error_description" => "Unauthorized",
]
It's worth noting that the app name, google_oauth_developer_key, google_oauth_client_secret, and google_oauth_client_id have not changed. They are the same ones that were working earlier to retrieve the user's contacts, calendar events, etc when the access token was not yet expired.
What could be causing this error?
You need to actually use your refresh token at some point.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$client->getAccessToken();
Code ripped from my Oauth2Authentication.php sample
Note
Also remember that refresh tokens are user / client based. So if the token was generated by one client then a different client will probably not be able to use it. I will be very surprised if you can use a refresh token created in Ios code in a php application. The client types are different.
Ok so I figured out what I did wrong. I originally followed these instructions https://developers.google.com/identity/sign-in/ios/sign-in which assume you need online access only, but I actually need offline access to the scopes so I followed these instructions https://developers.google.com/identity/sign-in/ios/offline-access and it works now. So instead of having the IOS app send up the access token and the refresh token separately like this
- (void)signIn:(GIDSignIn *)signIn didSignInForUser:(GIDGoogleUser *)user
withError:(NSError *)error {
if (!error) {
NSString *accessToken = user.authentication.accessToken;
NSString *refreshToken = user.authentication.refreshToken;
I simply have it send up the serverAuthCode like this
- (void)signIn:(GIDSignIn *)signIn didSignInForUser:(GIDGoogleUser *)user
withError:(NSError *)error {
if (!error) {
NSString *serverAuthCode = user.serverAuthCode;
and then on the server I run this code to get the access token
$access_token = $client->authenticate($google_server_auth_code);
$client->setAccessToken($access_token);
and then when the access token expires I run this to refresh it
$access_token = $client->refreshToken($client->getRefreshToken());
$client->setAccessToken($access_token);

Google PHP SDK - not getting refresh token

I am trying to get a refresh token for the Google API's, using the PHP SDK. I am authenticating the user with Javascript, retrieving a code, and exchanging it for an access_token server side, but this doesn't grant me an access token. What am I doing wrong? Here is the code I use:
$client = new Google_Client();
$client->setClientId($client_id);
$client->setClientSecret($client_secret);
$client->addScope('https://www.googleapis.com/auth/plus.me');
$client->addScope('https://www.google.com/m8/feeds');
$client->setRedirectUri('postmessage');
$client->setAccessType('offline');
if (isset($_REQUEST['code'])) {
$client->authenticate($_REQUEST['code']);
if ($client->getAccessToken()) {
$_SESSION['access_token'] = $client->getAccessToken();
$token_data = $client->verifyIdToken()->getAttributes();
$result['data']=$token_data;
$result['access_token']=json_decode($_SESSION['access_token']);
}
}
debug($result); //my own function, var_dumps the content of an array
Here is the result of the array:
$result['access_token'] contains:
access_token: TOKEN
created: 1434380576
expires_in: 3594
id_token: IDTOKEN
token_type:"Bearer"
If I am not mistaken the first access token should also contain the refresh token, what am I doing wrong?
First check the settings in the developer console of Google to see if your RedirectUri is the same and that the API is activated (although if you already got that .json, then I assume it is.
You have to go through the Google Auth Prompt Screen at least 1 time to get a refresh token in your .json, and if your RedirectUri is taking you nowhere, you won't be able to get your refresh token or even the access validated.
You can also try a service account if you're doing small file transactions and don't need a user validation for the process of your script. Good Luck.
The problem was that I had to specify that I want offline access in the authentication process, the client side... The Google API's are horribly documented!!!

Google Analytics API blank screen when querying accounts?

I am novice to Google Analytics Api. I just started working on a small project where I want to pull data from the API and display it on each user’s Dashboard, using one single Google Analytics Account. I tried to follow the tutorial provided by google and made adjustments where required due to update to the library.
I am working on a codeigniter based platform and I was able to create a Google Client Object and also to make use of a refresh token which is saved in the database. I use the refresh token in order to have the data available on the dashboard without having to manually login every time.
The access token is there every time when I am logged in, and I can use it to set the client access token and create a Google Service Analytics object ($service = new Google_Service_Analytics($client);). I am printing the service and I can see the client id, client secret, etc and the access token being passed to it; but other like Google_Service_Analytics_DataGa_Resource Object are empty ( I do not know if they should be like that or not at this particular step ?).
When I am trying to request the user accounts
$accounts = $analytics->management_accounts->listManagementAccounts();,
I get a blank screen and my view is not being rendered.
I could not find such a problem being encountered before, so I am a bit confused why is happening. I do not get any error messages or anything that might point me to the cause of it or the right direction.
Note: I did managed to make it work using the same credentials trough JavaScript, but in this case it is not what I am looking for. I was able to retrieve data, display data in charts,etc using JS. I am new to making posts, so if anything is required from my part in order for you to have a better idea of what is going on, please do let me know.
I would greatly appreciate it I could get any indication to why that might be happening, or anything that would put me on the right path.
Codeigniter controller Class as follows
// Step 1 - Load PHP Client Libraries
require_once APPPATH.'libraries/Google/Client.php';
require_once APPPATH.'libraries/Google/Analytics.php';
class GoogleTest extends CI_Controller {
public function index(){
$this->load->helper(array('url','form'));
$this->load->model('googleapi_model'); //used to get the refresh token
// Step 2 - Start a session to persist credentials
session_start();
// Step 3 - Create and configure a new client object
$client = new Google_Client();
$client->setApplicationName("API Project");
// Insert client id, api key, client secret, project scope and redirect uri
$client->setDeveloperKey("***************");
$client->setClientId('********************');
$client->setClientSecret('******************');
$client->setRedirectUri('****************');
$client->setScopes(array('https://www.googleapis.com/auth/analytics.readonly'));
// Check if refresh token exists, it is used to login users automatically & it is being generated only once when you login the first time from the created
// google analytics app, this will take precedence to Step 4 or 6 below ;
if(count($this->googleapi_model->getGoogleRefreshToken()) > 0){
$db_refresh_token = $this->googleapi_model->getGoogleRefreshToken();
$client->refreshToken($db_refresh_token[0]->refreshtoken);
$_SESSION['token'] = $client->getAccessToken();
}else{
if ($client->getAccessToken()) {
$token = $client->getAccessToken();
$authObj = json_decode($token);
$refreshToken = $authObj->refresh_token;
if(isset($refreshToken) && $refreshToken != null){
$this->googleapi_model->insertGoogleRefreshToken($refreshToken);
}
}
}
//Step 4 - Handle authorization flow from the server
if (isset($_GET['code'])) {
$client->authenticate($_GET['code']);
$_SESSION['token'] = $client->getAccessToken();
$redirect = 'http://' . $_SERVER['HTTP_HOST']. $_SERVER['PHP_SELF'];
header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
}
// Step 5 - Retrieve and use stored credentials
if (isset($_SESSION['token'])) {
$client->setAccessToken($_SESSION['token']);
}
// Stept 6 - Either prompt the user to login or run the demo
if(!$client->getAccessToken()){
$authUrl = $client->createAuthUrl();
$this->data['auth'] = $authUrl;
}else{ //Create analytics service object
echo 'authenticated';
$analytics = new Google_Service_Analytics($client);
//TILL HERE MY CODE WORKS FINE, NO ERRORS, VIEW BEING RENDERED
$accounts = $analytics ->management_accountSummaries->listManagementAccountSummaries();
// $accounts = $analytics->management_accounts->listManagementAccounts();
echo '<pre>';
print_r($analytics);
echo '</pre>';
}
$this->data['content'] = '/public/dashboard/google_test';
$this->load->view('template/template', $this->data);
}
Make sure you're logged into the google account that API app is in.
And that you have clicked 'connect'.
Then run the script.
Also turn on error reporting (including notices)

Fetch Google Calendar Events on PHP server after authenticating on iOS app

Okay so here's what I want to do...
user authorized the app on iPhone with read/write access to Google calendar
I get an auth token of some kind from Google
Pass on the token to my PHP server and save it in database
Use the token to regularly check on Google events and store them in server's database
Send the Google events data as json to the app
I want to implement the fetching of Google events on server, so that I can build additional functionality around them like sending remote push notifications.
I am stuck at the part of getting auth token and saving it on server and using it to fetch events from Google's calendar api, having not able to find the resources for same. Can somebody throw some light on this.
UPDATE
I have been able to successfully implement the scenario till step 3.
I get the auth token and refresh token from Google and save it in database. Now using the Google API php client, I am trying to connect to Google's calendar API using the access token that I got earlier. I am using the following code...
require_once(APPPATH . "libraries/Google/Google_Client.php");
require_once(APPPATH . "libraries/Google/contrib/Google_CalendarService.php");
$client = new Google_Client();
$client->setAccessToken($google_access_token);
$calendar = new Google_CalendarService($client);
$calendarList = $calendar->calendarList->listCalendarList();
echo print_r($calendarList, true);
But now I get this error...
PHP Fatal error: Uncaught exception 'Google_AuthException' with
message 'Could not json decode the token' in
/myserver/application/libraries/Google/auth/Google_OAuth2.php:162
Stack trace:
/myserver/application/libraries/Google/Google_Client.php(170): Google_OAuth2->setAccessToken('a_token...')
I understand that I am directly trying to set the access token in Google client api without specifying any redirect url or other params normally used when the user authorizes the access to Google calendars on server itself. Is this supposed to work like I am trying to?
UPDATE 2
Upon some further digging, I found out that directly setting the access token using setAccessToken does not work as Google client for API expects a JSON encoded string in the setAccessToken method. After some tweaks I changed my code to following....
require_once(APPPATH . "libraries/Google/Google_Client.php");
require_once(APPPATH . "libraries/Google/contrib/Google_CalendarService.php");
$client = new Google_Client();
$client->setAccessType('offline');
$client->refreshToken($google_refresh_token);
$newToken = $client->getAccessToken();
$client->setAccessToken($newToken);
$calendar = new Google_CalendarService($client);
$calendarList = $calendar->calendarList->listCalendarList();
echo print_r($calendarList, true);
Now the error that I am getting is that of an invalid_request.
Error refreshing the OAuth2 token, message: '{"error" : "invalid_request"}'
Finally I am able to answer my own question. Hope this helps someone else.
Step 1 & 2. I got the Google OAuth protocol working in my iOS App following the instructions in this excellent tutorial on mobiletuts.
Step 3. I saved the access token and refresh token in database on my web server.
Step 4. Using the refresh token I got from iOS App I connected to the Google calendar API with this code...
require_once(APPPATH . "libraries/Google/Google_Client.php");
require_once(APPPATH . "libraries/Google/contrib/Google_CalendarService.php");
/* setup google client object */
$client = new Google_Client();
$client->setClientId(GOOGLE_CLIENT_ID);
/* refresh access token */
$client->refreshToken($google_refresh_token);
$newToken = $client->getAccessToken();
$client->setAccessToken($newToken);
/* get google calendars list */
$calendar = new Google_CalendarService($client);
$calendarList = $calendar->calendarList->listCalendarList();
echo print_r($calendarList, true);

Categories