Google OAuth yenileme jetonu almıyor


270

Google'dan erişim belirteci almak istiyorum. Google API , erişim belirtecini almak, kodu ve diğer parametreleri belirteç oluşturma sayfasına gönderdiğini ve yanıtın aşağıdaki gibi bir JSON Nesnesi olacağını söylüyor.

{
"access_token" : "ya29.AHES6ZTtm7SuokEB-RGtbBty9IIlNiP9-eNMMQKtXdMP3sfjL1Fc",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "1/HKSmLFXzqP0leUihZp2xUt3-5wkU7Gmu2Os_eBnzw74"
}

Ancak, yenileme kodunu almıyorum. Benim durumumdaki cevap:

{
 "access_token" : "ya29.sddsdsdsdsds_h9v_nF0IR7XcwDK8XFB2EbvtxmgvB-4oZ8oU",
"token_type" : "Bearer",
"expires_in" : 3600
}

Benzer bir sorun yaşadım. Cevabımı buradan
Arithran

Yanıtlar:


675

Bu refresh_token, yalnızca kullanıcıdan gelen ilk yetkilendirme ile sağlanır. Bir OAuth2 entegrasyonunu test ederken yaptığınız türden sonraki yetkilendirmeler bir refresh_tokendaha geri dönmeyecektir . :)

  1. Hesabınıza erişimi olan Uygulamaları gösteren sayfaya gidin: https://myaccount.google.com/u/0/permissions .
  2. Üçüncü taraf uygulamalar menüsü altında uygulamanızı seçin.
  3. Erişimi kaldır'ı ve ardından onaylamak için Tamam'ı tıklayın.
  4. refresh_tokenYapacağınız bir sonraki OAuth2 isteği ('access_type = offline' sorgu parametresini de içermesi koşuluyla) döndürecektir.

Alternatif olarak, sorgu parametrelerini prompt=consent&access_type=offlineOAuth yönlendirmesine ekleyebilirsiniz (bkz. Google'ın Web Sunucusu Uygulamaları için OAuth 2.0) sayfası).

Bu, kullanıcıdan uygulamayı yeniden yetkilendirmesini ister ve her zaman bir a döndürür refresh_token.


20
Bu benim için işe yaramadı, ancak "access_type = offline" parametresini eklemek hile gibi görünüyordu: developers.google.com/accounts/docs/OAuth2WebServer#offline
Jesse

87
Her access_type=offlinedurumda istediğiniz zaman ihtiyacınız var refresh_token.
DanH

5
Ancak bu durumda süresinin dolmasından sonra belirteci nasıl yenileyebilirim?
vivek_jonam

5
@vivek_jonam Yenileme belirtecini ve son kullanma tarihini saklayın. Süresi dolduğunda yenileme kodunu kullanarak yeni bir kod istersiniz. Buraya bakın: developers.google.com/accounts/docs/OAuth2WebServer#refresh
gelviis

4
İle çalıştım $client->setAccessType('offline'). function setApprovalPrompt()Zaten geçirilen forcevarsayılan olarak.
Moey

57

Yenileme jetonunu almak için her ikisini de eklemeniz gerekir approval_prompt=forceve access_type="offline" Google tarafından sağlanan java istemcisini kullanıyorsanız şu şekilde görünecektir:

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

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

Düğümde: var authUrl = oauth2Client.generateAuthUrl ({access_type: 'offline', kapsam: SCOPES, confirm_prompt: 'force'});
Joris Mans

2
Google'ın kendi belgelerinde bu sorunu ele almadığı veya en azından 7 saattir baktığım php veya oath2 belgelerinde çirkin olması çok çirkin. Neden dünyada bu onların belgelerinde büyük kalın metin değil
Colin Rickels

Teşekkür ederim! Buradaki dokümanlar ( github.com/googlesamples/apps-script-oauth2 ) bu parametre hakkında çok yanıltıcıdır. Confirm_prompt = force eklediğimde sonunda bir yenileme jetonu aldım.
Alex Zhevzhik

28

Uzun bir gece aradım ve bu hile yapıyor:

Admin-sdk'den değiştirilmiş user-example.php

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

daha sonra kodu yönlendirme URL'sinde ve kodla kimlik doğrulaması yaparak yenileme jetonunu alırsınız

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

Şimdi saklamalısınız;)

