Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google api refresh_token null and how to refresh access token

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 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;
  }
 }

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 from google get refreshToken = null or need set null with key refresh token or this dosn't metter ?

    $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"); //some  recomendation
    $client->getGoogleClient()->setApprovalPrompt ("force"); //some recomendation

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

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.

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

I try

  • 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.apps.googleusercontent.com
            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

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']);
    $client -> setAccessType ($config['access_type']);
    $client -> setApprovalPrompt ($config['approval_prompt']);

    $this -> client = $client;
}

config this is:

    happy_r_google_api:
    application_name: carbon-quanta-137312
    oauth2_client_id: xxxx.apps.googleusercontent.com
    oauth2_client_secret: xxx
    oauth2_redirect_uri: null
    developer_key: null
    site_name: aog.local.com
    access_type: offline
    approval_prompt: force

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

like image 873
shuba.ivan Avatar asked Jul 19 '16 19:07

shuba.ivan


3 Answers

The refresh_token is only returned on the first request. When you refresh the access token a second time it returns everything except the refresh_token and the file_put_contents removes the refresh_token when this happens the second time.

Modifying the code as following will merge in the original access token with the new one (see: array_merge). This way you will be able to preserve your refresh_token for future requests. I have submitted the following fix to Google, hope they update it at some point.

See docs for more info

    // Refresh the token if it's expired.
    if ($client->isAccessTokenExpired()) {
        $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
        $newAccessToken = $client->getAccessToken();
        $accessToken = array_merge($accessToken, $newAccessToken);
        file_put_contents($credentialsPath, json_encode($accessToken));
    }
like image 83
Arithran Avatar answered Oct 13 '22 20:10

Arithran


Half of the answer has already been answered by Arithran.

The expire token is sent only the first time you authorize your account. After that you won't receive it anymore, and that's why you need to save it since the beginning and then on every refresh, merge the old and new arrays.

The other half of the answer is how to delete and receive again that token, otherwise you would need to test everytime with a new google account.

  1. Go to your account security settings: https://www.google.com/settings/u/1/security.
  2. Scroll to section "Authorizing applications and sites" then click on View All.
  3. Then "Revoke Access" to your app.
  4. Make a new OAuth2 request. This will return a refresh_token.

Remember to add access_type=offline to your request

like image 33
Abraham Romero Avatar answered Oct 13 '22 21:10

Abraham Romero


In the OAuth 2.0 protocol, your app requests authorization to access resources which are identified by scopes, and assuming the user is authenticated and approves, your app receives short-lived access tokens which let it access those resources, and (optionally) refresh tokens to allow long-term access.

The idea of refresh tokens is that if an access token is compromised, because it is short-lived, the attacker has a limited window in which to abuse it.

Refresh tokens, if compromised, are useless because the attacker requires the client id and secret in addition to the refresh token in order to gain an access token.

Reason why token might stop working:

  • The user has revoked access.
  • The token has not been used for six months.
  • The user changed passwords and the token contains Gmail, Calendar, Contacts, or Hangouts scopes.
  • The user account has exceeded a certain number of token requests.

There is currently a limit of 25 refresh tokens per user account per client. If the limit is reached, creating a new token automatically invalidates the oldest token without warning. This limit does not apply to service accounts.

Here's a related SO ticket discuss why getting NULL token: Getting null Refresh token

like image 41
Android Enthusiast Avatar answered Oct 13 '22 21:10

Android Enthusiast