Google-api-php-client: Google api refresh_token null and how to refresh access token

Created on 20 Jul 2016  路  16Comments  路  Source: googleapis/google-api-php-client

I use HWIO Bundle for google api and when I have response from google refreshToken = null why? How to refresh token

oAuthToken = {HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken} [11]
accessToken = "ya29.Ci8lA1JTu9CB81dOFy-nzszViRgCI2CvvKVrCd0Lq-8I0QR_dIrl-_7RccdGt1Islg"
rawToken = {array} [4]
 access_token = "ya29.Ci8lA1JTu9CB81dOFy-nzszViRgCI2CvvKVrCd0Lq-8I0QR_dIrl-_7RccdGt1Islg"
 token_type = "Bearer"
 expires_in = 3578
id_token = "xxxxx"
refreshToken = null
expiresIn = 3578
createdAt = 1468957368
tokenSecret = null
resourceOwnerName = null

because in "name": "google/apiclient", "version": "1.1.7" in function need refresh_token

 public function getRefreshToken()
 {
  if (array_key_exists('refresh_token', $this->token)) {
    return $this->token['refresh_token'];
  } else {
    return null;
  }
 }

how to refresh token and how to with token get refresh token, for refresh token ?

I try

Go to your account security settings: https://www.google.com/settings/u/1/security.
Click the edit button next to "Authorizing applications and sites".
and not find how to enable refresh token

Most helpful comment

Try

$client->setAccessType ("offline");
$client->setApprovalPrompt ("force");

All 16 comments

Try

$client->setAccessType ("offline");
$client->setApprovalPrompt ("force");

this my access token

{"access_token":"ya29.Ci8lA1JTu9CB81dOFy-nzszViRgCI2CvvKVrCd0Lq-8I0QR_dIrl-_7RccdGt1Islg","token_type":"Bearer","expires_in":3578,"id_token":"xxxx","created":1468957368}

not have refresh token because grom google get refreshToken = null ot need set null with key refresh token or this dosn't metter ?

 `$client = $this->get('artel.google.api.client');

    /** @var CodeUserReference[] $accessToken */
    $accessToken = $this->get('doctrine.orm.entity_manager')->getRepository('ArtelProfileBundle:CodeUserReference')
        ->getReferenceAccessClient($user);
    if ($accessToken) {
        $client->setAccessToken($accessToken[0]->getAccessTokenClient());
    } else {
        $view = $this->view(['No accessToken was found for this user id'], 400);
        return $this->handleView($view);
    }

    $isExpired = $client->isAccessTokenExpired(); // true (bool Returns True if the access_token is expired.)
    $refresh = $client->getRefreshToken(); //null because not gahe refresh token 

    $client->getGoogleClient()->setAccessType ("offline"); //your recomendation
    $client->getGoogleClient()->setApprovalPrompt ("force"); //your recomendation

    $isAgainExpired = $client->isAccessTokenExpired(); // still true (expired)

    $service = new \Google_Service_Drive($client->getGoogleClient());
    $file = new \Google_Service_Drive_DriveFile();
    $file->setName($request->request->get('title')
        ? $request->request->get('title')
        : $request->files->get('file')->getClientOriginalName()
    );
    $file->setDescription($request->request->get('description'));
    $file->setMimeType($request->request->get('mimeType')
        ? $request->request->get('mimeType')
        : $request->files->get('file')->getClientMimeType()
    );

    // Set the parent folder.
    if ($request->request->get('parentId') != null) {
        $parent = new Google_Service_Drive_ParentReferen();
        $parent->setId($request->request->get('parentId'));
        $file->setParents(array($parent));
    }

    try {
        $data = $request->files->get('file');

        $createdFile = $service->files->create($file, array(
            'data' => $data,
            'mimeType' => $request->request->get('mimeType')
                ? $request->request->get('mimeType')
                : $request->files->get('file')->getClientMimeType(),
            'uploadType' => 'media'
        ));

        // Uncomment the following line to print the File ID
        // print 'File ID: %s' % $createdFile->getId();
        return View::create()
            ->setStatusCode(200)
            ->setData([$createdFile]);

    } catch (\Exception $e) {
        $view = $this->view((array) $e->getMessage(), 400);
        return $this->handleView($view);
    }`

