Не получать токен обновления OAuth Google

Я хочу получить токен доступа от Google. API Google говорит, что для получения токена доступа, отправки кода и других параметров на страницу генерации токенов, и ответ будет JSON Object like

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

refresh_token предоставляется только при первой авторизации от пользователя. Последующие авторизации, такие как те, которые вы делаете во время тестирования интеграции OAuth2, больше не будут возвращать refresh_token. :)

  1. Перейдите на страницу, на которой показаны приложения с доступом к вашей учетной записи: https://myaccount.google.com/u/0/permissions.
  2. В меню Сторонние приложения выберите свое приложение.
  3. Нажмите Удалить доступ, а затем нажмите ОК, чтобы подтвердить
  4. Следующий запрос OAuth2 вернет refresh_token.

Кроме того, вы можете добавить параметр запроса prompt=consent к перенаправлению OAuth (см. Страницу Google OAuth 2.0 для приложений веб-сервера).

Это побудит пользователя снова авторизовать приложение и всегда вернет refresh_token.

Ответ 2

Чтобы получить токен обновления, вы должны добавить как approval_prompt=force, так и access_type="offline" Если вы используете клиент java, предоставленный Google, он будет выглядеть следующим образом:

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

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

Ответ 3

Я искал длинную ночь, и это делает трюк:

Измененный user-example.php из admin-sdk

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

Вы должны сохранить его сейчас;)

Когда время доступа отключается, просто

$client->refreshToken($theRefreshTokenYouHadStored);

Ответ 4

Это вызвало у меня некоторую путаницу, поэтому я подумал, что разделю то, что я пришел, чтобы успеть:

Когда вы запрашиваете доступ с помощью параметров access_type=offline и approval_prompt=force, вы должны получить токен доступ и токен обновить. Текс доступ истекает вскоре после его получения, и вам нужно его обновить.

Вы правильно сделали запрос на получение нового токена доступа и получили ответ с новым токеном access. Меня также смутил тот факт, что я не получил новый токен refresh. Тем не менее, так оно и должно быть, так как вы можете использовать один и тот же токен обновить снова и снова.

Я думаю, что некоторые из других ответов предполагают, что вы хотели получить себе новый токен refresh по какой-то причине и предложили, чтобы вы повторно авторизировали пользователя, но на самом деле вам не нужно так как токен обновления, который у вас есть, будет работать до тех пор, пока пользователь не аннулирует его.

Ответ 5

Ответ Rich Sutton, наконец, работал у меня, после того как я понял, что добавление access_type=offline выполняется в запросе клиента для код авторизации, не запрос на конец, который обменивает этот код для access_token. Я добавил комментарий к его ответу и эту ссылку в Google для получения дополнительной информации об обновляющих токенах.

P.S. Если вы используете Satellizer, вот как добавить эту опцию в $authProvider.google в AngularJS.

Ответ 6

Установка этого параметра приведет к тому, что токен обновления будет отправляться каждый раз:

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

Ответ 7

Чтобы получить refresh_token, вам нужно включить access_type=offline в URL-адрес запроса OAuth. Когда пользователь аутентифицируется в первый раз, вы вернетесь к не-nil refresh_token, а также к access_token, который истекает.

Если у вас есть ситуация, когда пользователь может повторно аутентифицировать учетную запись, у вас уже есть токен аутентификации (например, @SsjCosty упоминает выше), вам нужно получить информацию от Google, на какой учетной записи есть токен. Для этого добавьте profile в свои области. Используя драгоценный камень OAuth2 Ruby, ваш последний запрос может выглядеть примерно так:

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 предоставит дополнительный атрибут id_token в ответе get_token. Чтобы получить информацию из id_token, просмотрите эту страницу в документах Google. Есть несколько библиотек, предоставляемых Google, которые будут проверять и "декодировать" это для вас (я использовал Ruby драгоценный камень google-id-token). После того как вы его разобрали, параметр sub фактически является уникальным идентификатором учетной записи Google.

Стоит отметить, что если вы измените область действия, вы снова получите токен обновления для пользователей, которые уже прошли аутентификацию с исходной областью. Это полезно, если, скажем, у вас уже есть группа пользователей, и вы не хотите, чтобы все они были отключены в Google.

О, и последнее замечание: вам не нужно prompt=select_account, но полезно, если у вас есть ситуация, когда ваши пользователи могут пройти проверку подлинности с несколькими учетными записями Google (т.е. вы не используете это для вход/аутентификация).

Ответ 8

Для меня я пытался CalendarSampleServlet предоставлял Google. Через 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;
}

Ответ 9

теперь google отказался от этих параметров в моем запросе (access_type, prompt)...:( и вообще нет кнопки "Отменить доступ". Я расстраиваюсь из-за возврата моего refresh_token lol

UPDATE: Я нашел ответ здесь: D вы можете вернуть токен обновления по запросу https://developers.google.com/identity/protocols/OAuth2WebServer

curl -H "Content-type: application/x-www-form-urlencoded" \         https://accounts.google.com/o/oauth2/revoke?token= {токен}

Маркер может быть токеном доступа или токеном обновления. Если токен является токеном доступа и имеет соответствующий токен обновления, токен обновления также будет отменен.

Если аннулирование успешно обработано, тогда код состояния ответа равен 200. Для условий ошибки возвращается код состояния 400 вместе с кодом ошибки.

Ответ 10

    #!/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

Ответ 11

Использование автономного доступа и подсказки: согласие хорошо для меня:

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

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

Ответ 12

Мое решение было немного странным. Я перепробовал каждое решение, которое нашел в интернете, и ничего. Удивительно, но это сработало: удалите credentials.json, обновите, снова откачайте ваше приложение в своей учетной записи. Новый файл credentials.json будет иметь маркер обновления. Сделайте резервную копию этого файла где-нибудь. Затем продолжайте использовать приложение, пока ошибка обновления токена не появится снова. Удалите файл crendetials.json, который теперь только с сообщением об ошибке (в моем случае это произошло), затем вставьте старый файл учетных данных в папку, готово! Прошла 1 неделя с тех пор, как я это сделал, и проблем больше не было.

Ответ 13

Чтобы каждый раз получать новый refresh_token при аутентификации, тип учетных данных OAuth 2.0, созданных на панели мониторинга, должен быть "Другой". Также, как упомянуто выше, опция access_type = 'offline' должна использоваться при генерации authURL.

При использовании учетных данных с типом "веб-приложение" никакая комбинация переменных prompt/authentication_prompt работать не будет - вы все равно получите refresh_token только при первом запросе.

Ответ 14

1. Как получить "refresh_token"?

Решение: опция access_type = 'offline' должна использоваться при создании authURL. Источник: Использование OAuth 2.0 для приложений веб-сервера

2. Но даже с "access_type = offline" я не получаю "refresh_token"?

Решение: обратите внимание, что вы получите его только при первом запросе, поэтому, если вы храните его где-то и есть возможность перезаписать это в своем коде при получении нового access_token после истечения предыдущего срока действия, убедитесь, что это значение не перезаписано.

Из Google Auth Doc: (это value = access_type)

Это значение указывает серверу авторизации Google возвращать токен обновления и токен доступа при первом обмене кода авторизации вашим приложением для токенов.

Если вам снова понадобится "refresh_token", то вам нужно удалить доступ к своему приложению, выполнив шаги, написанные в ответе Рича Саттона.