I am having an issue with authorizing some requests and I am getting a 401 "Invalid Credentials" error. The application flow is as follows. The user logs in my website using the Google sign in button. I am using the offline access parameter and I am saving the refresh token in the session. After the user has logged in I am trying to retrieve all of their playlists (public and private) from their YouTube account.
$client->setScopes('https://www.googleapis.com/auth/youtube.readonly');
if (isset($_SESSION['googletoken']['refresh_token'])){
$client->setAccessToken($_SESSION['googletoken']['refresh_token']);}
$tokenSessionKey = $client->prepareScopes();
$params = [
'maxResults' => 1,
'mine' => true
];
try{
$queryParams = [
'maxResults' => 1,
'mine' => true
];
$listResponse = $youtube->playlists->listPlaylists('snippet', $queryParams);
You are setting your access token with the refresh token You should be using
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
Oauthcallback.php
require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/Oauth2Authentication.php';
// Start a session to persist credentials.
session_start();
Oauth2Authncation.php
require_once __DIR__ . '/vendor/autoload.php';
/**
* Gets the Google client refreshing auth if needed.
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Initializes a client object.
* #return A google client object.
*/
function getGoogleClient() {
$client = getOauth2Client();
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}
return $client;
}
/**
* Builds the Google client object.
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Scopes will need to be changed depending upon the API's being accessed.
* Example: array(Google_Service_Analytics::ANALYTICS_READONLY, Google_Service_Analytics::ANALYTICS)
* List of Google Scopes: https://developers.google.com/identity/protocols/googlescopes
* #return A google client object.
*/
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]);
$client->setRedirectUri(getRedirectUri());
return $client;
}
/**
* Builds the redirect uri.
* Documentation: https://developers.google.com/api-client-library/python/auth/installed-app#choosingredirecturi
* Hostname and current server path are needed to redirect to oauth2callback.php
* #return A redirect uri.
*/
function getRedirectUri(){
//Building Redirect URI
$url = $_SERVER['REQUEST_URI']; //returns the current URL
if(strrpos($url, '?') > 0)
$url = substr($url, 0, strrpos($url, '?') ); // Removing any parameters.
$folder = substr($url, 0, strrpos($url, '/') ); // Removeing current file.
return (isset($_SERVER['HTTPS']) ? "https" : "http") . '://' . $_SERVER['HTTP_HOST'] . $folder. '/oauth2callback.php';
}
/**
* Authenticating to Google using Oauth2
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Returns a Google client with refresh token and access tokens set.
* If not authencated then we will redirect to request authencation.
* #return A google client object.
*/
function getOauth2Client() {
try {
$client = buildClient();
// Set the refresh token on the client.
if (isset($_SESSION['refresh_token']) && $_SESSION['refresh_token']) {
$client->refreshToken($_SESSION['refresh_token']);
}
// If the user has already authorized this app then get an access token
// else redirect to ask the user to authorize access to Google Analytics.
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
// Set the access token on the client.
$client->setAccessToken($_SESSION['access_token']);
// Refresh the access token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$client->setAccessToken($client->getAccessToken());
$_SESSION['access_token'] = $client->getAccessToken();
}
return $client;
} else {
// We do not have access request access.
header('Location: ' . filter_var( $client->getRedirectUri(), FILTER_SANITIZE_URL));
}
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
}
// Handle authorization flow from the server.
if (! isset($_GET['code'])) {
$client = buildClient();
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
$client = buildClient();
$client->authenticate($_GET['code']); // Exchange the authencation code for a refresh token and access token.
// Add access token and refresh token to seession.
$_SESSION['access_token'] = $client->getAccessToken();
$_SESSION['refresh_token'] = $client->getRefreshToken();
//Redirect back to main script
$redirect_uri = str_replace("oauth2callback.php",$_SESSION['mainScript'],$client->getRedirectUri());
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
Related
I'm using the latest version of the Google API Client PHP SDK (v2.11) to request an OAuth2 access token.
While retrieving an access token, I can see that the expires_in value is missing from the response, which leads to a PHP error when calling isAccessTokenExpired() later on:
Step 1 - Retrieve an access and refresh token
...
$client->authenticate($_GET['code']);
$_SESSION['access_token'] = $client->getAccessToken();
$_SESSION['refresh_token'] = $client->getRefreshToken();
var_dump($client->getAccessToken());
...
Result
array(1) { ["access_token"]=> string(163) "xxxxxxxxxxxxxxxxxxx" }
It seems that both the expires_in and created columns are missing from this answer.
Step 2 - Let's check if the Access token has expired and needs to be refreshed
$client->setAccessToken($_SESSION['access_token']);
if ($client->isAccessTokenExpired())
{
$client->refreshToken($_SESSION['refresh_token']);
$_SESSION['access_token'] = $client->getAccessToken();
}
Result
Warning: Undefined array key "expires_in" in
/var/www/admin/vendor/google/apiclient/src/Client.php on line 554
This is the code I use. The library should be handling this for you.
Oauth2Callback.php
require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/Oauth2Authentication.php';
// Start a session to persist credentials.
session_start();
// Handle authorization flow from the server.
if (! isset($_GET['code'])) {
$client = buildClient();
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
$client = buildClient();
$client->authenticate($_GET['code']); // Exchange the authencation code for a refresh token and access token.
// Add access token and refresh token to seession.
$_SESSION['access_token'] = $client->getAccessToken();
$_SESSION['refresh_token'] = $client->getRefreshToken();
//Redirect back to main script
$redirect_uri = str_replace("oauth2callback.php",$_SESSION['mainScript'],$client->getRedirectUri());
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
?>
Oauth2Authentication.php
require_once __DIR__ . '/vendor/autoload.php';
/**
* Gets the Google client refreshing auth if needed.
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Initializes a client object.
* #return A google client object.
*/
function getGoogleClient() {
$client = getOauth2Client();
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}
return $client;
}
/**
* Builds the Google client object.
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Scopes will need to be changed depending upon the API's being accessed.
* Example: array(Google_Service_Analytics::ANALYTICS_READONLY, Google_Service_Analytics::ANALYTICS)
* List of Google Scopes: https://developers.google.com/identity/protocols/googlescopes
* #return A google client object.
*/
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]);
$client->setRedirectUri(getRedirectUri());
return $client;
}
/**
* Builds the redirect uri.
* Documentation: https://developers.google.com/api-client-library/python/auth/installed-app#choosingredirecturi
* Hostname and current server path are needed to redirect to oauth2callback.php
* #return A redirect uri.
*/
function getRedirectUri(){
//Building Redirect URI
$url = $_SERVER['REQUEST_URI']; //returns the current URL
if(strrpos($url, '?') > 0)
$url = substr($url, 0, strrpos($url, '?') ); // Removing any parameters.
$folder = substr($url, 0, strrpos($url, '/') ); // Removeing current file.
return (isset($_SERVER['HTTPS']) ? "https" : "http") . '://' . $_SERVER['HTTP_HOST'] . $folder. '/oauth2callback.php';
}
/**
* Authenticating to Google using Oauth2
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Returns a Google client with refresh token and access tokens set.
* If not authencated then we will redirect to request authencation.
* #return A google client object.
*/
function getOauth2Client() {
try {
$client = buildClient();
// Set the refresh token on the client.
if (isset($_SESSION['refresh_token']) && $_SESSION['refresh_token']) {
$client->refreshToken($_SESSION['refresh_token']);
}
// If the user has already authorized this app then get an access token
// else redirect to ask the user to authorize access to Google Analytics.
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
// Set the access token on the client.
$client->setAccessToken($_SESSION['access_token']);
// Refresh the access token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$client->setAccessToken($client->getAccessToken());
$_SESSION['access_token'] = $client->getAccessToken();
}
return $client;
} else {
// We do not have access request access.
header('Location: ' . filter_var( $client->getRedirectUri(), FILTER_SANITIZE_URL));
}
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
}
?>
My API response was missing expires_in due to retrieving the tokens twice in my redirect.php script (called after the user has been authenticated).
As described here, the OAuth refresh token as well as expires_in value are provided to you only during the first authorization. Adding a consent prompt also helped to address this issue.
If you are doing some testing and need to reset the authorization you gave, you can do it here: https://myaccount.google.com/permissions
Here's the full script, which is now working:
<?php
include(__DIR__.'/vendor/autoload.php');
$client = new Google_Client();
$client->setAccessType('offline');
$client->setClientId(GOOGLE_OAUTH_CLIENT_ID);
$client->setClientSecret(GOOGLE_OAUTH_CLIENT_SECRET);
$client->setRedirectUri(BASE_URL.'/redirect.php');
$client->addScope('email');
$client->addScope('profile');
$client->setPrompt('consent');
if (isset($_GET['code']) && !empty($_GET['code']))
{
$client->authenticate($_GET['code']);
if ($client->getAccessToken())
{
$google_oauth = new Google_Service_Oauth2($client);
$google_account_info = $google_oauth->userinfo->get();
if (!isset($google_account_info->hd) || $google_account_info->hd != 'mydomain.com')
die('This domain name has not been authorized.');
else
{
$redirect_uri = BASE_URL.(isset($_GET['state']) ? $_GET['state'] : '/');
$_SESSION['picture'] = $google_account_info->picture;
$_SESSION['access_token'] = $client->getAccessToken();
$_SESSION['refresh_token'] = $client->getRefreshToken();
$_SESSION['token_expiration'] = time() + 3600;
header('Location: '.filter_var($redirect_uri, FILTER_SANITIZE_URL));
exit;
}
}
}
It includes a domain check (i.e. replace mydomain.com by your own domain) as well as a referrer callback (i.e. populate state on your login page with the referrer first).
i have successfully integrated google api login and logout and both are working fine but after i logged in and try to refresh the webpage .. it shows me the below error-
Fatal error: Uncaught GuzzleHttp\Exception\ClientException: Client error: POST https://oauth2.googleapis.com/token resulted in a 400 Bad Request response: { "error":
"invalid_grant", "error_description": "Bad Request" } in
C:\xamppNew\htdocs\realestate\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php:113 Stack
trace: #0 C:\xamppNew\htdocs\realestate\vendor\guzzlehttp\guzzle\src\Middleware.php(69):
GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request),
Object(GuzzleHttp\Psr7\Response), NULL, Array, NULL) #1
C:\xamppNew\htdocs\realestate\vendor\guzzlehttp\promises\src\Promise.php(204):
GuzzleHttp\Middleware::GuzzleHttp{closure}(Object(GuzzleHttp\Psr7\Response)) #2
C:\xamppNew\htdocs\realestate\vendor\guzzlehttp\promises\src\Promise.php(153):
GuzzleHttp\Promise\Promise::callHandler(1, Object(GuzzleHttp\Psr7\Response), NULL) #3
C:\xamppNew\htdocs\realestate\vendor\guzzlehttp\promises\src\TaskQueue.php(48):
GuzzleHttp\Promise\Promise::GuzzleHttp\Promise{closure}() #4 C:\xamppNew\ht in
C:\xamppNew\htdocs\realestate\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php on line 113
My config.php -
<?php
session_start();
require_once 'vendor/autoload.php';
$google_client = new Google_Client();
$google_client->setAccessType('offline');
$google_client->setClientId('client key');
$google_client->setClientSecret('client secret key');
$google_client->setRedirectUri('http://localhost/realestate/index.php');
$google_client->addScope('email');
$google_client->addScope('profile');
?>
My index.php google api session codes-
<?php
include('config.php');
$login_button = '';
if(isset($_GET["code"]))
{
$token = $google_client->fetchAccessTokenWithAuthCode($_GET["code"]);
if(!isset($token['error']))
{
$google_client->setAccessToken($token['access_token']);
$_SESSION['access_token'] = $token['access_token'];
$google_service = new Google_Service_Oauth2($google_client);
$data = $google_service->userinfo->get();
if(!empty($data['given_name']))
{
$_SESSION['user_first_name'] = $data['given_name'];
}
if(!empty($data['family_name']))
{
$_SESSION['user_last_name'] = $data['family_name'];
}
if(!empty($data['email']))
{
$_SESSION['user_email_address'] = $data['email'];
}
if(!empty($data['gender']))
{
$_SESSION['user_gender'] = $data['gender'];
}
if(!empty($data['picture']))
{
$_SESSION['user_image'] = $data['picture'];
}
}
}
if(!isset($_SESSION['access_token']))
{
$login_button = '<a href="'.$google_client->createAuthUrl().'">Login With
Google</a>';
}
?>
//this is for testing purpose
<?php if($login_button == '') {echo '<h3><b>Name :</b>
'.$_SESSION['user_first_name'].' '.$_SESSION['user_last_name'].'</h3>';
echo '<h3><a href="logout.php">Logout</h3>
</div>'; }?>
//this is the login button-
<?php echo '<a class="btn connect-google">'.$login_button . '</a>'; ?>
My logout.php-
<?php
include('config.php');
$accesstoken=$_SESSION['access_token'];
//Reset OAuth access token
$google_client->revokeToken($accesstoken);
//Destroy entire session data.
session_destroy();
//redirect page to index.php
header('location:index');
?>
I have no idea how why it is happening and how to fix this. Btw after i logged in though google api in my website and refresh the page , it should refresh successfully while staying logged in . But it shows me the error and when i click back it takes to me google login page again.
I think your issue is that your not using your refresh token properly
oauth2callback.php
Notice how when the code is returned that i am storing both the access token and the refresh token into the session.
require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/Oauth2Authentication.php';
// Start a session to persist credentials.
session_start();
// Handle authorization flow from the server.
if (! isset($_GET['code'])) {
$client = buildClient();
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
$client = buildClient();
$client->authenticate($_GET['code']); // Exchange the authencation code for a refresh token and access token.
// Add access token and refresh token to seession.
$_SESSION['access_token'] = $client->getAccessToken();
$_SESSION['refresh_token'] = $client->getRefreshToken();
//Redirect back to main script
$redirect_uri = str_replace("oauth2callback.php",$_SESSION['mainScript'],$client->getRedirectUri());
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
Oauth2Authentication.php
Then check this to see how i test if the access token is expired and if it is i use the refresh token to fetch a new one.
require_once __DIR__ . '/vendor/autoload.php';
/**
* Gets the Google client refreshing auth if needed.
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Initializes a client object.
* #return A google client object.
*/
function getGoogleClient() {
$client = getOauth2Client();
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}
return $client;
}
/**
* Builds the Google client object.
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Scopes will need to be changed depending upon the API's being accessed.
* Example: array(Google_Service_Analytics::ANALYTICS_READONLY, Google_Service_Analytics::ANALYTICS)
* List of Google Scopes: https://developers.google.com/identity/protocols/googlescopes
* #return A google client object.
*/
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]);
$client->setRedirectUri(getRedirectUri());
return $client;
}
/**
* Builds the redirect uri.
* Documentation: https://developers.google.com/api-client-library/python/auth/installed-app#choosingredirecturi
* Hostname and current server path are needed to redirect to oauth2callback.php
* #return A redirect uri.
*/
function getRedirectUri(){
//Building Redirect URI
$url = $_SERVER['REQUEST_URI']; //returns the current URL
if(strrpos($url, '?') > 0)
$url = substr($url, 0, strrpos($url, '?') ); // Removing any parameters.
$folder = substr($url, 0, strrpos($url, '/') ); // Removeing current file.
return (isset($_SERVER['HTTPS']) ? "https" : "http") . '://' . $_SERVER['HTTP_HOST'] . $folder. '/oauth2callback.php';
}
/**
* Authenticating to Google using Oauth2
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Returns a Google client with refresh token and access tokens set.
* If not authencated then we will redirect to request authencation.
* #return A google client object.
*/
function getOauth2Client() {
try {
$client = buildClient();
// Set the refresh token on the client.
if (isset($_SESSION['refresh_token']) && $_SESSION['refresh_token']) {
$client->refreshToken($_SESSION['refresh_token']);
}
// If the user has already authorized this app then get an access token
// else redirect to ask the user to authorize access to Google Analytics.
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
// Set the access token on the client.
$client->setAccessToken($_SESSION['access_token']);
// Refresh the access token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$client->setAccessToken($client->getAccessToken());
$_SESSION['access_token'] = $client->getAccessToken();
}
return $client;
} else {
// We do not have access request access.
header('Location: ' . filter_var( $client->getRedirectUri(), FILTER_SANITIZE_URL));
}
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
}
userinfo
Also you should consider going though the People api instead of the userinfo endpoint its much more stable when requesting user profile information, as you are already requesting email and profile scopes you should already have access.
I am reading calendar events successfully, but when the access token expires, I cannot refresh it. Up until now, I have been getting a new access token but this doesn't seem correct. I would rather refresh it properly.
I receive this error :
refresh token must be passed in or set as part of setAccessToken
From events.php
function GetEvents()
{
$client = new \Google_Client();
$credentialsPath = '/cfg/GoogleClientSecret.json';
$client->setAuthConfig($credentialsPath);
$client->addScope(\Google_Service_Calendar::CALENDAR_READONLY);
$client->setAccessType('offline');
if (isset($_SESSION['access_token']) && $_SESSION['access_token'])
{
$client->setAccessToken($_SESSION['access_token']);
if ($client->isAccessTokenExpired())
{
$refreshTokenSaved = $client->getRefreshToken();
/**** This line fails ****/
$client->fetchAccessTokenWithRefreshToken($refreshTokenSaved);
/*************************/
$accessTokenUpdated = $client->getAccessToken();
$accessTokenUpdated['refresh_token'] = $refreshTokenSaved;
//Need to do more here once i have the new access token.
}
ReadThroughEvents($client);
}
else
{
$redirect_uri = 'oauthcallback.php';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
oauthcallback.php
require 'google-api-php-client-2.4.0 2/vendor/autoload.php';
session_start();
$client = new \Google_Client();
$client->setAuthConfigFile('/cfg/GoogleClientSecret.json');
$callbackuri = 'oauthcallback.php';
$client->setRedirectUri($callbackuri);
$client->addScope(Google_Service_Calendar::CALENDAR_READONLY);
if (! isset($_GET['code']))
{
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
}
else
{
$client->authenticate($_GET['code']);
$_SESSION['access_token'] = $client->getAccessToken();
$redirect_uri = 'events.php';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
fetchAccessTokenWithRefreshToken should work assuming that the refresh token you are sending it is in fact a refresh token and not null or something. I would try and print it out so that you can see its actually a value.
Here is my code.
oauth2callback.php
require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/Oauth2Authentication.php';
// Start a session to persist credentials.
session_start();
// Handle authorization flow from the server.
if (! isset($_GET['code'])) {
$client = buildClient();
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
$client = buildClient();
$client->authenticate($_GET['code']); // Exchange the authencation code for a refresh token and access token.
// Add access token and refresh token to seession.
$_SESSION['access_token'] = $client->getAccessToken();
$_SESSION['refresh_token'] = $client->getRefreshToken();
//Redirect back to main script
$redirect_uri = str_replace("oauth2callback.php",$_SESSION['mainScript'],$client->getRedirectUri());
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
Oauth2Authentication.php
require_once __DIR__ . '/vendor/autoload.php';
/**
* Gets the Google client refreshing auth if needed.
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Initializes a client object.
* #return A google client object.
*/
function getGoogleClient() {
$client = getOauth2Client();
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}
return $client;
}
/**
* Builds the Google client object.
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Scopes will need to be changed depending upon the API's being accessed.
* Example: array(Google_Service_Analytics::ANALYTICS_READONLY, Google_Service_Analytics::ANALYTICS)
* List of Google Scopes: https://developers.google.com/identity/protocols/googlescopes
* #return A google client object.
*/
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]);
$client->setRedirectUri(getRedirectUri());
return $client;
}
/**
* Builds the redirect uri.
* Documentation: https://developers.google.com/api-client-library/python/auth/installed-app#choosingredirecturi
* Hostname and current server path are needed to redirect to oauth2callback.php
* #return A redirect uri.
*/
function getRedirectUri(){
//Building Redirect URI
$url = $_SERVER['REQUEST_URI']; //returns the current URL
if(strrpos($url, '?') > 0)
$url = substr($url, 0, strrpos($url, '?') ); // Removing any parameters.
$folder = substr($url, 0, strrpos($url, '/') ); // Removeing current file.
return (isset($_SERVER['HTTPS']) ? "https" : "http") . '://' . $_SERVER['HTTP_HOST'] . $folder. '/oauth2callback.php';
}
/**
* Authenticating to Google using Oauth2
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Returns a Google client with refresh token and access tokens set.
* If not authencated then we will redirect to request authencation.
* #return A google client object.
*/
function getOauth2Client() {
try {
$client = buildClient();
// Set the refresh token on the client.
if (isset($_SESSION['refresh_token']) && $_SESSION['refresh_token']) {
$client->refreshToken($_SESSION['refresh_token']);
}
// If the user has already authorized this app then get an access token
// else redirect to ask the user to authorize access to Google Analytics.
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
// Set the access token on the client.
$client->setAccessToken($_SESSION['access_token']);
// Refresh the access token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$client->setAccessToken($client->getAccessToken());
$_SESSION['access_token'] = $client->getAccessToken();
}
return $client;
} else {
// We do not have access request access.
header('Location: ' . filter_var( $client->getRedirectUri(), FILTER_SANITIZE_URL));
}
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
}
I'll like to update the title, short description and full description of my apps in google developper console.
I cannot do it in PHP, I have found some examples in python but I need in PHP.
Here is what I've done till now :
function updateListing($configFileJSON) {
echo "Updating Listings"."\n";
$packageName = 'com.mycompany.myapp';
$client = new Google_Client();
$client->setApplicationName($packageName);
$client->setClientId('100......usercontent.com');
$key = "Rdhmg......5_t";
$client->setClientSecret($key);
$client->setScopes(array('https://www.googleapis.com/auth/androidpublisher') );
try {
$service = new Google_Service_AndroidPublisher($client);
$app_edit = new Google_Service_AndroidPublisher_AppEdit();
$edits = $service->edits;
$edit_request = $edits->insert($packageName,$app_edit);
$edit = $edit_request->execute();
$editId = $edit->getId();
echo ("Created edit with id: $editId");
$listing = $service->listings;
$listing.setTitle("WWW");
$listing.setFullDescription("WWW");
$listing.setShortDescription("WWW");
// $listing.setVideo("WWW");
$updateListingsRequest = $edits->listings()->update($packageName,$editId,"af", $listing);
$updatedUsListing = $updateListingsRequest->execute();
echo("Created new AF app listing with title: " . $$updatedUsListing->getTitle());
} catch (Exception $e) {
var_dump( $e->getMessage() );
}
echo "ENDING"."\n";
}
I know there is still some code missing, but until now I get :
string(238) "{
"error": {
"errors": [
{
"domain": "global",
"reason": "required",
"message": "Login Required",
"locationType": "header",
"location": "Authorization"
}
],
"code": 401,
"message": "Login Required"
}
}
the sample in python is:
def main(argv):
# Authenticate and construct service.
service, flags = sample_tools.init(
argv,
'androidpublisher',
'v2',
__doc__,
__file__, parents=[argparser],
scope='https://www.googleapis.com/auth/androidpublisher')
# Process flags and read their values.
package_name = flags.package_name
try:
edit_request = service.edits().insert(body={}, packageName=package_name)
result = edit_request.execute()
edit_id = result['id']
listing_response_us = service.edits().listings().update(
editId=edit_id, packageName=package_name, language='af',
body={'fullDescription': 'Dessert trunk truck',
'shortDescription': 'Bacon ipsum',
'title': 'App Title US'}).execute()
print ('Listing for language %s was updated.'
% listing_response_us['language'])
listing_response_gb = service.edits().listings().update(
editId=edit_id, packageName=package_name, language='am',
body={'fullDescription': 'Pudding boot lorry',
'shortDescription': 'Pancetta ipsum',
'title': 'App Title UK'}).execute()
print ('Listing for language %s was updated.'
% listing_response_gb['language'])
commit_request = service.edits().commit(
editId=edit_id, packageName=package_name).execute()
# print 'Edit "%s" has been committed' % (commit_request['id'])
except client.AccessTokenRefreshError:
print ('The credentials have been revoked or expired, please re-run the '
'application to re-authorize')
if __name__ == '__main__':
main(sys.argv)
what I'm missing in the authentificate part? anyone have a sample of updating app listing in PHP?
Thanks
Your code appears to be missing the entire authentication section.
Oauth2Authentication.php
require_once __DIR__ . '/vendor/autoload.php';
/**
* Gets the Google client refreshing auth if needed.
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Initializes a client object.
* #return A google client object.
*/
function getGoogleClient() {
$client = getOauth2Client();
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}
return $client;
}
/**
* Builds the Google client object.
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Scopes will need to be changed depending upon the API's being accessed.
* Example: array(Google_Service_Analytics::ANALYTICS_READONLY, Google_Service_Analytics::ANALYTICS)
* List of Google Scopes: https://developers.google.com/identity/protocols/googlescopes
* #return A google client object.
*/
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]);
$client->setRedirectUri(getRedirectUri());
return $client;
}
/**
* Builds the redirect uri.
* Documentation: https://developers.google.com/api-client-library/python/auth/installed-app#choosingredirecturi
* Hostname and current server path are needed to redirect to oauth2callback.php
* #return A redirect uri.
*/
function getRedirectUri(){
//Building Redirect URI
$url = $_SERVER['REQUEST_URI']; //returns the current URL
if(strrpos($url, '?') > 0)
$url = substr($url, 0, strrpos($url, '?') ); // Removing any parameters.
$folder = substr($url, 0, strrpos($url, '/') ); // Removeing current file.
return (isset($_SERVER['HTTPS']) ? "https" : "http") . '://' . $_SERVER['HTTP_HOST'] . $folder. '/oauth2callback.php';
}
/**
* Authenticating to Google using Oauth2
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Returns a Google client with refresh token and access tokens set.
* If not authencated then we will redirect to request authencation.
* #return A google client object.
*/
function getOauth2Client() {
try {
$client = buildClient();
// Set the refresh token on the client.
if (isset($_SESSION['refresh_token']) && $_SESSION['refresh_token']) {
$client->refreshToken($_SESSION['refresh_token']);
}
// If the user has already authorized this app then get an access token
// else redirect to ask the user to authorize access to Google Analytics.
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
// Set the access token on the client.
$client->setAccessToken($_SESSION['access_token']);
// Refresh the access token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$client->setAccessToken($client->getAccessToken());
$_SESSION['access_token'] = $client->getAccessToken();
}
return $client;
} else {
// We do not have access request access.
header('Location: ' . filter_var( $client->getRedirectUri(), FILTER_SANITIZE_URL));
}
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
}
oauth2callback.php
require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/Oauth2Authentication.php';
// Start a session to persist credentials.
session_start();
// Handle authorization flow from the server.
if (! isset($_GET['code'])) {
$client = buildClient();
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
$client = buildClient();
$client->authenticate($_GET['code']); // Exchange the authencation code for a refresh token and access token.
// Add access token and refresh token to seession.
$_SESSION['access_token'] = $client->getAccessToken();
$_SESSION['refresh_token'] = $client->getRefreshToken();
//Redirect back to main script
$redirect_uri = str_replace("oauth2callback.php",$_SESSION['mainScript'],$client->getRedirectUri());
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
I'm trying to run google drive API example. I set my project in the google API console. I uploaded script to hosting.
index.php
<?php
require_once __DIR__.'/vendor/autoload.php';
session_start();
//session_unset();
$client = new Google_Client();
$client->setAuthConfig('client_secrets.json');
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$client->setAccessToken($_SESSION['access_token']);
$drive = new Google_Service_Drive($client);
$files = $drive->files->listFiles(array())->getFiles();
echo json_encode($files);
} else {
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
OAuth2callback.php
<?php
require_once __DIR__.'/vendor/autoload.php';
session_start();
$client = new Google_Client();
$client->setAuthConfigFile('client_secrets.json');
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);
if (! isset($_GET['code'])) {
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
$client->authenticate($_GET['code']);
$_SESSION['access_token'] = $client->getAccessToken();
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
It works. But in couple of hours I received error 401. I uncommented session_unset(); run once and commented again. It works. What I need to correct?
You should be requesting offline access so that you have a refresh token that you can use to request a new access token
The following file is rather large i have only copied the section with the refresh token.
Oauth2Authentication.php
require_once __DIR__ . '/vendor/autoload.php';
/**
* Gets the Google client refreshing auth if needed.
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Initializes a client object.
* #return A google client object.
*/
function getGoogleClient() {
$client = getOauth2Client();
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}
return $client;
}
/**
* Builds the Google client object.
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Scopes will need to be changed depending upon the API's being accessed.
* Example: array(Google_Service_Analytics::ANALYTICS_READONLY, Google_Service_Analytics::ANALYTICS)
* List of Google Scopes: https://developers.google.com/identity/protocols/googlescopes
* #return A google client object.
*/
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]);
$client->setRedirectUri(getRedirectUri());
return $client;
}
/**
* Builds the redirect uri.
* Documentation: https://developers.google.com/api-client-library/python/auth/installed-app#choosingredirecturi
* Hostname and current server path are needed to redirect to oauth2callback.php
* #return A redirect uri.
*/
function getRedirectUri(){
//Building Redirect URI
$url = $_SERVER['REQUEST_URI']; //returns the current URL
if(strrpos($url, '?') > 0)
$url = substr($url, 0, strrpos($url, '?') ); // Removing any parameters.
$folder = substr($url, 0, strrpos($url, '/') ); // Removeing current file.
return (isset($_SERVER['HTTPS']) ? "https" : "http") . '://' . $_SERVER['HTTP_HOST'] . $folder. '/oauth2callback.php';
}
/**
* Authenticating to Google using Oauth2
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Returns a Google client with refresh token and access tokens set.
* If not authencated then we will redirect to request authencation.
* #return A google client object.
*/
function getOauth2Client() {
try {
$client = buildClient();
// Set the refresh token on the client.
if (isset($_SESSION['refresh_token']) && $_SESSION['refresh_token']) {
$client->refreshToken($_SESSION['refresh_token']);
}
// If the user has already authorized this app then get an access token
// else redirect to ask the user to authorize access to Google Analytics.
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
// Set the access token on the client.
$client->setAccessToken($_SESSION['access_token']);
// Refresh the access token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$client->setAccessToken($client->getAccessToken());
$_SESSION['access_token'] = $client->getAccessToken();
}
return $client;
} else {
// We do not have access request access.
header('Location: ' . filter_var( $client->getRedirectUri(), FILTER_SANITIZE_URL));
}
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
}
oauth2callback.php
require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/Oauth2Authentication.php';
// Start a session to persist credentials.
session_start();
// Handle authorization flow from the server.
if (! isset($_GET['code'])) {
$client = buildClient();
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
$client = buildClient();
$client->authenticate($_GET['code']); // Exchange the authencation code for a refresh token and access token.
// Add access token and refresh token to seession.
$_SESSION['access_token'] = $client->getAccessToken();
$_SESSION['refresh_token'] = $client->getRefreshToken();
//Redirect back to main script
$redirect_uri = str_replace("oauth2callback.php",$_SESSION['mainScript'],$client->getRedirectUri());
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
Once you have a refresh token your code will be able to refresh the users access after the access token has expired.
Note Above code is my own sample code and not official google samples.