How do i refresh google token if expired? - php

I am Creating YouTube Broadcast and it successfully working.
$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->setScopes('https://www.googleapis.com/auth/youtube');
// $client->refreshToken($accessToken);
// // $client->refreshToken($accessToken);
// $newToken = $client->getAccessToken();
// echo "new token : ". $newToken;
$client->setAccessToken($accessToken);
try {
// Define service object for making API requests.
$service = new Google_Service_YouTube($client);
// Define the $liveBroadcast object, which will be uploaded as the request body.
$liveBroadcast = new Google_Service_YouTube_LiveBroadcast();
// Add 'contentDetails' object to the $liveBroadcast object.
$liveBroadcastContentDetails = new Google_Service_YouTube_LiveBroadcastContentDetails();
$liveBroadcastContentDetails->setEnableClosedCaptions(true);
$liveBroadcastContentDetails->setEnableContentEncryption(true);
$liveBroadcastContentDetails->setEnableDvr(true);
$liveBroadcastContentDetails->setRecordFromStart(true);
$liveBroadcastContentDetails->setStartWithSlate(true);
$liveBroadcast->setContentDetails($liveBroadcastContentDetails);
// Add 'snippet' object to the $liveBroadcast object.
$liveBroadcastSnippet = new Google_Service_YouTube_LiveBroadcastSnippet();
$liveBroadcastSnippet->setScheduledStartTime($start_date_time);
$liveBroadcastSnippet->setTitle($class_name);
$liveBroadcast->setSnippet($liveBroadcastSnippet);
// Add 'status' object to the $liveBroadcast object.
$liveBroadcastStatus = new Google_Service_YouTube_LiveBroadcastStatus();
$liveBroadcastStatus->setPrivacyStatus('unlisted');
$liveBroadcast->setStatus($liveBroadcastStatus);
$response = $service->liveBroadcasts->insert('snippet,contentDetails,status', $liveBroadcast);
return ($response->id);
} catch (Google_Service_Exception $e) {
print_r($e);
} catch (Google_Exception $e) {
print_r($e);
}
but after some time Authorization failed.
token has been expired and unable to create broadcast.
I tried to refresh token but not working please help.
https://developers.google.com/youtube/v3/live/docs/liveBroadcasts/insert?apix=true[][1]

First make sure to request offline access this will return a refresh token to you
function buildClient(){
$client = new Google_Client();
$client->setAccessType("offline"); // offline access. Will result in a refresh token
$client->setIncludeGrantedScopes(true); // incremental auth
$client->setAuthConfig(__DIR__ . '/client_secrets.json');
$client->addScope([YOUR SCOPES HERE]);
return $client;
}
The first time the user authorizes you should have a refresh token in returned. Store it some place.
$client->getRefreshToken()
Make sure that you load the refresh token inside the $client->setRefreshtoken($stored) so that it has it for the next part.
Then check if the access token has expired and add the refresh token back and force a fetch of a new access token.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$client->setAccessToken($client->getAccessToken());
}

Related

Google Calendar API Token not refreshing

