没有收到谷歌的OAuth刷新令牌

问题描述 投票:238回答:14

我想从谷歌的访问令牌。 The Google API says,为了获得访问令牌,发送代码和其他参数令牌生成页面,并且响应将是一个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
}
gdata gdata-api access-token
14个回答
621
投票

所述refresh_token只提供对来自用户的第一授权。随后的授权,比如那种让你在测试中加入OAuth2整合,不会再返回refresh_token。 :)

  1. 去显示访问您的帐户关联的应用页面:https://myaccount.google.com/u/0/permissions
  2. 根据第三方应用程序菜单中,选择您的应用程序。
  3. 单击删除访问,然后单击OK确认
  4. 接下来OAuth2要求你做会返回一个refresh_token

另外,您也可以添加查询参数prompt=consent到OAuth的重定向(见谷歌的OAuth 2.0 for Web Server Applications页)。

这会提示用户重新授权的应用程序,总是会返回一个refresh_token


0
投票

现在,谷歌已经在我的请求被拒绝那些参数(ACCESS_TYPE,提示)... :(并没有“撤销访问权限”按钮,在所有。我很沮丧,因为找回我的refresh_token的笑

更新:我发现在这里的答案:D您可以通过请求https://developers.google.com/identity/protocols/OAuth2WebServer找回刷新令牌

卷曲-H“内容类型:application / X WWW的窗体-urlencoded” \ https://accounts.google.com/o/oauth2/revoke?token= {令牌}

令牌可以是一个访问令牌或刷新令牌。如果令牌是一个访问令牌,它有一个相应的刷新令牌,刷新令牌也将被撤销。

如果撤销处理成功,则该响应的状态码为200。错误条件,状态码400与错误代码一起返回。


0
投票
    #!/usr/bin/env perl

    use strict;
    use warnings;
    use 5.010_000;
    use utf8;
    binmode STDOUT, ":encoding(utf8)";

    use Text::CSV_XS;
    use FindBin;
    use lib $FindBin::Bin . '/../lib';
    use Net::Google::Spreadsheets::V4;

    use Net::Google::DataAPI::Auth::OAuth2;

    use lib 'lib';
    use Term::Prompt;
    use Net::Google::DataAPI::Auth::OAuth2;
    use Net::Google::Spreadsheets;
    use Data::Printer ;


    my $oauth2 = Net::Google::DataAPI::Auth::OAuth2->new(
         client_id => $ENV{CLIENT_ID},
         client_secret => $ENV{CLIENT_SECRET},
         scope => ['https://www.googleapis.com/auth/spreadsheets'],
    );
    my $url = $oauth2->authorize_url();
    # system("open '$url'");
    print "go to the following url with your browser \n" ;
    print "$url\n" ;
    my $code = prompt('x', 'paste code: ', '', '');
    my $objToken = $oauth2->get_access_token($code);

    my $refresh_token = $objToken->refresh_token() ;

    print "my refresh token is : \n" ;
    # debug p($refresh_token ) ;
    p ( $objToken ) ;


    my $gs = Net::Google::Spreadsheets::V4->new(
            client_id      => $ENV{CLIENT_ID}
         , client_secret  => $ENV{CLIENT_SECRET}
         , refresh_token  => $refresh_token
         , spreadsheet_id => '1hGNULaWpYwtnMDDPPkZT73zLGDUgv5blwJtK7hAiVIU'
    );

    my($content, $res);

    my $title = 'My foobar sheet';

    my $sheet = $gs->get_sheet(title => $title);

    # create a sheet if does not exit
    unless ($sheet) {
         ($content, $res) = $gs->request(
              POST => ':batchUpdate',
              {
                    requests => [
                         {
                              addSheet => {
                                    properties => {
                                         title => $title,
                                         index => 0,
                                    },
                              },
                         },
                    ],
              },
         );

         $sheet = $content->{replies}[0]{addSheet};
    }

    my $sheet_prop = $sheet->{properties};

    # clear all cells
    $gs->clear_sheet(sheet_id => $sheet_prop->{sheetId});

    # import data
    my @requests = ();
    my $idx = 0;

    my @rows = (
         [qw(name age favorite)], # header
         [qw(tarou 31 curry)],
         [qw(jirou 18 gyoza)],
         [qw(saburou 27 ramen)],
    );

    for my $row (@rows) {
         push @requests, {
              pasteData => {
                    coordinate => {
                         sheetId     => $sheet_prop->{sheetId},
                         rowIndex    => $idx++,
                         columnIndex => 0,
                    },
                    data => $gs->to_csv(@$row),
                    type => 'PASTE_NORMAL',
                    delimiter => ',',
              },
         };
    }

    # format a header row
    push @requests, {
         repeatCell => {
              range => {
                    sheetId       => $sheet_prop->{sheetId},
                    startRowIndex => 0,
                    endRowIndex   => 1,
              },
              cell => {
                    userEnteredFormat => {
                         backgroundColor => {
                              red   => 0.0,
                              green => 0.0,
                              blue  => 0.0,
                         },
                         horizontalAlignment => 'CENTER',
                         textFormat => {
                              foregroundColor => {
                                    red   => 1.0,
                                    green => 1.0,
                                    blue  => 1.0
                              },
                              bold => \1,
                         },
                    },
              },
              fields => 'userEnteredFormat(backgroundColor,textFormat,horizontalAlignment)',
         },
    };

    ($content, $res) = $gs->request(
         POST => ':batchUpdate',
         {
              requests => \@requests,
         },
    );

    exit;

    #Google Sheets API, v4

    # Scopes
    # https://www.googleapis.com/auth/drive   View and manage the files in your Google D# # i# rive
    # https://www.googleapis.com/auth/drive.file View and manage Google Drive files and folders that you have opened or created with this app
    # https://www.googleapis.com/auth/drive.readonly   View the files in your Google Drive
    # https://www.googleapis.com/auth/spreadsheets  View and manage your spreadsheets in Google Drive
    # https://www.googleapis.com/auth/spreadsheets.readonly  View your Google Spreadsheets

0
投票

使用离线访问以及对提示:同意行之有效对我说:

   auth2 = gapi.auth2.init({
                    client_id: '{cliend_id}' 
   });

   auth2.grantOfflineAccess({prompt:'consent'}).then(signInCallback); 

0
投票

我的解决方案是一个有点weird..i千方百计解决我的互联网并没有什么上找到。 Surprisely这工作:删除credentials.json,刷新,再次vinculate您帐户中的应用。新credentials.json文件将具有刷新令牌。备份这个文件的某个地方。然后继续使用您的应用程序,直到刷新令牌错误再次出现。删除crendetials.json文件,现在仅是一个错误信息(这hapenned在我的情况),然后粘贴你旧凭证文件夹中的文件,它的完成了!它的后的1星期了香港专业教育学院做到了这一点,也没有更多的问题。


0
投票

为了每次拿到新refresh_token身份验证的仪表板创造应该是“其他”的OAuth 2.0凭据类型。也ACCESS_TYPE如上所述=“离线”选项应生成authURL时使用。

当使用类型为“Web应用程序”的凭据没有提示/ approval_prompt变量的组合将工作 - 你仍然会得到refresh_token只在第一次请求。


56
投票

为了获得刷新令牌你如果你正在使用谷歌提供的Java客户端会像这样同时添加approval_prompt=forceaccess_type="offline"

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

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

27
投票

我搜索一个漫长的夜晚,这是做的伎俩:

从管理-SDK修改用户使用example.php

$client->setAccessType('offline');
$client->setApprovalPrompt('force');
$authUrl = $client->createAuthUrl();
echo "<a class='login' href='" . $authUrl . "'>Connect Me!</a>";

然后你在重定向URL代码,并与代码验证和获取刷新令牌

$client()->authenticate($_GET['code']);
echo $client()->getRefreshToken();

你应该存储现在;)