Erişim anahtarınız zaman aşımına uğradığında

$client->refreshToken($theRefreshTokenYouHadStored);

Perfect @Norbert, Tam da ihtiyacım olan buydu.
Emmanuel

Teşekkürler! Soruma tam yanıt @Norbert
varun teja-MVT

16

Bu bana biraz karışıklık yarattı, bu yüzden zor yoldan öğrenmek için geldiğimi paylaşacağımı düşündüm:

access_type=offlineVe approval_prompt=forceparametrelerini kullanarak erişim isteğinde bulunduğunuzda, hem bir erişim belirteci hem de bir yenileme belirteci almanız gerekir . giriş Bunu aldıktan ve bunu yenilemek gerekecek sonra belirteç yakında sona eriyor.

Doğru yeni olsun istekte erişim belirteci ve yeni sahiptir yanıt aldı erişim belirteci. Yeni bir yenileme jetonu alamadığım için de kafam karıştı . Ancak, aynı yenileme jetonunu tekrar tekrar kullanabildiğiniz için böyle olması gerekiyordu .

Sanırım diğer bazı cevaplar, kendinize bir nedenden dolayı yeni bir yenileme jetonu almak istediğinizi ve kullanıcıyı yeniden yetkilendirdiğinizi önerdiğini varsayıyor, ancak gerçekte, sahip olduğunuz yenileme jetonunun kullanıcı tarafından iptal edildi.


1
Farklı kullanıcıların analiz API'sine bağlanmak için farklı Google hesapları kullandıkları bir CMS'im var. Bununla birlikte, bazen birkaç kullanıcı aynı kurumsal google hesabını kullanarak bağlanabilir, ancak her biri farklı bir Analytics hesabına erişmek ister. Sadece birincisi yenileme jetonunu alırken, diğerleri her saat yeniden bağlanmak zorunda kalmaz ve bu nedenle yeniden bağlanmak zorundadır. Yalnızca bir saat içinde sona eren access_token yerine sonraki kimlik doğrulamaları için SAME yenileme kodunu almanın bir yolu yok mu?
SsjCosty

1
API, yenileme kodunu tam olarak bir kez üretiyor gibi görünüyor . Simgenin herhangi bir "paylaşımı" kodunuzda gerçekleşmelidir. Yine de, kullanıcılara yanlışlıkla yeni erişim ayrıcalıkları vermemeye dikkat etmelisiniz. Bunu yapmanın basit bir yolu, uygulamanın yenileme jetonlarını ve ilişkili hesapları kendi depolarında (SQLese'de ayrı 'tablo') takip etmesini sağlamaktır. Ardından, yeni bir erişim jetonu almak istediğinizde bu ortak jetonu kontrol edip oradan kullanabilirsiniz. Belli bir şekilde uygulandığında, kodunuzun jetonu kimin aldığını bilmesine gerek yoktur.
Haziran'da jeteon

1
Sahip olduğum yeni bir erişim belirteciyle hangi yenileme belirtecini ilişkilendirmem gerektiğini nasıl belirleyebileceğimi bilmiyorum. Giriş yapan farklı kullanıcılar vardır ve ortak oldukları tek şey, API'ya bağlanmak için aynı Google hesabını (e-posta) kullanmalarıdır. Ancak Google, hesabın veya e-postanın kimliğini geri göndermez, yalnızca bir jeton geri gönderir. Bu yüzden 2 farklı CMS kullanıcısını nasıl ilişkilendireceğimi bilmiyorum ...
SsjCosty


Youtube oAuth2 refresh_token yalnızca kuvvet kullanıldığında gösterilir.
Dmitry Polushkin

7

Zengin Sutton cevabı ben eklemenin fark sonra nihayet benim için çalıştı access_type=offlineyapılır ön uç , bir yetkilendirme kodu için müşterinin isteğine değil arka uç isteği olduğunu bir access_token için alışverişi o kodu. Yenileme simgeleri hakkında daha fazla bilgi için yanıtına ve Google'daki bu bağlantıya bir yorum ekledim .

PS Satellizer kullanıyorsanız, bu seçeneği AngularJS'deki $ authProvider.google 'a nasıl ekleyeceğiniz aşağıda açıklanmıştır .


Çok küçük detaylar ama önemli olan. Beni kurtardı ! Teşekkürler :)
Dexter