still have exception - The OAuth 2.0 access token has expired, and a refresh token is not available. Refresh tokens are not returned for responses that were auto-approved.

In my code I assumed $client = new Google_Client();. Also, I am not familiar with the way you request the access token.

For you to get the refresh token, you need to specify access_type and approval_prompt in the same place where you specify scope and redirect_uri.

  • In my code too $client = new Google_Client() but in wrapper, in constructor.
  • I get access token from HWIO bundle:

hwi_oauth: connect: account_connector: app.provider.user_provider firewall_name: secured_area resource_owners: google: type: google client_id: xxx client_secret: xxx scope: "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/drive"

and after I get access token I set it in DB. Then in Action I create wrapper for google api (new Google Client ()) and set this client my accesss token from DB. How to refresh my access token? I try in action use function google api lib setAccessType and setApprovalPrompt, but not efect

$client->getGoogleClient()->setAccessType ("offline"); //your recomendation
$client->getGoogleClient()->setApprovalPrompt ("force"); //your recomendation

when I create object wrapper I create new Google Client

public function __construct(array $config, LoggerInterface $symfonyLogger = null) { // True if objects should be returned by the service classes. // False if associative arrays should be returned (default behavior). $config['use_objects'] = true; $client = new \Google_Client($config); if ($symfonyLogger) { //BC for Google API 1.0 if (class_exists('\Google_Logger_Psr')) { $googleLogger = new \Google_Logger_Psr($client, $symfonyLogger); $client->setLogger($googleLogger); } else { $client->setLogger($symfonyLogger); } } $client -> setApplicationName($config['application_name']); $client -> setClientId($config['oauth2_client_id']); $client -> setClientSecret($config['oauth2_client_secret']); $client -> setRedirectUri($config['oauth2_redirect_uri']); $client -> setDeveloperKey($config['developer_key']); $this -> client = $client; }

config this is:

   `happy_r_google_api:
    application_name: carbon-quanta-137312
    oauth2_client_id: xxx.apps.googleusercontent.com
    oauth2_client_secret: xxx
    oauth2_redirect_uri: null
    developer_key: null
    site_name: aog.local.com

`

and if in action I set to Google Client some parameters this is same if I add constructorI, so what I'am doing wrong ?

OK.
So from what I understand, you should add to your config :

access_type: offline
approval_prompt: force

And in your else statement

$client->setAccessType ($config['access_type']);
$client->setApprovalPrompt ($config['approval_prompt']);

Yes, I add to wrapper

 $client -> setAccessType ($config['access_type']);
 $client -> setApprovalPrompt ($config['approval_prompt']);

but still have

"The OAuth 2.0 access token has expired, and a refresh token is not available. Refresh tokens are not returned for responses that were auto-approved."

and after rebuild project, I lost function create and now have insert, this is a magic, I dont change version in composer json :)

        $createdFile = $service->files->insert($file, array(
            'data' => $data,
            'mimeType' => $request->request->get('mimeType')
                ? $request->request->get('mimeType')
                : $request->files->get('file')->getClientMimeType(),
            'uploadType' => 'media'
        ));

early I have

        $createdFile = $service->files->create($file, array(
            'data' => $data,
            'mimeType' => $request->request->get('mimeType')
                ? $request->request->get('mimeType')
                : $request->files->get('file')->getClientMimeType(),
            'uploadType' => 'media'
        ));

I assume you go through the whole process and open a window for the user to give permission to use the account?

Because, if not, then this is probably your problem:
Refresh tokens are not returned for responses that were auto-approved.
And you need to go through that process, as far as I understand.

when user connect to github first they have window with scope, where user accept this scope and after I have in response accessToken.

The "auto-approval" happens when a user has already accepted the authorization prompt, and so is not prompted again. A refresh token is not returned in this case. You can read more about this here.

I assume when you generate the auth URL (using $client->createAuthUrl), you are not setting approval_prompt=force. You can check this by inspecting the URL's query parameters directly. Setting $client->setApprovalPrompt() in the code above will have no effect, this only has effect if added before the authorization URL is created.

I understan. I get access token from HWIO bundle and I add in config HWIO bundle access_type: offline, approval_prompt: force and in response I have refresh token not null

    google:
        type:                google
        client_id:           xxx
        client_secret:       xxx
        scope:               "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/drive"
        options:
            access_type:         offline
            approval_prompt:     force

