97

I can't get my refresh token with my code. I can only get my access token, token type etc., I have followed some tutorials like putting access_type=offline on my login URL:

echo "<a href='https://accounts.google.com/o/oauth2/auth?" 
    . "access_type=offline&client_id=123345555.apps.googleusercontent.com& "
    . "scope=https://www.googleapis.com/auth/calendar+https://www.googleapis.com/auth/plus.me&response_type=code& "
    . "redirect_uri=http://www.sample.com/sample.php&state=/profile'>Google</a>";

and my fields in getting the access token:

$fields=array(
    'code'=>  urlencode($authcode),
    'client_id'=> urlencode($clientid),
    'client_secret'=> urlencode($clientsecret),
    'redirect_uri'=> urlencode($redirecturi),
    'grant_type'=> 'authorization_code',
);

but I can't get refresh_token, just the access_token, token_type, id_token and expires_in.

Ivan Aracki
  • 4,861
  • 11
  • 59
  • 73
Robin Carlo Catacutan
  • 13,249
  • 11
  • 52
  • 85
  • 1
    /*check this link that work for me @Nobert solution */ https://stackoverflow.com/questions/10827920/not-receiving-google-oauth-refresh-token – Manmeet Khurana Dec 12 '17 at 13:09

9 Answers9

130

Found out by adding this to your url parameters

approval_prompt=force

Update:

Use access_type=offline&prompt=consent instead.

approval_prompt=force no longer works https://github.com/googleapis/oauth2client/issues/453

Robin Carlo Catacutan
  • 13,249
  • 11
  • 52
  • 85
  • 13
    Why doesnt it work with Auto ? i dont want users to every time grant permission. How can i over come this ? – Harsha M V Jun 23 '12 at 13:09
  • 6
    Because the reresh token is only returned the first time on granting the application permission. After that all requests with `approval_prompt=auto` don't have a refresh_token anymore. Check this answer for more detailed explanation http://stackoverflow.com/a/10857806/987864 – Daan Apr 20 '15 at 10:17
  • 4
    You need `access_type=offline` in all cases when you want the refresh_token – Daan Apr 20 '15 at 10:33
  • 7
    Edited answer to something that is working as this answer is old and no longer seems to work. I spent significant time trying this as there are multiple places saying to use this method. I finally read the documentation (which I should have done first) and it says you must use ```prompt=consent```. Reference: https://developers.google.com/identity/protocols/OAuth2WebServer#offline – Goblinlord Jan 05 '16 at 00:49
  • 9
    Both @Daan and @Goblinlord are correct, I struggled with this even after reading their comments. In fact we need BOTH, `access_type=offline&prompt=consent`. Otherwise the `refresh_token` will not be present. – Noitidart Aug 13 '16 at 06:31
  • 2
    This helped me. If you're using the PHP api client, `$this->client->setApprovalPrompt('force');` works too. – anastymous Sep 13 '16 at 11:00
  • 1
    This answer is outdated. See https://stackoverflow.com/a/45740113 for the valid answer. – xurei Oct 24 '19 at 14:43
67

If I may expand on user987361's answer:

From the offline access portion of the OAuth2.0 docs:

When your application receives a refresh token, it is important to store that refresh token for future use. If your application loses the refresh token, it will have to re-prompt the user for consent before obtaining another refresh token. If you need to re-prompt the user for consent, include the approval_prompt parameter in the authorization code request, and set the value to force.

So, when you have already granted access, subsequent requests for a grant_type of authorization_code will not return the refresh_token, even if access_type was set to offline in the query string of the consent page.

As stated in the quote above, in order to obtain a new refresh_token after already receiving one, you will need to send your user back through the prompt, which you can do by setting approval_prompt to force.

Cheers,

PS This change was announced in a blog post as well.

Community
  • 1
  • 1
