324

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
}
4

17 に答える 17

814

refresh_token、ユーザーからの最初の承認時にのみ提供されます。OAuth2統合のテスト中に行った種類などの後続の認証では、refresh_token再度認証が返されることはありません。:)

  1. アカウントにアクセスできるアプリを表示しているページに移動します: https ://myaccount.google.com/u/0/permissions 。
  2. [サードパーティアプリ]メニューで、アプリを選択します。
  3. [アクセスの削除]をクリックし、[OK]をクリックして確認します
  4. 次に行うOAuth2リクエストは、を返しますrefresh_token('access_type =offline'クエリパラメータも含まれている場合)。

または、クエリパラメータをOAuthリダイレクトに追加することもできます(「 Webサーバーアプリケーション用prompt=consent&access_type=offlineのGoogleのOAuth 2.0」ページを参照)。

これにより、ユーザーはアプリケーションを再度承認するように求められ、常に。が返されrefresh_tokenます。

于 2012-06-01T21:51:56.980 に答える
65

更新トークンを取得するには、両方を追加するapproval_prompt=force必要access_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");
于 2013-01-01T08:21:21.767 に答える
30

私は長い夜を検索しました、そしてこれはトリックをしています:

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

今すぐ保存する必要があります;)

アクセスキーがタイムアウトしたときは、

$client->refreshToken($theRefreshTokenYouHadStored);
于 2014-11-06T12:56:10.033 に答える
20

これは私にいくつかの混乱を引き起こしたので、私は難しい方法を学ぶために来たものを共有したいと思いました:

access_type=offlineおよびパラメータを使用してアクセスを要求すると、アクセストークンと更新approval_prompt=forceトークンの両方を受け取る必要があります。アクセストークンは、受け取った直後に期限切れになるため、更新する必要があります。

新しいアクセストークンを取得するように正しくリクエストし、新しいアクセストークンを持つ応答を受け取りました。また、新しい更新トークンを取得しなかったという事実にも混乱しました。ただし、同じ更新トークンを何度も使用できるため、これが本来の意味です。

他の回答のいくつかは、何らかの理由で新しい更新トークンを取得したいと考えており、ユーザーを再承認することを提案していると思いますが、実際には、所有している更新トークンはユーザーによって取り消されました。

于 2015-05-15T13:12:39.557 に答える
17

この問題に遭遇した欲求不満の魂のために、この主題についてもう少し情報を追加したいと思います。オフラインアプリの更新トークンを取得するための鍵は、同意画面を表示していることを確認することです。はrefresh_token、ユーザーが[許可]をクリックして承認を付与した直後にのみ返されます。

ここに画像の説明を入力してください

この問題は、開発環境でテストを行った後、特定のアカウントでアプリケーションを既に承認した後で発生しました(他にも多くの疑いがあります)。その後、本番環境に移行し、すでに認証されているアカウントを使用して再度認証を試みました。この場合、同意画面は再び表示されず、APIは新しい更新トークンを返しません。これを機能させるには、次のいずれかの方法で同意画面を強制的に再表示する必要があります。

prompt=consent

また

approval_prompt=force

どちらか一方が機能しますが、両方を使用しないでください。2021年の時点でprompt=consent、古いパラメーターを置き換えるため、使用することをお勧めしますapproval_prompt。一部のAPIバージョンでは、後者が実際に壊れていました(https://github.com/googleapis/oauth2client/issues/453)。また、promptスペースで区切られたリストなので、prompt=select_account%20consent両方が必要なように設定できます。

もちろん、次のものも必要です。

access_type=offline

追加の読み物:

于 2021-01-13T12:34:14.017 に答える
8

リッチサットンの答えaccess_type=offlineは、追加がフロントエンドクライアントの認証コードの要求で行われ、そのコードをaccess_tokenと交換するバックエンドの要求ではないことに気付いた後、ようやくうまくいきました。トークンの更新の詳細については、彼の回答とGoogleのこのリンクにコメントを追加しました。

PS Satellizerを使用している場合、AngularJSの$authProvider.googleにそのオプションを追加する方法は次のとおりです。

于 2015-12-12T02:47:06.087 に答える
5

を取得するには、OAuthリクエストURLrefresh_tokenに含める必要があります。access_type=offlineユーザーが初めて認証を行うと、nil以外の値と、有効期限が切れる値が返さ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"
)

スコープには2つのスペース区切りのエントリがあります。1つはGoogleAnalyticsへの読み取り専用アクセス用で、もう1つはprofileOpenIDConnect標準であるだけです。

これにより、Googleid_tokenget_token応答で呼び出される追加の属性を提供します。id_tokenから情報を取得するには、Googleドキュメントのこのページを確認してください。これを検証して「デコード」するGoogle提供のライブラリがいくつかあります(私はRuby google-id-token gemを使用しました)。解析すると、subパラメータは事実上一意のGoogleアカウントIDになります。

注目に値するのは、スコープを変更すると、元のスコープですでに認証されているユーザーの更新トークンが再び返されることです。これは、たとえば、すでに多数のユーザーがいて、すべてのユーザーにGoogleのアプリの認証を解除させたくない場合に便利です。