@shubaivan it sounds like you figured it out, but if you continue to have issues, I suggest filing an issue with HWIOBundle.

@bshaffer No, I don't have continue problem, now I have refresh_token in response and this issue closed

require_once 'vendor/autoload.php';

session_start();

/*

  • You can acquire an OAuth 2.0 client ID and client secret from the
  • {{ Google Cloud Console }} <{{ https://cloud.google.com/console }}>
  • For more information about using OAuth 2.0 to access Google APIs, please see:
  • https://developers.google.com/youtube/v3/guides/authentication
  • Please ensure that you have enabled the YouTube Data API for your project.
    */
    $OAUTH2_CLIENT_ID = 'xxxxxxxxxxxxxxxx.apps.googleusercontent.com'; // Enter your Client ID here
    $OAUTH2_CLIENT_SECRET = 'xxxxxxxxxxxxxx'; // Enter your Client Secret here
    $REDIRECT = filter_var('https://developers.google.com/oauthplayground', FILTER_SANITIZE_URL);
    $APPNAME = "xxxxx";

$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->setScopes('https://www.googleapis.com/auth/youtube');
$client->setRedirectUri($REDIRECT);
$client->setApplicationName($APPNAME);
$client->setAccessType('offline');
$client->setApprovalPrompt('force');

// Define an object that will be used to make all API requests.
$youtube = new Google_Service_YouTube($client);

if (isset($_GET['code'])) {
if (strval($_SESSION['state']) !== strval($_GET['state'])) {
die('The session state did not match.');
}

$client->authenticate($_GET['code']);
$_SESSION['token'] = $client->getAccessToken();

}

if (isset($_SESSION['token'])) {
$client->setAccessToken($_SESSION['token']);
echo "Access Token: " . json_encode($_SESSION['token']);
}

// Check to ensure that the access token was successfully acquired.
if ($client->getAccessToken()) {
try {
// Call the channels.list method to retrieve information about the
// currently authenticated user's channel.
$channelsResponse = $youtube->channels->listChannels('contentDetails', array('mine' => 'true'));

    $htmlBody = '';
    foreach ($channelsResponse['items'] as $channel) {
        // Extract the unique playlist ID that identifies the list of videos
        // uploaded to the channel, and then call the playlistItems.list method
        // to retrieve that list.
        $uploadsListId = $channel['contentDetails']['relatedPlaylists']['uploads'];

        $playlistItemsResponse = $youtube->playlistItems->listPlaylistItems('snippet', array(
            'playlistId' => $uploadsListId,
            'maxResults' => 50
        ));

        $htmlBody .= "<h3>Videos in list $uploadsListId</h3><ul>";
        foreach ($playlistItemsResponse['items'] as $playlistItem) {
            $htmlBody .= sprintf('<li>%s (%s)</li>', $playlistItem['snippet']['title'],
                $playlistItem['snippet']['resourceId']['videoId']);
        }
        $htmlBody .= '</ul>';
    }
} catch (Google_ServiceException $e) {
    $htmlBody .= sprintf('<p>A service error occurred: <code>%s</code></p>',
        htmlspecialchars($e->getMessage()));
} catch (Google_Exception $e) {
    $htmlBody .= sprintf('<p>An client error occurred: <code>%s</code></p>',
        htmlspecialchars($e->getMessage()));
}

$_SESSION['token'] = $client->getAccessToken();

} else {
$state = mt_rand();
$client->setState($state);
$_SESSION['state'] = $state;

$authUrl = $client->createAuthUrl();
$htmlBody = <<<END

Authorization Required

You need to authorise access before proceeding.


END;
}
?>




My Uploads




// please help me solve this i am not get token

how to get token, for Authorization: Bearer

One should know, not to share there accessToken or any other token in the details.

Hi, any update about this? I'm facing the same issue.
Or is there a way to Make a New Token without user interactions? I mean User must click the url and get the new code and exchange it with the new token?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

whatido1 picture whatido1  路  3Comments

mevsme picture mevsme  路  4Comments

unixkapl picture unixkapl  路  3Comments

armetiz picture armetiz  路  4Comments

AlexandreGerault picture AlexandreGerault  路  5Comments