获取Google API的刷新令牌

97

我无法使用我的代码获取刷新令牌。 我只能获取访问令牌、令牌类型等信息, 我已经按照一些教程进行了操作,例如在我的登录URL中添加access_type=offline

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

我获取访问令牌时使用的字段:

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

但是我无法获得refresh_token,只有access_tokentoken_typeid_tokenexpires_in


1
/请查看这个链接,这是@Nobert的解决方案,对我有效/ https://dev59.com/4mgv5IYBdhLWcg3wI9Sg - Manmeet Khurana
9个回答

133

13
为什么自动模式不起作用?我不希望用户每次都需要授权。有什么办法可以解决这个问题? - Harsha M V
6
因为刷新令牌只在首次授权应用程序时返回。之后所有带有 approval_prompt=auto 的请求都不再具有刷新令牌。请查看此答案以获取更详细的解释:https://dev59.com/4mgv5IYBdhLWcg3wI9Sg#10857806 - Daan
4
当您想要刷新令牌时,所有情况下都需要使用access_type=offline - Daan
7
我已经编辑过这个答案,使其能够正常工作,因为旧的答案似乎已经失效。由于多个地方都提到了使用这种方法,我花了很多时间来尝试。最后我阅读了文档(我应该先这么做),发现你必须使用prompt=consent。参考链接:https://developers.google.com/identity/protocols/OAuth2WebServer#offline - Goblinlord
9
@Daan和@Goblinlord都是正确的,即使我读了他们的评论之后,我仍然很困惑。实际上,我们需要同时使用'access_type=offline&prompt=consent',否则'refresh_token'将不会出现。 - Noitidart
显示剩余2条评论

69

如果我可以扩展一下user987361的回答:

关于OAuth2.0文档中的离线访问部分:

当你的应用程序接收到刷新令牌时,将该刷新令牌存储以供将来使用非常重要。如果您的应用程序丢失了刷新令牌,则必须重新提示用户同意才能获得另一个刷新令牌。如果您需要重新提示用户同意,请在授权代码请求中包括approval_prompt参数,并将值设置为force

因此,当您已经授予访问权限后,对于grant_typeauthorization_code的后续请求,即使在同意页面的查询字符串中设置了access_typeoffline,也不会返回refresh_token

如上面的引用所述,为了在已经获得refresh_token之后获得new refresh_token,您需要将用户重新发送到提示页面,并通过将approval_prompt设置为force来实现。

干杯,

PS:这个更改也在博客文章中宣布了。


4
我想补充一点,如果你丢失了 refresh token 或者用户撤销了你的访问权限,你需要获取一个新的 refresh token。否则,你可以继续使用相同的 refresh token 来获取新的 access token - jeteon
1
我有一个CMS,不同的用户使用不同的Google帐户连接到分析API。然而,有时候几个用户可以使用相同的企业Google帐户连接,但每个人都想访问不同的分析帐户。只有第一个人收到刷新令牌,而其他所有人都没有,因此必须每小时重新连接。难道没有办法在后续身份验证中获取相同的刷新令牌,而不仅仅是在一小时内过期的访问令牌吗? - Costin_T
是的。就这样做。当您发送请求时,您将收到一个访问令牌和刷新令牌。 - bossylobster
1
我一直在苦苦寻找refresh_token的解决方案,而你为我指明了方向!!!因此,当您已经授予访问权限时,即使在同意页面的查询字符串中将access_type设置为离线,对于授权代码的grant_type的后续请求也不会返回refresh_token。 - Cristiana SP

12

这是使用Google官方SDK的PHP完整代码

$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

1
这是截至2022年10月13日的正确答案。需要同时使用“离线”和“强制”,使用“同意”不起作用。 - PK.

12

1
该链接页面指出,当访问令牌过期时(更新令牌可能在secrets XML文件中),Google客户端将负责续订访问令牌,但是并未显示如何检测访问令牌已更改,以便可以将其保存在应用程序中供下一次访问使用。是否有回调函数来处理此问题,或者应用程序是否始终需要检查每个远程访问是否更改了访问令牌? - Jason

11

在我们的应用程序中,我们需要同时使用这两个参数access_type=offline&prompt=consentapproval_prompt=force对我们无效


2
谢谢Ricky,这对我也起作用了。我认为旧的答案可能在建议“approval_prompt=force”时是正确的,但现在已经不再适用了。这里有一些讨论: https://github.com/google/oauth2client/issues/453 - Mike Morearty
1
"approval_prompt=force" 对我有效。 - Shawinder Jit Singh

8

你好,我按照以下步骤进行操作,成功获取了刷新令牌。

授权流程分为两个步骤。

  1. 获取授权代码,使用URL:https://accounts.google.com/o/oauth2/auth?。 需要发送一个带有以下参数的POST请求:'scope=' + SCOPE + '&client_id=' + CLIENTID + '&redirect_uri=' + REDIRECT + '&response_type=' + TYPE + '&access_type=offline'。提供以上参数后,将会收到一个授权代码。

  2. 获取AccessToken和RefreshToken,使用URL:https://accounts.google.com/o/oauth2/token?。 需要发送一个带有以下参数的POST请求:

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

第一次尝试时,只要授权权限就能够获得刷新令牌。后续的尝试将不再提供刷新令牌。如果需要再次获取令牌,请在您的应用程序中撤销访问。

希望这能帮助其他人,祝愉快 :)


6

OAuth在实际应用中有两种情况:在线和离线。

默认的访问方式是在线访问。但有时你的应用可能需要在用户不在场的情况下访问Google API,这时就需要使用离线访问。

在离线访问中,在第一次授权代码交换期间可以获取一个刷新令牌(refresh token)。

因此,在某些情况下您可以获得刷新令牌(refresh token),而不是所有情况。

详细内容请参见https://developers.google.com/identity/protocols/OAuth2WebServer#offline


2

1
对于那些正在使用Google API Client Library进行PHP编程,并寻求离线访问和刷新令牌的用户,请注意,截至本文撰写时,文档中显示的示例不正确。
当前它显示的是:
$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

来源:https://developers.google.com/identity/protocols/OAuth2WebServer#offline

所有的东西都很好 - 除了一个问题。

$client->setApprovalPrompt("consent");

经过一番推理,我将这行代码更改为以下内容,一切都正常工作了
$client->setPrompt("consent");

这是有道理的,因为使用HTTP请求时,它从approval_prompt=force更改为prompt=consent。因此,将setter方法从setApprovalPrompt更改为setPrompt遵循自然约定 - 但它没有在文档中提到!至少我没有找到。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接