For some reason when my token expires I need to delete the file and reconnect again otherwise nothing is working. Is it because the new token is not stored or?
I have the following code:
if(!$_GET['id']){
echo print_r('BUSINESS NOT FOUND');
exit();
}else {
$client = new Google_Client();
$client->setApplicationName('Google Calendar API PHP Quickstart');
$client->setScopes(Google_Service_Calendar::CALENDAR);
$client->setAuthConfig(__DIR__ . '/client.json');
$client->setAccessType('offline');
$client->setPrompt('select_account consent');
// Load previously authorized token from a file, if it exists.
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
$tokenPath = '../Remindly/accounts/' . $_GET['id'] . '.json';
if (file_exists($tokenPath)) {
$accessToken = json_decode(file_get_contents($tokenPath), true);
$client->setAccessToken($accessToken);
return $client;
}
// If there is no previous token or it's expired.
if ($client->isAccessTokenExpired()) {
// Refresh the token if possible, else fetch a new one.
if ($client->getRefreshToken()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
}
// Save the token to a file.
file_put_contents($tokenPath, json_encode($client->getAccessToken()));
}
}
It seems that you are not returning client in case the token expired
Modify your code as shown in the quickstart for PHP to return the client at the end of the function - both if the access token expired and if it did not:
...
if(...){
...
}else{
$client = new Google_Client();
$client->setApplicationName('Google Calendar API PHP Quickstart');
$client->setScopes(Google_Service_Calendar::CALENDAR_READONLY);
$client->setAuthConfig('credentials.json');
$client->setAccessType('offline');
$client->setPrompt('select_account consent');
// Load previously authorized token from a file, if it exists.
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
$tokenPath = 'token.json';
if (file_exists($tokenPath)) {
$accessToken = json_decode(file_get_contents($tokenPath), true);
$client->setAccessToken($accessToken);
}
// If there is no previous token or it's expired.
if ($client->isAccessTokenExpired()) {
// Refresh the token if possible, else fetch a new one.
if ($client->getRefreshToken()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
} else {
// Request authorization from the user.
$authUrl = $client->createAuthUrl();
printf("Open the following link in your browser:\n%s\n", $authUrl);
print 'Enter verification code: ';
$authCode = trim(fgets(STDIN));
// Exchange authorization code for an access token.
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
$client->setAccessToken($accessToken);
// Check to see if there was an error.
if (array_key_exists('error', $accessToken)) {
throw new Exception(join(', ', $accessToken));
}
}
// Save the token to a file.
if (!file_exists(dirname($tokenPath))) {
mkdir(dirname($tokenPath), 0700, true);
}
file_put_contents($tokenPath, json_encode($client->getAccessToken()));
}
return $client;
}
...

How to fetch gmail in php without using imap?

I have used imap for fetching gmail using php. Is there any other way to fetch gmails using php without using imap?
You can use the gmail api to access a users gmail account. You will need to authenticate the user using Oauth2 rather than using the login and password you are probably using on the imap server.
Google has a quick start which can be found here
<?php
require __DIR__ . '/vendor/autoload.php';
if (php_sapi_name() != 'cli') {
throw new Exception('This application must be run on the command line.');
}
/**
* Returns an authorized API client.
* #return Google_Client the authorized client object
*/
function getClient()
{
$client = new Google_Client();
$client->setApplicationName('Gmail API PHP Quickstart');
$client->setScopes(Google_Service_Gmail::GMAIL_READONLY);
$client->setAuthConfig('credentials.json');
$client->setAccessType('offline');
$client->setPrompt('select_account consent');
// Load previously authorized token from a file, if it exists.
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
$tokenPath = 'token.json';
if (file_exists($tokenPath)) {
$accessToken = json_decode(file_get_contents($tokenPath), true);
$client->setAccessToken($accessToken);
}
// If there is no previous token or it's expired.
if ($client->isAccessTokenExpired()) {
// Refresh the token if possible, else fetch a new one.
if ($client->getRefreshToken()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
} else {
// Request authorization from the user.
$authUrl = $client->createAuthUrl();
printf("Open the following link in your browser:\n%s\n", $authUrl);
print 'Enter verification code: ';
$authCode = trim(fgets(STDIN));
// Exchange authorization code for an access token.
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
$client->setAccessToken($accessToken);
// Check to see if there was an error.
if (array_key_exists('error', $accessToken)) {
throw new Exception(join(', ', $accessToken));
}
}
// Save the token to a file.
if (!file_exists(dirname($tokenPath))) {
mkdir(dirname($tokenPath), 0700, true);
}
file_put_contents($tokenPath, json_encode($client->getAccessToken()));
}
return $client;
}
// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Gmail($client);
// Print the labels in the user's account.
$user = 'me';
$results = $service->users_labels->listUsersLabels($user);
if (count($results->getLabels()) == 0) {
print "No labels found.\n";
} else {
print "Labels:\n";
foreach ($results->getLabels() as $label) {
printf("- %s\n", $label->getName());
}
}