bossylobster
  • 9,993
  • 1
  • 42
  • 61
  • 4
    I would add that you would only need to get a **new** `refresh token` if you lose it or your user revokes your access. Otherwise you can keep using the same `refresh token` to obtain new `access token`s. – jeteon May 15 '15 at 13:19
  • 1
    I have a CMS where different users use different google accounts to connect to the analytics api. However, sometimes several users can connect using the same corporate google account, but each wanting access to a different Analytics accounts. Only the first one receives the refresh token, while all others don't and thus have to reconnect every hour. Isn't there a way to get the SAME refresh token for subsequent authentications instead of just the access_token which expires within the hour? – Costin_T Jun 11 '15 at 14:36
  • Yes. Just do it. When you send the request you'll get back an access token and the refresh token. – bossylobster Jun 12 '15 at 16:28
  • 1
    I was strugling to get a refresh_token and you enlighted me with the solution !!! "So, when you have already granted access, subsequent requests for a grant_type of authorization_code will not return the refresh_token, even if access_type was set to offline in the query string of the consent page." – Cristiana SP Apr 28 '20 at 21:15
12

It is access_type=offline that you want.

This will return the refresh token the first time the user authorises the app. Subsequent calls do not force you to re-approve the app (approval_prompt=force).

See further detail: https://developers.google.com/accounts/docs/OAuth2WebServer#offline

Elliot Coad
  • 1,038
  • 2
  • 11
  • 16
  • 1
    That page linked states that the Google client will take care of renewing the access token when it expires (the renewal token is presumably in the secrets XML file), but does not show how you would detect that the access token has changed so that it can be saved in the application for the next access. Is there a callback for this, or a should application always check if the access token has changed on the *every* remote access it performs? – Jason Jun 06 '17 at 11:53
12

This is complete code in PHP using google official SDK

$client = new Google_Client();
## some need parameter
$client->setApplicationName('your application name');
$client->setClientId('****************');
$client->setClientSecret('************');
$client->setRedirectUri('http://your.website.tld/complete/url2redirect');
$client->setScopes('https://www.googleapis.com/auth/userinfo.email');
## these two lines is important to get refresh token from google api
$client->setAccessType('offline');
$client->setApprovalPrompt('force'); # this line is important when you revoke permission from your app, it will prompt google approval dialogue box forcefully to user to grant offline access
Mr_Green
  • 40,727
  • 45
  • 159
  • 271
  • 1
    this is the correct answer as of 13 Oct 2022. need both 'offline' and 'force', using 'consent' does not work. – PK. Oct 13 '22 at 02:02
11

For our app we had to use both these parameters access_type=offline&prompt=consent. approval_prompt=force did not work for us

Ricky Sahu
  • 23,455
  • 4
  • 42
  • 32
  • 2
    Thanks Ricky, this is what worked me as well. I think the older answers, suggesting `approval_prompt=force`, were probably correct at the time, but no longer work. There is some discussion here: https://github.com/google/oauth2client/issues/453 – Mike Morearty Jul 15 '18 at 22:54
  • 1
    "approval_prompt=force" worked for me – Shawinder Jit Singh Oct 01 '21 at 05:02
8

Hi I followed following steps and I had been able to get the refresh token.

Authorization flow has two steps.

  1. Is to obtain the authorization code using https://accounts.google.com/o/oauth2/auth? URL.

    For that a post request is sent providing following parameters. 'scope=' + SCOPE + '&client_id=' + CLIENTID + '&redirect_uri=' + REDIRECT + '&response_type=' + TYPE + '&access_type=offline' Providing above will receive a authorization code.

  2. Retrieving AcessToken and RefreshToken using https://accounts.google.com/o/oauth2/token? URL. For that a post request is sent providing following parameters.

    "code" : code, "client_id" : CID, "client_secret" : CSECRET, "redirect_uri" : REDIRECT, "grant_type" : "authorization_code",

So in your first attempt once you authorize the permissions you will be able to get the Refresh token. Subsequent attempts will not provide the refresh token. If you want the token again the revoke the access in you application.

Hope this will help someone cheers :)

dnWick
  • 393
  • 3
  • 14
6

OAuth has two scenarios in real mode. The normal and default style of access is called online. In some cases, your application may need to access a Google API when the user is not present,It's offline scenarios . a refresh token is obtained in offline scenarios during the first authorization code exchange.

So you can get refersh_token is some scenarios ,not all.

you can have the content in https://developers.google.com/identity/protocols/OAuth2WebServer#offline .

Julian89757
  • 160
  • 1
  • 4
2

Since March 2016, use prompt=consent to regenerate Google API refresh token.

As mentioned in https://github.com/googleapis/oauth2client/issues/453,

approval_prompt=force has been replaced with prompt=none|consent|select_account

Finwe
  • 6,372
  • 2
  • 29
  • 44
1

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.

Jay
  • 566
  • 6
  • 18