@ZackMorris Yani .. u erişim belirteci kullanarak arka uçtan refresh_token alamıyorum demek istiyor musunuz?
Nevermore

@Nevermore access_token'in kendisinden bir refresh_token alamazsınız. Sunucunuzun yenilemeleri işlemesini istiyorsanız, refresh_token'i veritabanınızda ilk kez depolamanız gerekir. Ayrıca, kullanıcı arabiriminde bir istemci OAuth akışı yapıyorsanız, kullanıcıların sunucunun kendileri için yenilenmesini istedikleri takdirde arka plana refresh_token göndermeleri gerekir.
Zack Morris

4

Bunun için OAuth istek URL'sine refresh_tokeneklemeniz gerekir access_type=offline. Bir kullanıcı kimliğini doğrular ilk defa olmayan bir nil geri alacak zaman refresh_tokeniyi bir yanı access_tokendolacağını.

Bir kullanıcının zaten bir kimlik doğrulama jetonuna sahip olduğunuz bir hesabı yeniden doğrulayabileceği bir durumunuz varsa (yukarıdaki @SsjCosty'den bahsedildiği gibi), Google'dan jetonun hangi hesaba ait olduğu bilgisini geri almanız gerekir. Bunu yapmak profileiçin kapsamlarınıza ekleyin . OAuth2 Ruby taşını kullanarak son isteğiniz şöyle görünebilir:

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

Kapsamın, biri Google Analytics'e salt okunur erişim için diğerinin sadece profilebir OpenID Connect standardı olduğunu belirten iki alanla sınırlı girişi olduğunu unutmayın.

Bu adında ek özelliği sağlayarak Google'da sonuçlanacaktır id_tokeniçinde get_tokentepki. İd_token'dan bilgi almak için Google dokümanlarındaki bu sayfaya göz atın . Bunu sizin için doğrulayacak ve "kodunu çözecek" Google tarafından sağlanan birkaç kitaplık var (Ruby google-id-token mücevherini kullandım ). Ayrıştırıldıktan sonra, subparametre etkili bir şekilde benzersiz Google hesap kimliğidir.

Eğer varsa değer belirterek, değiştirmek kapsamını, zaten orijinal kapsamı ile doğrulanmış olan kullanıcılar için tekrar jetonun bir yenileme geri döneceğiz. Diyelim ki, zaten bir grup kullanıcınız varsa ve bunların hepsini Google'daki uygulamanın yetkisini kaldırmak istemiyorsanız yararlıdır.

Oh, ve bir final not: yok gerek prompt=select_account , ancak kullanıcılar birden fazla Google hesabı ile kimlik doğrulaması isteyebilirsiniz bir durum varsa yararlıdır (yani sen Oturum açma / kimlik doğrulaması için bu kullanmıyorsanız) .


Bence herhangi bir kişisel bilgi saklamadan kullanıcıları tanımlamanın önemli bir parçası olduğunu düşünüyorum. İşaret ettiğiniz için teşekkürler, Google dokümanlarında bu konuda herhangi bir referans görmedim.
Danielo515

3

1. 'refresh_token' nasıl alınır?

Çözüm: authURL oluşturulurken access_type = 'offline' seçeneği kullanılmalıdır. kaynak: Web Sunucusu Uygulamaları için OAuth 2.0 Kullanma

2. Ama 'access_type = offline' ile bile, 'refresh_token' almıyorum?

Çözüm: Lütfen yalnızca ilk istekte alacağınızı unutmayın; bu nedenle, bir yerde saklıyorsanız ve önceki süre dolduktan sonra yeni access_token alırken kodunuzun üzerine yazmak için bir hüküm varsa, bu değerin üzerine yazmamaya dikkat edin.

Google Auth Doc'tan: (bu değer = erişim_türü)

Bu değer, Google yetkilendirme sunucusuna, uygulamanız ilk kez belirteçler için bir yetkilendirme kodu alışverişinde bulunduğunda bir yenileme belirteci ve erişim belirteci döndürmesini bildirir.

Tekrar 'refresh_token' gerekiyorsa, Zengin Sutton'ın cevabında yazılı adımları uygulayarak uygulamanıza erişimi kaldırmanız gerekir .


2

Bunu ayarlamak, yenileme kodunun her seferinde gönderilmesine neden olur:

$client->setApprovalPrompt('force');

bir örnek aşağıda verilmiştir (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');

1

Benim için CalendarSampleServletGoogle tarafından sağlanmıştı. 1 saat sonra access_key zaman aşımına uğrar ve 401 sayfaya yönlendirilir. Yukarıdaki tüm seçenekleri denedim ama işe yaramadı. Son olarak 'AbstractAuthorizationCodeServlet' için kaynak kodunu kontrol ettikten sonra , kimlik bilgileri varsa yeniden yönlendirmenin devre dışı bırakılacağını görebiliyordum, ama ideal olarak kontrol etmeliydi refresh token!=null. Aşağıdaki kodu ekledim CalendarSampleServletve bundan sonra çalıştı. Saatlerce süren hayal kırıklığından sonra büyük rahatlama. Tanrıya şükür.

if (credential.getRefreshToken() == null) {
    AuthorizationCodeRequestUrl authorizationUrl = authFlow.newAuthorizationUrl();
    authorizationUrl.setRedirectUri(getRedirectUri(req));
    onAuthorization(req, resp, authorizationUrl);
    credential = null;
}

0

şimdi google bu parametreleri isteğimde reddetti (access_type, istemi) ... :( ve hiç "Erişimi İptal Et" düğmesi yok. benim refresh_token lol geri almak nedeniyle sinir bozucu

GÜNCELLEME: Cevabı burada buldum: D https://developers.google.com/identity/protocols/OAuth2WebServer isteğiyle yenileme kodunu geri alabilirsiniz.

curl -H "İçerik türü: application / x-www-form-urlencoded" \ https://accounts.google.com/o/oauth2/revoke?token= {token}

Belirteç bir erişim belirteci veya yenileme belirteci olabilir. Belirteç bir erişim belirteciyse ve karşılık gelen bir yenileme belirtecine sahipse, yenileme belirteci de iptal edilir.

İptal başarılı bir şekilde işlenirse, yanıtın durum kodu 200'dür. Hata koşulları için, bir hata kodu ile birlikte bir durum kodu 400 döndürülür.


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

Çevrimdışı erişim ve bilgi istemi kullanma : onay benim için iyi çalıştı:

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

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

0

Benim çözüm biraz garip ... internet ve hiçbir şey buldum her çözümü denedim. Şaşırtıcı olan bu çalıştı: credentials.json silmek, yenilemek, hesabınıza tekrar uygulamanızı vinculate. Yeni credentials.json dosyası yenileme jetonuna sahip olacaktır. Bu dosyayı bir yere yedekleyin. Ardından, yenileme belirteci hatası tekrar gelene kadar uygulamanızı kullanmaya devam edin. Şimdi sadece bir hata mesajıyla (bu benim durumumda hapenned) crendetials.json dosyasını silin, daha sonra klasöre eski kimlik bilgileri dosyasını yapıştırın, bitti! Ive bu yana yapılan ve daha fazla sorun vardı beri 1 hafta oldu.


0

Kimlik doğrulamasında her defasında yeni refresh_token almak için, gösterge tablosunda oluşturulan OAuth 2.0 kimlik bilgilerinin türü "Diğer" olmalıdır. Ayrıca yukarıda belirtildiği gibi authURL oluşturulurken access_type = 'offline' seçeneği kullanılmalıdır.

"Web uygulaması" türünde kimlik bilgilerini kullanırken, bilgi istemi / confirm_prompt değişkenlerinin hiçbir kombinasyonu çalışmaz - refresh_token değerini yalnızca ilk istekte alırsınız.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.