当你的ACCESSKEY超时只是做

$client->refreshToken($theRefreshTokenYouHadStored);

16
投票

这引起了我一些混乱,所以我想我会分享我来学习困难的方式:

当您使用access_type=offlineapproval_prompt=force参数请求访问您会收到两个访问令牌和刷新令牌。你收到它,你将需要刷新之后的访问令牌即将到期。

你做出正确获取新的访问令牌的请求,并收到了新的访问令牌的响应。我也对我没有得到一个新的刷新令牌的事实混淆。然而,这是它是如何意思是,因为你可以使用相同的刷新令牌一遍又一遍。

我认为一些其他的答案假设你想给自己一个新的刷新令牌出于某种原因,并sugggested您重新授权的用户,但实际上,你并不需要,因为刷新令牌,你必须将工作到由用户撤销。


7
投票

Rich Sutton's answer终于为我工作后,我意识到,加入access_type=offline是在前端客户端的授权码的要求,而不是交换代码为对的access_token后端请求完成。我已经加入到他的回答和this link at Google评论有关刷新令牌的更多信息。

附:如果您正在使用Satellizer,here is how to add that option to the $authProvider.google in AngularJS


4
投票

为了获得refresh_token你需要包括在OAuth请求URL access_type=offline。当用户首次进行身份验证时,你会得到一个非空refresh_token以及为到期的access_token

