未收到Google OAuth刷新令牌

389
我希望从Google那里获取访问令牌。 Google 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
}

1
我曾经遇到过类似的问题。请查看我的回答这里 - Arithran
20个回答

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

#2023年3月

Short answer -->

access_type: 'offline',
prompt: 'consent',

pass these in  oAuth2Client.generateAuthUrl({})

这是正确的答案,我在更新提示参数后开始得到这个答案。 - Dalibor Karlović

1
使用离线访问prompt:consent对我来说效果很好:
   auth2 = gapi.auth2.init({
                    client_id: '{cliend_id}' 
   });

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

1
为了在认证时每次获取新的refresh_token,仪表板中创建的OAuth 2.0凭据类型应为“其他”。此外,如上所述,在生成authURL时应使用access_type ='offline'选项。
当使用类型为“Web应用程序”的凭据时,无论提示/批准提示变量的组合如何,都不起作用 - 您仍将仅在第一个请求中获得refresh_token。

1
对我来说,我正在尝试使用 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;
}

0

我的解决方案有点奇怪...我尝试了网上找到的每个解决方案,但都没有用。令人惊讶的是,这个方法有效:删除credentials.json文件,刷新,重新将您的应用程序与您的帐户关联。新的credentials.json文件将具有刷新令牌。将此文件备份到其他地方。 然后继续使用您的应用程序,直到再次出现刷新令牌错误。删除现在只有错误消息的crendetials.json文件(在我的情况下发生了这种情况),然后将旧的凭据文件粘贴到文件夹中,完成! 自从我这样做以来已经过去了1周,再也没有遇到问题。


0
在我的情况下,我按照上述步骤做了一切,但问题仍然存在。
我正在使用Python,并尝试按照以下方式获取凭据(文档参考,解释为什么应该有效。):
creds = {
          'token': credentials.token,
          'refresh_token': credentials.refresh_token,
          'token_uri': credentials.token_uri,
          'client_id': credentials.client_id,
          'client_secret': credentials.client_secret,
          'scopes': credentials.scopes
}

无论出于何种原因,这段代码在返回其他内容时却没有正确返回刷新令牌。
最终将其更改为以下内容解决了问题。
import json
creds = json.loads(credentials.to_json())

0

现在谷歌拒绝了我的请求中的这些参数(access_type,prompt)... :( 而且根本没有“撤销访问”按钮。我因为要重新获取我的refresh_token而感到沮丧。

更新: 我在这里找到了答案:D 你可以通过请求https://developers.google.com/identity/protocols/OAuth2WebServer来获取refresh token

curl -H "Content-type:application/x-www-form-urlencoded" \ https://accounts.google.com/o/oauth2/revoke?token={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

access_type=offline 添加到 Google 授权 URL 中对我很有帮助。我正在使用 Java 和 Spring 框架。

这是创建客户端注册的代码:

return CommonOAuth2Provider.GOOGLE
                    .getBuilder(client)
                    .scope("openid", "profile", "email", "https://www.googleapis.com/auth/gmail.send")
                    .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                    .authorizationUri("https://accounts.google.com/o/oauth2/v2/auth?access_type=offline")
                    .clientId(clientId)
                    .redirectUriTemplate("{baseUrl}/{action}/oauth2/code/{registrationId}")
                    .clientSecret(clientSecret)
                    .build();

重要的部分在于授权URI,后面附加了?access_type=offline

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