Google Sheet Access Token

I am a bit confused on the Access token. I have written a PHP script which inserts the data I get from the POST request , I already have authorized the App and it does add the Row at the end of the Sheet.
My Question is how I refresh the token when it get implemented on the server, as it will add the POST data.
Here is the Code
<?php
// Load the Google API PHP Client Library.
require_once __DIR__ . '/vendor/autoload.php';
session_start();
$client = new Google_Client();
$client->setAuthConfigFile(__DIR__ . '/client_secrets.json');
$client->addScope(Google_Service_Sheets::SPREADSHEETS);
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$client->setAccessToken($_SESSION['access_token']);
$lead = array (
"first_name" => $_POST['name'],
"email" => $_POST['email']
);
$sid = "sheet id on which the row is added";
addRowToSpreadsheet($lead, $client , $sid);
} else {
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/fb/oauth2callback.php';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
function addRowToSpreadsheet($ary_values = array(), $client , $sid) {
$sheet_service = new Google_Service_Sheets($client);
$fileId = $sid;
$values = array();
foreach( $ary_values AS $d ) {
$cellData = new Google_Service_Sheets_CellData();
$value = new Google_Service_Sheets_ExtendedValue();
$value->setStringValue($d);
$cellData->setUserEnteredValue($value);
$values[] = $cellData;
}
// Build the RowData
$rowData = new Google_Service_Sheets_RowData();
$rowData->setValues($values);
// Prepare the request
$append_request = new Google_Service_Sheets_AppendCellsRequest();
$append_request->setSheetId(0);
$append_request->setRows($rowData);
$append_request->setFields('userEnteredValue');
// Set the request
$request = new Google_Service_Sheets_Request();
$request->setAppendCells($append_request);
// Add the request to the requests array
$requests = array();
$requests[] = $request;
// Prepare the update
$batchUpdateRequest = new Google_Service_Sheets_BatchUpdateSpreadsheetRequest(array(
'requests' => $requests
));
try {
// Execute the request
$response = $sheet_service->spreadsheets->batchUpdate($fileId, $batchUpdateRequest);
if( $response->valid() ) {
// Success, the row has been added
return true;
}
} catch (Exception $e) {
// Something went wrong
error_log($e->getMessage());
}
return false;
}
?>
I have tried hosting the app on the server and it doesn't add a new row in the Sheet, I think this is a problem due to the Access Token
Please Help
There is actually a PHP Quickstart for Sheets API which includes how to refresh tokens. Here's a snippet:
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}
There's also a Refreshing an access token (offline access) guide with regard to refresh tokens
Access tokens periodically expire. You can refresh an access token
without prompting the user for permission (including when the user is
not present) if you requested offline access to the scopes associated
with the token.
If you use a Google API Client Library, the client object refreshes
the access token as needed as long as you configure that object for
offline access. If you are not using a client library, you need to set
the access_type HTTP query parameter to offline when redirecting the
user to Google's OAuth 2.0 server. In that case, Google's
authorization server returns a refresh token when you exchange an
authorization code for an access token. Then, if the access token
expires (or at any other time), you can use a refresh token to obtain
a new access token.
If your application needs offline access to a Google API, set the API
client's access type to offline:
$client->setAccessType("offline");

Google API: refresh_token missing (access type = offline)

