我想从谷歌获取访问令牌。谷歌API说,要获得访问令牌,将代码和其他参数发送到令牌生成页面,响应将是一个JSON对象,如:

{
"access_token" : "ya29.AHES6ZTtm7SuokEB-RGtbBty9IIlNiP9-eNMMQKtXdMP3sfjL1Fc",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "1/HKSmLFXzqP0leUihZp2xUt3-5wkU7Gmu2Os_eBnzw74"
}

但是,我没有收到刷新令牌。我的回答是:

{
 "access_token" : "ya29.sddsdsdsdsds_h9v_nF0IR7XcwDK8XFB2EbvtxmgvB-4oZ8oU",
"token_type" : "Bearer",
"expires_in" : 3600
}

当前回答

为了获得刷新令牌,你必须同时添加approval_prompt=force和access_type="offline" 如果您正在使用谷歌提供的java客户端,它将看起来像这样:

GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
            HTTP_TRANSPORT, JSON_FACTORY, getClientSecrets(), scopes)
            .build();

AuthorizationCodeRequestUrl authorizationUrl =
            flow.newAuthorizationUrl().setRedirectUri(callBackUrl)
                    .setApprovalPrompt("force")
                    .setAccessType("offline");

其他回答

设置这个将导致刷新令牌每次都被发送:

$client->setApprovalPrompt('force');

下面给出一个例子(php):

$client = new Google_Client();
$client->setClientId($client_id);
$client->setClientSecret($client_secret);
$client->setRedirectUri($redirect_uri);
$client->addScope("email");
$client->addScope("profile"); 
$client->setAccessType('offline');
$client->setApprovalPrompt('force');

我想为那些遇到这个问题的沮丧灵魂补充一点关于这个主题的信息。获得离线应用程序刷新令牌的关键是确保呈现同意屏幕。refresh_token仅在用户通过单击“允许”授予授权后立即返回。

在我在开发环境中进行了一些测试之后,我(我怀疑还有许多其他人)就遇到了这个问题,因此我已经在一个给定的帐户上授权了我的应用程序。然后,我转移到生产环境,尝试使用一个已经获得授权的帐户再次进行身份验证。在这种情况下,同意屏幕不会再次出现,api也不会返回新的刷新令牌。要实现此功能,您必须通过以下方式强制再次出现同意屏幕:

prompt=consent

or

approval_prompt=force

任何一个都可以,但你不应该同时使用。截至2021年,我建议使用prompt=consent,因为它取代了旧的参数approval_prompt,在一些api版本中,后者实际上已经被破坏了(https://github.com/googleapis/oauth2client/issues/453)。此外,prompt是一个以空格分隔的列表,因此如果您想要两者都使用,可以将其设置为prompt=select_account%20consent。

当然你还需要:

access_type=offline

更多阅读:

文档:https://developers.google.com/identity/protocols/oauth2/web-server # request-parameter-prompt 文档:https://developers.google.com/identity/protocols/oauth2/openid-connect # re-consent 关于此问题的讨论:https://github.com/googleapis/google-api-python-client/issues/213

For me I was trying out CalendarSampleServlet provided by Google. After 1 hour the access_key times out and there is a redirect to a 401 page. I tried all the above options but they didn't work. Finally upon checking the source code for 'AbstractAuthorizationCodeServlet', I could see that redirection would be disabled if credentials are present, but ideally it should have checked for refresh token!=null. I added below code to CalendarSampleServlet and it worked after that. Great relief after so many hours of frustration . Thank God.

if (credential.getRefreshToken() == null) {
    AuthorizationCodeRequestUrl authorizationUrl = authFlow.newAuthorizationUrl();
    authorizationUrl.setRedirectUri(getRedirectUri(req));
    onAuthorization(req, resp, authorizationUrl);
    credential = null;
}

My solution was a bit weird..i tried every solution i found on internet and nothing. Surprisely this worked: delete the credentials.json, refresh, vinculate your app in your account again. The new credentials.json file will have the refresh token. Backup this file somewhere. Then keep using your app until the refresh token error comes again. Delete the crendetials.json file that now is only with an error message (this hapenned in my case), then paste you old credentials file in the folder, its done! Its been 1 week since ive done this and had no more problems.

refresh_token仅在用户第一次授权时提供。后续的授权,比如您在测试OAuth2集成时所做的授权,将不会再次返回refresh_token。:)

进入可以访问您帐户的应用程序页面: https://myaccount.google.com/u/0/permissions。 在第三方应用程序菜单下,选择您的应用程序。 单击“删除访问”,然后单击“确定”确认 下一个OAuth2请求将返回一个refresh_token(前提是它还包括'access_type=offline'查询参数)。

或者,您可以将查询参数prompt=consent&access_type=offline添加到OAuth重定向(参见谷歌的OAuth 2.0 for Web服务器应用程序页面)。

这将提示用户再次授权应用程序,并总是返回一个refresh_token。