I wrote a method to get the Google client and refresh the token file when needed. However $client->isAccessTokenExpired() always returns true, so every request a new token gets dumped.
I have already read this question. The answer does not apply to me. I already do the steps in the right order.
Hopefully someone can steer me in the right direction.
/**
* Initialize Google Client and return it
* #return Client
*/
private function getClient()
{
if ( $this->client !== null ) {
return $this->client;
}
$client = new Client();
$client->setClientId($this->google_client_id);
$client->setClientSecret($this->google_client_secret);
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
$client->setAccessToken(file_get_contents($this->google_token));
if($client->isAccessTokenExpired()) {
try {
$fs = new FileSystem();
$fs->dumpFile($this->google_token, json_encode($client->getAccessToken()));
$this->logger->info(sprintf('Dumped new Google OAuth token in: %s', $this->google_token));
} catch(IOException $e) {
$this->logger->critical(sprintf('Error dumping new Google OAuth token: %s', $e->getMessage());
}
}
$this->client = $client;
return $this->getClient();
}
Related
I have this code to authenticate the user using oauth 2.0 api in php but I want to change the expiry time of the token usually the token expires in 1 hour but I have to change it to the maximum time I think it is 200 days. how can I achieve that. Any help or suggestion will be appreciated
<?php
class Connection {
public function __construct() {
$this->credentials = "credentials.json";
$this->client = $this->create_client();
}
public function get_client() {
return $this->client;
}
public function get_credentials() {
return $this->credentials;
}
public function is_connected() {
return $this->is_connected;
}
public function get_unauthenticated_data() {
$authUrl = $this->client->createAuthUrl();
return "<a href='$authUrl'>Click here to link your account</a>";
}
public function credentials_in_browser() {
if ($_GET['code']) {
return true;
}
return false;
}
public function create_client() {
$client = new Google_Client();
$client->setApplicationName('Gmail API PHP');
$client->addScope('https://mail.google.com/');
$client->setAuthConfig('credentials.json');
$client->setAccessType('offline');
$client->setPrompt('select_account consent');
$tokenPath = 'token.json';
if (file_exists($tokenPath)) {
$accessToken = json_decode(file_get_contents($tokenPath), true);
$client->setAccessToken($accessToken);
}
if ($client->isAccessTokenExpired()) {
if ($client->getRefreshToken()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
} elseif($this->credentials_in_browser()) {
$authCode = $_GET['code'];
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
$client->setAccessToken($accessToken);
if (array_key_exists('error', $accessToken)) {
throw new Exception(join(', ', $accessToken));
}
} else {
$this->is_connected = false;
return $client;
}
if (!file_exists(dirname($tokenPath))) {
mkdir(dirname($tokenPath), 0700, true);
}
file_put_contents($tokenPath, json_encode($client->getAccessToken()));
}
else {}
$this->is_connected = true;
return $client;
}
}
?>
Welcome to the world of Oauth2.
Access tokens by standard expire after one hour. This is configured by the authorization server that created it. So if you own the authorization server that created it you would have access to change the expiration time.
Google Access tokens are created by Googles authorization server, Googles access tokens expire after one hour. You do not have access to change this.
That being said.
Your code appears to be using offline access and using the refresh token to request a new access token.
if ($client->getRefreshToken()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
Refresh tokens are long lived as long as your application is in set to production your refresh token should not expire. Your code will then request a new access token when ever it needs one.
So technically you dont need to set the access token to 200 days, your refresh token should already be longer then that.
Note with the gmail api refresh tokens will expire if the user changes their password.
I have a token.json file from oauth authentication to access gmail api,
{
"access_token":"token",
"expires_in":3599,
"refresh_token":"token",
"scope":"https:\/\/mail.google.com\/ https:\/\/www.googleapis.com\/auth\/gmail.compose",
"token_type":"Bearer",
"created":1615956208
}
Below I have include my code
Class Connection extends CI_Controller {
public function __construct() {
// echo .'contruct';
// die;
// parent::__construct();
$this->credentials = "assets/gmail_api/credentials/credentials.json";
$this->client = $this->create_client();
}
public function get_client() {
return $this->client;
}
public function get_credentials() {
return $this->credentials;
}
public function is_connected() {
return $this->is_connected;
}
public function get_unauthenticated_data() {
$authUrl = $this->client->createAuthUrl();
return "<a href='".$authUrl."'>Click to Link Your Gmail</a>";
}
public function credentials_in_browser() {
if (isset($_GET['code'])) {
return true;
}
return false;
}
public function create_client() {
$client = new Google_Client();
$client->setApplicationName('Gmail API PHP Quickstart');
$client->setScopes(array(
'https://mail.google.com/',
'https://www.googleapis.com/auth/gmail.compose'
));
$client->setAuthConfig($this->credentials);
$client->setAccessType('offline');
$client->setPrompt('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 = 'assets/gmail_api/'.$_SESSION['mail_box_email'].'/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());
}
elseif ($this->credentials_in_browser()) {
$authCode = $_GET['code'];
// 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));
}
}
else {
$this->is_connected = false;
return $client;
}
// Save the token to a file.
if (!file_exists(dirname($tokenPath))) {
mkdir(dirname($tokenPath), 0700, true);
}
file_put_contents($tokenPath, json_encode($client->getAccessToken()));
}
else {
$this->is_connected = true;
return $client;
}
$this->is_connected = true;
return $client;
}
}
Here i have refresh token to,
I have search about oauth access token, it always expires in 1 hour, but i want to extend this time as much long is possible, so i use refresh token, here my token.json file has refresh token, but still it's expire in one hour, i have read google oauth documentation, they said refresh token maximum life time is 200 days ( https://cloud.google.com/apigee/docs/api-platform/antipatterns/oauth-long-expiration ),
How can i increase the life time of access token, really i can't understand how it's work, please give some solution about extend the access token life time
Thank you.
Access tokens expire after an hour this is standard in all authorization servers. This is not something you can change.
What you should do is use the refresh tokens to request a new access token whenever you need one. Refresh tokens for the most part do not expire, however there are some tricks with gmail api scopes, if the user changes their password it will expire.
https://accounts.google.com/o/oauth2/token
client_id={ClientId}&client_secret={ClientSecret}&refresh_token={refreshtoken}&grant_type=refresh_token
You shouldn't need to deal with any of this if you are using the php client library all of this should be handled for you.
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 get a Google access token for a service account so I can access the Analytics API from the client side.
On the server side I have the following code:
$keyFile = base_path() . '/keys/xxxxxxxx-xxxxxxxxx.json';
$client = new Google_Client();
$client->setApplicationName('Analytics Demo');
$client->setAuthConfig($keyFile);
$client->setScopes(['https://www.googleapis.com/auth/analytics.readonly']);
$token = $client->getAccessToken(); // Returns null
At some point it returned a token, but after a couple of calls it started returning null.
Trying to get the $client->getRefreshToken() also returns null.
When I put $client in a Google_Service_Analytics object everything seems to work just fine, so I know the key file is correct and properly read:
$analytics = new Google_Service_Analytics($client);
$accounts = $analytics->management_accounts->listManagementAccounts(); // Returns proper data
Any ideas on what might be going wrong?
UPDATE:
Calling $client->isAccessTokenExpired() results in true so I guess I have to refresh the token, but I have no clue how.
After a lot of trial and error I found that I had to use $client->fetchAccessTokenWithAssertion() instead of $client->getAccessToken().
public static function getGoogleServiceToken():?string {
$keyFile = base_path() . '/keys/xxxxxxxx-xxxxxxx.json';
$client = new Google_Client();
$client->setAuthConfig($keyFile);
$client->setApplicationName('Analytics Demo');
$client->setAccessType('access_type');
$client->setScopes(['https://www.googleapis.com/auth/analytics.readonly']);
if ($client->isAccessTokenExpired()) {
$token = $client->fetchAccessTokenWithAssertion();
}
else {
$token = $client->getAccessToken();
}
return $token['access_token'];
}
Client side:
...
private _handleGetResponse(response) {
...
gapi.analytics.auth.authorize({
serverAuth: {
access_token: response.token,
}
});
...
Not sure why there is no decent documentation on this at all. Even knowing that I have to use this method I can't find documentation on what this method is actually doing. Any explanation or links to some documentation are still welcome!
Currently, I have this code.
/**
* Refresh a token.
*
* #param $token
* #return \Illuminate\Http\JsonResponse
*/
public function token($token)
{
if(!$token)
{
throw new BadRequestHttpException('Geen token aangeleverd');
}
try {
$newToken = \JWTAuth::refresh($token);
} catch(TokenInvalidException $e) {
throw new AccessDeniedHttpException('Incorrect token');
}
return \Response::json(compact('newToken'));
}
When I send a valid token to this method, I receive an extremely long token back from the JWTAuth::refresh call.
It looks like the new token is appended to my existing token.
I'm not too sure what I am doing wrong, so please fire at will. ;)
We have next method for refresh token. Let JWTAuth itself find token.
public function tokenRefresh(Request $request)
{
try {
$newToken = JWTAuth::setRequest($request)->parseToken()->refresh();
} catch (TokenExpiredException $e) {
event("jwt.expired", [$e], true);
} catch (JWTException $e) {
event("jwt.invalid", [$e], true);
}
/** Our Response wrapper :) */
return ApiResponse::success([
'token' => $newToken,
]);
}
I'm using codeigniter 3.x and php 5.5+. I've been trying to get this to work with no luck. I want to call methods inside a youtube controller class I created that will do different things based on communicating with the google or youtube. The problem is with the Google_Client I believe or it's with how to store $client variable maybe so you can use it in second function. When I try calling this from another function it gives a not login required error even thought the user already did the google verification. How can I tell my second function that the user has already done the authorization and got the token. Everything seems to work very well when both functions are in the same function(I mean just using one function). Also I don't want to verify user on every function or method I execute.
So after first function is done, I get redirected with an access token in the url to the second function but then I get an error Message: Error calling GET https://www.googleapis.com/youtube/analytics/v1/reports?ids=channel%3D%3DMINE&start-date=2014-01-01&end-date=2016-01-20&metrics=views&filters=video%3D%3DpC900o6JaMc: (401) Login Required
First function in the controller Youtubeverify:
class Youtubeverify extends CI_Controller{
public function youtube_consent(){
$this->load->library('google');
$OAUTH2_CLIENT_ID = 'MY_ID';
$OAUTH2_CLIENT_SECRET = 'MY_KEY';
$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->setScopes(array('https://www.googleapis.com/auth/yt-analytics-monetary.readonly','https://www.googleapis.com/auth/youtube.readonly'));
$redirect = filter_var('http://' . $_SERVER['HTTP_HOST'] . "/ci/youtubeverify/display_report",
FILTER_SANITIZE_URL);
$client->setRedirectUri($redirect);
$youtubeReporting = new Google_Service_YouTubeReporting($client);
if (isset($_REQUEST['logout'])) {
$this->session->unset_userdata('youtube_token');
}
if (isset($_GET['code'])) {
if (strval($_SESSION['state']) !== strval($_GET['state'])) {
die('The session state did not match.');
}
$client->authenticate($_GET['code']);
$youtube_token = $client->getAccessToken();
//trying to store the access token in a session
$newdata = array('youtube_token'=>$youtube_token);
$this->session->set_userdata($newdata);
header('Location: ' . $redirect);
}
if ($this->session->userdata('youtube_token')) {
$client->setAccessToken($this->session->userdata('youtube_token'));
}
if ($client->getAccessToken()) {
$client->getAccessToken();
}
else {
// If the user hasn't authorized the app, initiate the OAuth flow
$state = mt_rand();
$client->setState($state);
$_SESSION['state'] = $state;
$authUrl = $client->createAuthUrl();
redirect($authUrl);
}
}
Second function in the controller Youtubeverify:
public function display_report(){
$this->load->library('google');
$client = new Google_Client();
$client->getAccessToken();
$youtubeAnalytics = new Google_Service_YouTubeAnalytics($client);
$id = 'channel==MINE';
$start_date = '2014-01-01';
$end_date = '2016-01-20';
$optparams = array('filters' => 'video==*********');
$metrics = array('views');
$api_response = $metrics;
$api = $youtubeAnalytics->reports->query($id, $start_date, $end_date, $metric,$optparams);
$data['api_response'] = $api_response['views'];
$this->load->view('layouts/mainlay',$data);
}
I have never worked with YouTube API before, but here's a step in the right direction.
class Youtubeverify extends CI_Controller {
// Google API Keys
const CLIENT_ID = '';
const CLIENT_SECRET = '';
// We'll store the client in a class property so we can access it between methods.
protected $Client;
public function __construct () {
parent::__construct();
// setup google client.
$this->Client = new Google_Client();
$this->Client->setClientId(self::CLIENT_ID);
$this->Client->setClientSecret(self::CLIENT_SECRET);
// we call the authenication method for each request
$this->_authenticate_client();
}
// Authentication method
protected function _authenticate_client () {
//if we already have a token then we just set it in the client
//without going through authentication process again
if( $accessToken = $this->session->userdata('youtube_token') ) {
$this->Client->setAccessToken($accessToken);
}else{
// preform authentication as usual with a redirect ...etc
}
}
}