I'm trying to connect my webapp to google drive. So I'm using PHP with official Github PHP client code [ https://github.com/google/google-api-php-client/tree/v1-master ].
I followed the quickstart [ https://developers.google.com/drive/v2/web/quickstart/php ] for v2, because PHP client is for v2 only.
Then I added a line to request offline access. [See https://developers.google.com/identity/protocols/OAuth2WebServer#offline]
My app code, developed using Yii 1, but it's not important, is:
$client = new Google_Client();
$client->setApplicationName("Google Drive Client");
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);
$client->setRedirectUri( Yii::app()->createAbsoluteUrl("site/googleApiLoginCallback") );
$client->setAuthConfigFile(CLIENT_SECRET_PATH);
$client->setAccessType('offline');
if (file_exists(CREDENTIALS_PATH)) {
$accessToken = file_get_contents(CREDENTIALS_PATH);
} else {
// Request authorization from the user.
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
Yii::app()->end();
}
$client->setAccessToken($accessToken);
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$refresh_token = $client->getRefreshToken();
// CVarDumper::dump($refresh_token,2,true);
$client->refreshToken($refresh_token);
file_put_contents(CREDENTIALS_PATH, $client->getAccessToken());
}
return $client;
This is the code for handling the OAuth callback. I simply set the access token received, then redirect to the page.
public function actionGoogleApiLoginCallback($code)
{
$client = new Google_Client();
$client->setApplicationName("Google Drive Client");
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);
$client->setRedirectUri( Yii::app()->createAbsoluteUrl("site/googleApiLoginCallback") );
$client->setAuthConfigFile(CLIENT_SECRET_PATH);
$client->setAccessType('offline');
$accessToken = $client->authenticate($code);
if(!file_exists(dirname(CREDENTIALS_PATH))) {
mkdir(dirname(CREDENTIALS_PATH), 0700, true);
}
file_put_contents(CREDENTIALS_PATH, $accessToken);
$preGoogleApiLoginRoute = Yii::app()->user->getState("preGoogleApiLoginRoute", null);
if ($preGoogleApiLoginRoute)
{
$this->redirect(array( $preGoogleApiLoginRoute ));
} else {
$this->redirect(array("site/index"));
}
}
When user the first time access the page, my webapp sucessfully redirect to Google Login; user do login, and Google redirect user to my website at site/googleApiLoginCallback. I set the received code as accessToken and redirect user to the page of webapp he come from.
It works.
BUT: After a while, when user came back to the page, tyhe token is expired. When it's executed the $client->getRefreshToken(), it returns a null, so $client->refreshToken() throw the following error because of missing refresh token
Error refreshing the OAuth2 token, message: '{ "error" : "invalid_request", "error_description" : "Missing required parameter: refresh_token" }'
What am I missing or doing wrong?
For reference: this is my json access token. As you can see I've not a field named 'refreshToken' as I expect
{"access_token":"...hiddden...","token_type":"Bearer","expires_in":3600,"created":1453759023}
From this StackOverflow question I see that statement
in order to obtain a new refresh_token after already receiving one, you will need to send your user back through the prompt, which you can do by setting approval_prompt to force.
It pointed to this old blog post by Google.
So I added
$client->setApprovalPrompt('force');
after
$client->setAccessType('offline');
And now I've the resfresh token.
I am using a bit different logic, but it works... :-)
Instead of:
...
$accessToken = file_get_contents(CREDENTIALS_PATH);
...
$client->setAccessToken($accessToken);
if ($client->isAccessTokenExpired()) {
$refresh_token = $client->getRefreshToken();
$client->refreshToken($refresh_token);
file_put_contents(CREDENTIALS_PATH, $client->getAccessToken());
}
...
I do:
...
$accessToken = file_get_contents(CREDENTIALS_PATH);
...
$client->setAccessToken($accessToken);
if (!$client->getAccessToken()) {
die('invalid access token in ' . CREDENTIALS_PATH);
}
if ($client->isAccessTokenExpired()) {
$refresh_token = json_decode($accessToken)->refresh_token;
$client->refreshToken($refresh_token);
}
... now we are authenticated ...

Google Access Token Empty

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.

Categories