So I've literally copied the code from the Google example (https://developers.google.com/google-apps/calendar/quickstart/php) and followed its instructions as best as I can, and then my calendar worked quite well. But I've come in today and realized that it stopped working, and I can't figure out what's wrong.
I believe the root of my problem is this line :
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
since that line gives me this error
Uncaught LogicException: refresh token must be passed in or set as part of setAccessToken
There are similar questions (Get refresh token google api, Not receiving Google OAuth refresh token) But I don't seem to be able to solve my problem with their answers.
Another note; $client->getRefreshToken() seems to be returning null when I test it, which is why I think $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken()); is failing.
So this is the piece of code directly from the example that is in question
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}
That piece of code gives me errors because $client->getRefreshToken() is null, but I was under the assumption that I needed to use the refresh token to get a new token, which I can't do if there is no refresh token?
Also note, that this is already being set at the beginning of the calls
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
In your code
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}
there is one important thing missing:
before you get your refresh token, you should check first if it exists, and if not - create it first. This is what it should look like:
// Refresh the access token if it's expired.
if ($client->isAccessTokenExpired())
{
// Refresh the refresh token if possible, else fetch a new one.
if ($client->getRefreshToken()) // checks if the refresh token exists
{
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken()); //creates an access token, provided that a refresh token exists
} else // If the refresh token does not exist, you have to create it first
{
$authUrl = $client->createAuthUrl();
printf("Open the following link in your browser:\n%s\n", $authUrl); // you will be prompted to follow the authentification link and perform the authentification
print 'Enter verification code: '; // subsequently you will receive a verification code that you need to create a new token
$authCode = trim(fgets(STDIN));
Btw: If your refresh token already exists - it should be in the token.json file under your token path, however it could be invalid if you have changed the scopes after it was created. In this case, you should erase the token.json file, so that a new one can be generated.
Please note that access tokens have a limited lifetime and when it happens, this causes your Calendar to stop working. So, as suggested in Token expiration, you should write in your code to anticipate the possibility that a granted token might no longer work. This is where, refresh tokens becomes very useful for it allows your application to obtain new access tokens without going through the Authorization process again.
To request a refresh token, add access_type=offline to your authentication request. However, this GitHub post suggests that you could obtain the refresh token by providing the parameters
access_type=offline&approval_prompt=force in your request.
For more helpful tips, I think the following links will be beneficial:
The OAuth 2.0 Authorization Framework
OAuth2 and Google APIs Library for PHP
How and when to use the refresh token with PHP Google Calender API
Related
I am currently facing this problem: once I authorized youtube to access my account and after saving the token in a file called "token.txt," everything runs smoothly until the token expires. My script is not able to refresh the token.
Error
Caught Google service Exception 0 message is refresh token must be
passed in or set as part of setAccessTokenStack trace is #0
/home/omqoygue/contest.diamante.live/vendor/google/apiclient/src/Client.php(321):
Google\Client->fetchAccessTokenWithRefreshToken(NULL)
#1 /home/omqoygue/contest.diamante.live/upload.php(40): Google\Client->refreshToken(NULL)
#2 /home/omqoygue/contest.diamante.live/index.php(18): include('/home/omqoygue/...')
#3 {main}
This is where the token is created and stored in a file.
if (isset($_SESSION['token'])) {
$client->setAccessToken($_SESSION['token']);
$token = json_encode($_SESSION['token']);
file_put_contents('token.txt', $token);
foreach ($_SESSION['token'] as $key => $value) {
echo '<code>'.$key.":".$value."<br>".'</code>';
}
}
This is the part where the token validity is checked. If it has expired, it should be updated, but this does not happen.
$token = file_get_contents('token.txt');
try {
// Client init
$client = new Google_Client();
$client->setApplicationName($application_name);
$client->setClientId($client_id);
$client->setAccessType('offline');
$client->setAccessToken($token);
$client->setScopes($scope);
$client->setClientSecret($client_secret);
if ($client->getAccessToken()) {
/**
* Check to see if our access token has expired.
* If so, get a new one and save it to file for future use.
*/
if ($client->isAccessTokenExpired()) {
$newToken = json_decode($client->getAccessToken());
$client->refreshToken($newToken->refreshToken);
file_put_contents('token.txt', $client->getAccessToken());
}
}
}
When the token expires, I have to give permission again to youtube to access my account. I hope someone can help me, I have already checked the other posts on the subject, but they are obsolete.
If your refresh token is expired then you will need to authorize the app again there is no way around that. The easiest way to do that with your code is to delete 'token.txt' it should prompt you to authorize the app again.
Once your app is set to production instead of testing in Google developer console your token will stop expiring every seven days.
I got a refresh token using OAuth playground, but I am not sure what to do with it. Using the php sample code to upload a video, I added this line of code
$client->refreshToken($refreshToken);
Is this all I need to do?
Few more steps are required once you have the OAuth2 refresh token:
Define the path to credentials file obtain from Google's dev console (also called "client-secret") and set it for $client:
$credentialsFilePath = "client_secret_file.json";
$client->setAuthConfig($credentialsFilePath);
Add the required scope (see here) which should match the scope defined when you received the refresh token (after first user's consent), this is a scope example for Gmail:
$client->addScope('https://mail.google.com/');
Set your refresh token (gets a new token and sets it to the $client):
$refreshToken = "1/Je...................";
$client->refreshToken($refreshToken);
Get your access token (which I like to store in session):
$_SESSION['access_token'] = $client->getAccessToken();
Start calling the API:
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
// API calls
}
Full code for Gmail requests using OAuth2 with a refresh token:
https://eval.in/776863
I previously had issue with the Google account to access Youtube's API. So i created a new fresh gmail account & managed to get it working. Not only after like One hour. I found out that Refresh Token wasn't refreshing. I don't know why. This is becoming frustrating as it seems i would have to forfeit using Youtube services any longer.
This is my code below: perhaps i'm doing something wrong.
$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->setScopes('https://www.googleapis.com/auth/youtube');
$redirect = filter_var('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'],
FILTER_SANITIZE_URL);
$client->setRedirectUri($redirect);
$client->setAccessType('offline');
$client->setApprovalPrompt('force'); // this line is important when you revoke permission from your app, it will prompt google approval dialogue box forcefully to user to grant offline access
// Define an object that will be used to make all API requests.
$youtube = new Google_Service_YouTube($client);
// Check if an auth token exists for the required scopes
$tokenSessionKey = 'token-' . $client->prepareScopes();
$_SESSION[$tokenSessionKey] = $manually_stored_token; //$client->getAccessToken();
if (isset($_SESSION[$tokenSessionKey])) {
$client->setAccessToken($_SESSION[$tokenSessionKey]);
}
// Check to ensure that the access token was successfully acquired.
if($client->isAccessTokenExpired()) {
$client->refreshToken($refresh_token);
if(!$client->isAccessTokenExpired()) {
// do something
} else {
// refresh access token not granted
}
} else if ($client->getAccessToken()) {
// do something
} else {
// do something
}
I checked my account https://myaccount.google.com/u/0/security, under "Sign-in & Security" for authorized access to your Google Account, I still have authorization. So i don't know why its not refreshing my Token.
When you first authorise, you are given both the access_token and refresh_token in the response.
After that, you will only get a access_token back.
The refresh_token you must save and re-use.
If for what ever reason you loose it, you must reset your authorise access.
I had this issue and had to make a dirty hack as no one could give me an answer.
Basic fix is to "un-authorise" a user and then "re-authorise" them again. As if you do not, you will never get the refresh_token back.
To test and inspect. Open your account that is being authorised.
Go into the Dashboard and find "Apps connected to your account" section.
There you will see your app and can manually remove it for testing.
However, you will need to code for this later, but is good enough for testing.
I am using Google Drive API and authenticating using OAuth token using PHP program. For my test program I went to OAuth url manually and created a token. Then, I used it in the program and saved it to the file. From next time onwards the token is loaded from file and the program is able to access Google Drive. However, since the token would only be valid for 1 hr, after that I get the error since the token it retrieves from the file won't be valid anymore. I am not clear on how I can refresh the token so that its not required to manually obtain a new token.
Following is my code -
$client = new Google_Client();
$client->setClientId( CLIENT_ID );
$client->setClientSecret( CLIENT_SECRET );
$client->setRedirectUri( REDIRECT_URIS );
$client->setScopes($SCOPES);
$client->setAccessType('offline');
$client->setAuthConfigFile(CLIENT_SECRET_PATH);
If the cred file exist, I pull the token from that file else I would be fetching it. For now, the first time token I am setting manually -
if (file_exists(CREDENTIALS_PATH)) {
$accessToken = file_get_contents(CREDENTIALS_PATH);
} else {
$authCode = 'My Auth Code';
$accessToken = $client->authenticate($authCode);
}
file_put_contents(CREDENTIALS_PATH, $accessToken);
$client->setAccessToken($accessToken);
Now, if the token is expired I need to refresh the token automatically.
if ($client->isAccessTokenExpired()) {
//This is where I am running in trouble.
}
How do I achieve it? The target is to perform OAuth authentication and execute Google Drive API without any manual intervention.
Thank you for the help!
Looks like I found the answer.
I used the OAuth url for the first time access to include the parameter prompt=consent. So this generated the refresh-token that was saved in the file. After that, following addition to code did the trick -
if ($client->isAccessTokenExpired()) {
$client->refreshToken($client->getRefreshToken());
file_put_contents(CREDENTIALS_PATH, $client->getAccessToken());
}
After this the token is no longer expiring after an hour.
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!!!