最後にもう1つ注意してください。必要はありません prompt=select_account、ユーザーが複数のGoogleアカウントで認証したい場合(つまり、ログイン/認証にこれを使用していない場合)に便利です。 。

于 2017-09-20T23:16:46.117 に答える
3

1.'refresh_token 'を取得する方法は?

解決策: authURLを生成するときは、access_type='offline'オプションを使用する必要があります。ソース:WebサーバーアプリケーションにOAuth2.0を使用

2.しかし、「access_type = offset」を使用しても、「refresh_token」を取得できませんか?

解決策:最初のリクエストでのみ取得されることに注意してください。そのため、どこかに保存していて、以前の有効期限が切れた後に新しいaccess_tokenを取得するときにコードでこれを上書きする規定がある場合は、この値を上書きしないようにしてください。

Google AuthDocから:(この値=access_type)

この値は、アプリケーションが認証コードをトークンと初めて交換するときに、更新トークンとアクセストークンを返すようにGoogle認証サーバーに指示します。

'refresh_token'が再度必要な場合は、Rich Suttonの回答に記載されている手順に従って、アプリへのアクセスを削除する必要があります。

于 2019-06-20T08:36:28.867 に答える
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');
于 2016-09-06T22:00:43.963 に答える
1

私にとって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;
}
于 2013-11-13T05:38:18.897 に答える
1

オフラインアクセスprompt:consentを使用すると、うまくいきました。

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

   auth2.grantOfflineAccess({prompt:'consent'}).then(signInCallback); 
于 2018-01-18T13:55:10.493 に答える
1

プライベートデータへのアクセスにnodejsクライアントを使用しています

解決策は、 oAuth2Client.generateAuthUrl関数の設定オブジェクトに値の同意を得てprompプロパティを追加することでした。これが私のコードです:

const getNewToken = (oAuth2Client, callback) => {
    const authUrl = oAuth2Client.generateAuthUrl({
        access_type: 'offline',
        prompt: 'consent',
        scope: SCOPES,
    })
    console.log('Authorize this app by visiting this url:', authUrl)
    const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout,
    })
    rl.question('Enter the code from that page here: ', (code) => {
        rl.close()
        oAuth2Client.getToken(code, (err, token) => {
            if (err) return console.error('Error while trying to retrieve access token', err)
            oAuth2Client.setCredentials(token)
            // Store the token to disk for later program executions
            fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
                if (err) return console.error(err)
                console.log('Token stored to', TOKEN_PATH)
            })
            callback(oAuth2Client)
        })
    })
}

オンラインパラメータエクストラクタを使用して、トークンを生成するためのコードを取得できます。

オンラインパラメータエクストラクタ

これがグーグルの公式ドキュメントからの完全なコードです:

https://developers.google.com/sheets/api/quickstart/nodejs

情報がお役に立てば幸いです

于 2020-12-02T12:53:28.297 に答える
0

今グーグルは私のリクエスト(access_type、prompt)でそれらのパラメータを拒否しました...:(そして「RevokeAccess」ボタンはまったくありません。refresh_tokenを取り戻すためにイライラしています笑

更新:ここで答えを見つけました: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= {token}

トークンは、アクセストークンまたは更新トークンにすることができます。トークンがアクセストークンであり、対応する更新トークンがある場合、更新トークンも取り消されます。

失効が正常に処理された場合、応答のステータスコードは200です。エラー状態の場合、ステータスコード400がエラーコードとともに返されます。

于 2017-06-08T04:26:01.980 に答える
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
于 2017-08-08T15:06:15.333 に答える
0

私の解決策は少し奇妙でした..私はインターネットで見つけたすべての解決策を試しましたが、何もしませんでした。驚いたことに、これは機能しました。credentials.jsonを削除し、更新して、アカウントでアプリに再度アクセスします。新しいcredentials.jsonファイルには更新トークンが含まれます。このファイルをどこかにバックアップします。次に、更新トークンエラーが再び発生するまでアプリを使い続けます。エラーメッセージのみが表示されているcrendetials.jsonファイル(私の場合はこれが発生します)を削除してから、古いクレデンシャルファイルをフォルダーに貼り付けます。これで完了です。iveがこれを行ってから1週間が経過し、問題は発生しませんでした。

于 2018-06-04T16:13:21.203 に答える
0

認証時に毎回新しいrefresh_tokenを取得するには、ダッシュボードで作成されるOAuth2.0クレデンシャルのタイプを「その他」にする必要があります。また、前述のように、authURLを生成するときはaccess_type='offline'オプションを使用する必要があります。

タイプが「Webアプリケーション」のクレデンシャルを使用する場合、prompt/approval_prompt変数の組み合わせは機能しません。最初のリクエストでのみrefresh_tokenを取得できます。

于 2019-02-07T11:40:11.267 に答える
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();

ここで重要なのは、?access_type=offline追加される認証URIです。

于 2020-11-22T16:24:14.467 に答える