如果你遇到这样的情况,用户可能重新认证的帐户,你已经有(像上面@SsjCosty提到),你需要从谷歌上占令牌是找回信息的身份验证令牌。要做到这一点,添加profile到您的作用域。使用的OAuth2红宝石的宝石,你的最后请求可能是这个样子:

client = OAuth2::Client.new(
  ENV["GOOGLE_CLIENT_ID"],
  ENV["GOOGLE_CLIENT_SECRET"],
  authorize_url: "https://accounts.google.com/o/oauth2/auth",
  token_url: "https://accounts.google.com/o/oauth2/token"
)

# Configure authorization url
client.authorize_url(
  scope: "https://www.googleapis.com/auth/analytics.readonly profile",
  redirect_uri: callback_url,
  access_type: "offline",
  prompt: "select_account"
)

注意范围有两个空格分隔的条目,一个用于谷歌分析只读访问,另一个是刚刚profile,这是一个ID连接标准。

这将导致谷歌提供的id_token响应称为get_token附加属性。要获取信息了id_token,check out this page在谷歌文档。有谷歌提供的库将验证和“解码”了一把这件事情(我使用的红宝石google-id-token gem)。一旦你得到它的解析后,sub参数是有效的唯一谷歌帐户ID。

值得注意的是,如果你改变的范围,你会为那些已经与原来的范围身份验证的用户得到一个刷新令牌一次。比如说,如果你有一大堆的用户已经,不想让他们所有未权威性在谷歌应用程序,这非常有用。

哦,还有最后一点:你不需要prompt=select_account,但如果你遇到这样的情况你的用户可能需要一个以上的谷歌帐户(即验证它是非常有用的,你不使用此为登录/认证)。


2
投票

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

$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');

2
投票

1.如何获得“refresh_token”?

解决方案:ACCESS_TYPE =“离线”选项应该产生authURL时使用。来源:Using OAuth 2.0 for Web Server Applications

2.但是,即使“ACCESS_TYPE =离线”,我没有得到的“refresh_token”?

解决方案:请注意,你会得到它仅在第一次请求,所以如果你的地方存放,并有一条规定获得新的access_token时以前到期后,您的代码来覆盖这一点,那么请务必不要覆盖此值。

从谷歌验证文件:(此值= ACCESS_TYPE)

该值指示谷歌授权服务器返回一个刷新令牌和访问令牌首次申请往来的授权码令牌。

如果您需要“refresh_token”一遍,然后你需要删除访问你的应用程序由跟随写在Rich Sutton's answer的步骤。


1
投票

对我来说,我尝试了由谷歌提供CalendarSampleServlet。 1小时出access_key次,之后有一个重定向到一个401页。我尝试了所有上述选项,但他们没有工作。最后在检查“AbstractAuthorizationCodeServlet”的源代码,我可以看到,如果凭据都存在重定向将被禁用,但理想的应该有检查refresh token!=null。我添加下面的代码到CalendarSampleServlet和它的工作之后。这么多小时的挫折后的大救援。感谢上帝。

if (credential.getRefreshToken() == null) {
    AuthorizationCodeRequestUrl authorizationUrl = authFlow.newAuthorizationUrl();
    authorizationUrl.setRedirectUri(getRedirectUri(req));
    onAuthorization(req, resp, authorizationUrl);
    credential = null;
}
© www.soinside.com 2019 - 2024. All rights reserved.