首页 文章

未收到Google OAuth刷新令牌

提问于
浏览
219

我想从Google获取访问令牌 . 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
}

12 回答

  • 4

    refresh_token 仅在用户的第一次授权时提供 . 后续授权(例如您在测试OAuth2集成时所使用的类型)将不会再次返回 refresh_token . :)

    • 转到显示可访问您帐户的应用的页面:https://myaccount.google.com/u/0/permissions .

    • 在第三方应用菜单下,选择您的应用 .

    • 单击“删除访问”,然后单击“确定”进行确认

    • 您发出的下一个OAuth2请求将返回 refresh_token .

    或者,您可以将查询参数 prompt=consent 添加到OAuth重定向(请参阅Google的OAuth 2.0 for Web Server Applications页面) .

    这将提示用户再次授权应用程序,并始终返回 refresh_token .

  • 53

    为了获得刷新令牌,您必须同时添加 approval_prompt=forceaccess_type="offline" 如果您使用的是Google提供的Java客户端,它将如下所示:

    GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
                HTTP_TRANSPORT, JSON_FACTORY, getClientSecrets(), scopes)
                .build();
    
    AuthorizationCodeRequestUrl authorizationUrl =
                flow.newAuthorizationUrl().setRedirectUri(callBackUrl)
                        .setApprovalPrompt("force")
                        .setAccessType("offline");
    
  • 14

    我搜索了一个漫长的夜晚,这就是诀窍:

    从admin-sdk修改了user-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);
    
  • 1

    这让我有些困惑,所以我想我会分享我学到的东西:

    当您使用 access_type=offlineapproval_prompt=force 参数请求访问时,您应该同时收到 access 令牌和 refresh 令牌 . access 令牌在您收到后很快就会到期,您需要刷新它 .

    您正确地请求获取新的 access 令牌并收到具有新 access 令牌的响应 . 我也因为没有获得新的 refresh 令牌而感到困惑 . 但是,这就是它的意思,因为你可以一遍又一遍地使用相同的 refresh 令牌 .

    我认为其他一些答案假设您出于某种原因想要给自己一个新的 refresh 令牌,并建议您重新授权用户,但实际上,您不需要因为 refresh 令牌将会工作直到被用户撤销 .

  • 1

    Rich Sutton's answer终于为我工作了,之后我意识到在 front end 客户端的授权代码请求上添加了 access_type=offlinenot 是为access_token交换该代码的后端请求 . 我已经为他的回答添加了评论,并且this link at Google了解有关刷新令牌的更多信息 .

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

  • 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');
    
  • 555

    对我来说,我正在尝试由Google提供 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;
    }
    
  • 26

    要获取 refresh_token ,您需要在OAuth请求网址中包含 access_type=offline . 当用户第一次进行身份验证时,您将返回非零 refresh_token 以及到期的 access_token .

    如果您的用户可能会重新验证您已拥有身份验证令牌的帐户(例如上面提到的@SsjCosty提及),则需要从Google获取该令牌所针对的帐户的信息 . 为此,请将 profile 添加到您的范围 . 使用OAuth2 Ruby gem,您的最终请求可能如下所示:

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

    请注意,示波器有两个以空格分隔的条目,一个用于对Google Analytics的只读访问,另一个只是 profile ,这是一个OpenID Connect标准 .

    这将导致Google在 get_token 响应中提供名为 id_token 的附加属性 . 要从Google文档中的id_token,check out this page中获取信息 . 有一些谷歌提供的库将验证和“解码”这个为你(我使用Ruby google-id-token gem) . 解析后, sub 参数实际上是唯一的Google帐户ID .

    值得注意的是,如果你改变了范围,那么你想让它们全部取消对谷歌应用的认可 .

    哦,最后一点说明:你不需要 prompt=select_account ,但是's useful if you have a situation where your users might want to authenticate with more than one Google account (i.e., you'并没有使用它进行登录/验证 .

  • 0

    现在谷歌已经拒绝了我的请求中的那些参数(access_type,提示)... :(并且根本没有“撤销访问”按钮 . 我很沮丧因为得到了我的refresh_token lol

    更新:我在这里找到了答案:D您可以通过请求获取刷新令牌https://developers.google.com/identity/protocols/OAuth2WebServer

    curl -H“内容类型:application / x-www-form-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

    使用 offline accessprompt:consent 对我很有用:

    auth2 = gapi.auth2.init({
                        client_id: '{cliend_id}' 
       });
    
       auth2.grantOfflineAccess({prompt:'consent'}).then(signInCallback);
    
  • 0

    我的解决方案有点奇怪..我尝试了我在互联网上找到的所有解决方案,没有 . 令人惊讶的是,这有效:删除credentials.json,刷新,再次在您的帐户中vinculate您的应用程序 . 新的credentials.json文件将具有刷新令牌 . 在某处备份此文件 . 然后继续使用您的应用程序,直到再次出现刷新令牌错误 . 删除现在只有错误消息的crendetials.json文件(在我的情况下这是hapenned),然后将旧的凭证文件粘贴到文件夹中,完成!自从我做完这一周以来已经过去了一周,没有更多问题 .

相关问题