Google api refresh_token null and how to refresh access token

12,564

Solution 1

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

Solution 2

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

Solution 3

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

Solution 4

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
Share:
12,564
shuba.ivan
Author by

shuba.ivan

Updated on June 12, 2022

Comments

  • shuba.ivan
    shuba.ivan almost 2 years

    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 ?

  • shuba.ivan
    shuba.ivan over 7 years
    I update my question, in my scope three parameters and I have in constructor wrapper access_type: offline approval_prompt: force and still have expired refresh token, how to update or maybe problem in HWIO bundle I get access token from HWIO. Beacause I have another proplem with this lib I upload file in google drive but have emty file and have function create but now lost after rebuild project and composer install. I think something wrong (
  • KumailR
    KumailR over 4 years
    How to make that request using client side SDK JS??