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!!!
Related
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();
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);
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 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 want to build a script that will check a Authenticated User's Google Calendar via the Google Calendar PHP Client. I was able to build a simple page that lets a user Auth and give permission to the Calendar Events. I receive a token and then grab a 15 upcoming events via:
$googleCal = new Google_Service_Calendar($googleClient);
$results = $googleCal->events->listEvents($calendarId, $optParams);
But what I'm struggling with is how to save this so I can have a script check this everyday to see if there were new events added. I think what I have is close just struggling to get over the finish line.
Thanks!
--
Update, I'm trying to use the refresh token, here is my code:
public function checkRedirectCode()
{
if(isset($_GET['code']))
{
$this->client->authenticate($_GET['code']);
// $this->setToken($this->client->getRefreshToken());
$this->setToken($this->client->getAccessToken());
$this->storeUser($this->getPayload());
return true;
}
return false;
}
public function setToken($token)
{
$_SESSION['access_token'] = $token;
$this->client->setAccessToken($token);
}
I have been able to echo the refresh token so I know I'm getting a proper refresh token but I'm getting errors whenever I use the commented out string. Any ideas?
To enable your script to be called beyond the lifetime of the original access token (which only last an hour), you will need to retrieve and store the refresh token during the initial authorisation, and then use this to generate a new access token each time your script runs.
Access tokens have limited lifetimes. If your application needs access
to a Google API beyond the lifetime of a single access token, it can
obtain a refresh token. A refresh token allows your application to
obtain new access tokens.
https://developers.google.com/identity/protocols/OAuth2#basicsteps (4. Refresh the access token, if necessary.)
After the user has authenticated your app, they are returned to your redirect URI with the code query-string.
The following is an example of authenticating and getting the refresh token (this uses Analytics, but should be the same for other services):
$client = new Google_Client();
$client->setClientId('xxx');
$client->setClientSecret('xxx');
$client->setRedirectUri('xxx');
//authenticate with the code returned from google
$authenticate = $client->authenticate($_GET['code']);
//get the refresh token
$refreshToken = $client->getRefreshToken();
//store refresh token in database...
Then, when you run your daily script, use the refresh token (retrieved from your database) to generate a new access token:
$client = new Google_Client();
$client->setClientId('xxx');
$client->setClientSecret('yyy');
$client->addScope(Google_Service_Analytics::ANALYTICS_READONLY);
$client->refreshToken($user->refresh_token);
$newToken = $client->getAccessToken();
$client->setAccessToken($newToken);