Reputation: 119
I'm developing module for obtaining additional data from google analytics account. To get this data Google requires access_token. This is what I've managed so far
if (isset($_GET['code'])) {
// try to get an access token
$code = $_GET['code'];
$url = 'https://accounts.google.com/o/oauth2/token';
$params = array(
"code" => $code,
"client_id" => "559825975819-881lg83vs8feo70v5unqa8kfoijuvfnn.apps.googleusercontent.com",
"client_secret" => "vj4UNNItAJocX4RkNaD_3DQ4",
"redirect_uri" => 'http://' . $_SERVER["HTTP_HOST"] . $_SERVER["PHP_SELF"],
"access_type" => "offline",
"grant_type" => "authorization_code"
);
$ch = curl_init();
curl_setopt($ch, constant("CURLOPT_" . 'URL'), $url);
curl_setopt($ch, constant("CURLOPT_" . 'POST'), true);
curl_setopt($ch, constant("CURLOPT_" . 'POSTFIELDS'), $params);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
$data = (json_decode($output, true));
$access_token_var = $data['access_token'];
echo $access_token_var;
} else {
$url = "https://accounts.google.com/o/oauth2/auth";
$params = array(
"response_type" => "code",
"client_id" => "559825975819-881lg83vs8feo70v5unqa8kfoijuvfnn.apps.googleusercontent.com",
"redirect_uri" => 'http://' . $_SERVER["HTTP_HOST"] . $_SERVER["PHP_SELF"],
"scope" => "https://www.googleapis.com/auth/analytics",
"access_type" => "offline",
"approval_prompt" => "force"
);
$request_to = $url . '?' . http_build_query($params);
header("Location: " . $request_to);
}
And I'm getting access_token, it is echoing in needed variable. But I want to obtain analytics additional data in background process (for example, while client making order and clicking order button), but everytime I need new access_token, i need to authorize with my google account, and therefore, every client on web site needs to do this, despite the fact, that I set up "access_type" => "offline". What's wrong? Or is it something wrong with my API app?
Upvotes: 5
Views: 907
Reputation: 7918
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.
Requesting offline access is a requirement for any application that needs to access a Google API when the user is not present. For example, an app that performs backup services or executes actions at predetermined times needs to be able to refresh its access token when the user is not present. The default style of access is called online.
Server-side web applications, installed applications, and devices all obtain refresh tokens during the authorization process. Refresh tokens are not typically used in client-side (JavaScript) web applications.
For those using the Google API Client Library for PHP and seeking offline access and refresh tokens beware as of the time of this writing the docs are showing incorrect examples.
currently it's showing:
$client = new Google_Client();
$client->setAuthConfig('client_secret.json');
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');
// offline access will give you both an access and refresh token so that
// your app can refresh the access token without user interaction.
$client->setAccessType('offline');
// Using "consent" ensures that your application always receives a refresh token.
// If you are not using offline access, you can omit this.
$client->setApprovalPrompt("consent");
$client->setIncludeGrantedScopes(true); // incremental auth
source: https://developers.google.com/identity/protocols/OAuth2WebServer#offline
All of this works great - except ONE piece
$client->setApprovalPrompt("consent");
After a bit of reasoning I changed this line to the following and EVERYTHING WORKED
$client->setPrompt("consent");
It makes sense since using the HTTP requests it was changed from #approval_prompt=force# to #prompt=consent#. So changing the setter method from setApprovalPrompt to setPrompt follows natural convention - BUT IT'S NOT IN THE DOCS!!! That I found at least.
Upvotes: 0
Reputation: 301
The access token expire after a short amount of time. You need to refresh the access token every time it expires.
https://developers.google.com/identity/protocols/OAuth2WebServer
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.
You don't have to refresh to access token yourself. You can use Goggle php library https://github.com/googleapis/google-api-php-client so it can refresh the token automatically. Here is an example taken from Google website.
$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())->getItems();
echo json_encode($files);
} else {
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
If you don't want or can't use Google Php library, 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. You can use the same way you get the access token via curl but with different params.
POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded
client_id=<your_client_id>&
client_secret=<your_client_secret>&
refresh_token=<refresh_token>&
grant_type=refresh_token
Upvotes: 7