Google-api-python-client: Not getting refresh token even though access_type is offline in step1

Created on 5 Apr 2016  路  20Comments  路  Source: googleapis/google-api-python-client

Hi,

I'm doing some work with Google Search Console API. Before I start using the API, I need to get oauth credentials of the client: authorize my app to get access tokens to call the Search Console API on his behalf and do modifications to his Search Console data.

I'm doing the needed step1 and step2 flow exchange calls, but still I'm not getting any refresh token whatsoever, even though access_type is set to offline in the authorize url generated in step1.

Am I missing something?

Here's my code:

authorize_url = flow.step1_get_authorize_url()

And the url is like:

https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/webmasters&redirect_uri=http://mywebsite.com/google/scapi/callback/&response_type=code&client_id=redacted_client_id&access_type=offline

And then in my callback handler:

credentials = flow.step2_exchange(code)

Here's the json I'm getting from the Credentials object:

{
  "_module": "oauth2client.client",
  "token_expiry": "2016-04-05T12:46:24Z",
  "access_token": "ya29.. -- redacted --",
  "token_uri": "https://accounts.google.com/o/oauth2/token",
  "invalid": false,
  "token_response": {
    "access_token": "ya29.. -- redacted --",
    "token_type": "Bearer",
    "expires_in": 3419
  },
  "client_id": " -- redacted --",
  "id_token": null,
  "client_secret": " -- redacted --",
  "revoke_uri": "https://accounts.google.com/o/oauth2/revoke",
  "_class": "OAuth2Credentials",
  "refresh_token": null,
  "user_agent": null
}
triage me

Most helpful comment

This can happen if you've already authorized the app once before. The oauth2 server will only ever mint one refresh token at a time, and if you request another access token via the flow it will operate as if you only asked for an access token.

You can try constructing the flow object with prompt='consent' and see if that fixes it.

Related: google/oauth2client#453

All 20 comments

This can happen if you've already authorized the app once before. The oauth2 server will only ever mint one refresh token at a time, and if you request another access token via the flow it will operate as if you only asked for an access token.

You can try constructing the flow object with prompt='consent' and see if that fixes it.

Related: google/oauth2client#453

Had the exact same problem, and using prompt='consent' worked for me.
Bad surprise though :(

This is ridiculous. Why is this only documented in a blog post? Am I missing something?

This is documented here for now: https://developers.google.com/identity/protocols/OpenIDConnect#prompt

We are actively working to improve our auth docs, we are aware that it's difficult to find documentation about both the high-level libraries and the low-level protocol. Stay tuned.

@jonparrott I would not say that documents this issue: it makes no reference whatsoever to refresh tokens. The access_type description says offline must be specified to get a refresh token, but no mention of prompt there. The Refresh Tokens section says "Be sure to store the refresh token safely and permanently, because you can only obtain a refresh token the first time that you perform the code exchange flow." That kind of sort of describes the situation here, but "the first time" is vague, and makes no mention of the prompt=consent workaround. Anyway, good luck.

Discovering this was painful.

@jonparrott does forcing a new login/consent by the user invalidate prior refresh tokens for that user even if the prior refresh token was not used?

In addition are there any plans to either move away from the access_type=offline parameter or add as an alternative the mechanism specified in the OpenID specification, which is adding the scope offline_access to the authorization request? access_type is not part of the OAuth or OpenID specifications as far as I know.

http://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess

does forcing a new login/consent by the user invalidate prior refresh tokens for that user even if the prior refresh token was not used?

Not sure, but I think not. I think the refresh token is only invalidated if the user revokes access through accounts.google.com

In addition are there any plans to either move away from the access_type=offline parameter or add as an alternative the mechanism specified in the OpenID specification, which is adding the scope offline_access to the authorization request? access_type is not part of the OAuth or OpenID specifications as far as I know.

Not that I'm aware of.

does forcing a new login/consent by the user invalidate prior refresh tokens for that user even if the prior refresh token was not used?

I just tested with an old and new token/refresh_token combination and the old pair continues to be valid when refreshing.

Stumbled upon this while looking for solutions but if you use a Google privileged scope the refresh tokens do expire at some point without you knowing, so you will need to regain consent every 2(?) months I believe.

Apologies for bumping this topic but might be useful for anyone who finds this issue.

To add on this earlier comment, how come Google still got the "OpenID certified" badge (on the upper-right of this page), while its OpenID implementation does not support offline_access scope? :confused:

I'm passing access_type=offline&prompt=consent and I still can't get a new refresh token. This really kind of stinks if you have a crazy bug/issue where refresh token was lost and end users can't even reconnect to fix it.

@niemyjski Users have to deauthorize your application from their security dashboard and you'll get a new refresh token the next time they authorize.

In new api you must use:

setApprovalPrompt("force")

const authUrl = oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES,
prompt: 'consent', // this fixed
});

If someone happens to come across this and is using the PHP client, then I fixed this issue by setting the prompt to force:

$client->setApprovalPrompt('force');

For some reason when the option is left at it's default (auto) the refresh token is not returned, but when set to force, it is.

If someone happens to come across this and is using the PHP client, then I fixed this issue by setting the prompt to force:

$client->setApprovalPrompt('force');

For some reason when the option is left at it's default (auto) the refresh token is not returned, but when set to force, it is.

Ah, good to know. I've used the options to configure it by now.

Bump on this issue thread 鈥撀營 just had to deal with this painful issue. It would be great if @google-admin could add this to their documentation!

November 2020, and I bumped into this documentation while trying to get a missing refresh_token. Thankful I found it, as it was what I needed, but I question why it's not in the main documentation anywhere

Setting prompt=consent along with deauthorizing the app from user's security dashboard as @Sieabah mentioned was the complete solution for me to get refresh token.

Was this page helpful?
0 / 5 - 0 ratings