geçersiz_grant google'dan oAuth jetonu almaya çalışıyor


121

invalid_grantKişiler API'sine bağlanmak için Google'dan bir oAuth jetonu almaya çalışırken hata almaya devam ediyorum . Tüm bilgiler doğru ve bunu üç kez kontrol ettim, bu kadar şaşkın.

Bu soruna neyin neden olabileceğini bilen var mı? Bunun için farklı bir istemci kimliği kurmayı denedim ancak aynı sonucu alıyorum, zorla kimlik doğrulamayı denemek dahil birçok farklı yolu bağlamayı denedim, ancak yine de aynı sonuç.


benim için sorun google kimlik bilgileri sayfasındaydı ... başka bir tane oluşturdum ... ve sorunu
çözdüm

Yanıtlar:


59

Kullanıcıyı OAuth'a gönderirken açıkça "çevrimdışı" erişim istemediğimde bu sorunla karşılaştım "Bu uygulamaya öğelerinize dokunma izni vermek istiyor musunuz?" sayfa.

İsteğinizde access_type = offline değerini belirttiğinizden emin olun.

Ayrıntılar burada: https://developers.google.com/accounts/docs/OAuth2WebServer#offline

(Ayrıca: Google'ın bu kısıtlamayı 2011'in sonlarında eklediğini düşünüyorum. Daha önce eski simgeleriniz varsa, çevrimdışı kullanımı yetkilendirmek için kullanıcılarınızı izin sayfasına göndermeniz gerekir.)


9
@Adders Katılıyorum. Ben ayarlamak access_typeiçin offline, bu hata hala olur.
slideshowp2

Kabul edilen cevap bu olmamalı.
Kishan Solanki

Bu developer.google.com/android-publisher/authorization belgelerini inceleyin ve uygulanacak her şeyi okuyun
Kishan Solanki

70

"Çevrimdışı" seçeneğini belirlememe rağmen aynı sorunla karşılaştım access_typeBonkydog'un cevabına göre isteğimde . Uzun lafın kısası Burada açıklanan çözümün benim için işe yaradığını buldum:

https://groups.google.com/forum/#!topic/google-analytics-data-export-api/4uNaJtquxCs

Temelde, Google API'nizin konsoluna bir OAuth2 İstemcisi eklediğinizde, Google size bir "İstemci Kimliği" ve bir "E-posta adresi" (istemci türünüz olarak "webapp" ı seçtiğinizi varsayarak) verir. Google'ın yanıltıcı adlandırma kurallarına rağmen, sizden "E-posta adresini"client_id , OAuth2 API'lerine eriştiğinizde parametrenin .

Bu, bu URL'lerin her ikisini de çağırırken geçerlidir:

İlk URL'yi "E-posta adresiniz" yerine "Müşteri Kimliğiniz" ile ararsanız başarılı olacağını unutmayın. Ancak, bu istekten döndürülen kodu kullanmak, ikinci URL'den bir taşıyıcı belirteci almaya çalışırken işe yaramayacaktır. Bunun yerine bir 'Hata 400' ve bir "geçersiz_ bağış" mesajı alacaksınız.


66
Kesinlikle saçma: Özellikle ilk yenileme jetonunu alırsanız, client_id ile çalıştığı kısım. Google API ve belgeleri bir karmaşa.
Traubenfuchs

7
Saatlerdir bu konuya karşı kafamı vuruyordum. 'Client_id'nin' client_id 'alanı için beklenen şey olmadığını hiç beklemiyordum. Bir yenileme belirtecini aldığınız ve işe yaradığı zaman zaman haricinde. Eminim şu anda Google için sahip olduğum sözler SO'da söylenemez.
Justin

6
Merhabalar .. Bahsettiğiniz "e-posta" adresini bulamıyorum. konsolumda sahip olduğum şey bu -> pbs.twimg.com/media/CVVcEBWUwAAIiCy.png:large
omarojo

4
Bu e-posta adresi nerede? Aynı sorunu yaşıyorum
Isma Haro

4
Google belgelerine asla güvenmeyin. Crapiest belgeleri ve API'leri, dünyanın en değerli şirketi olan Google'dan gelir. Google API'yi kullanmak için sayısız saat harcamak zorunda kaldım. Sorunlardan sonra sorunlar vardı ve ardından farklı API'ler için kendi .Net kitaplıkları, farklı bağımlılık sorunları ve hepsi nedeniyle birlikte derlenmiyordu. Kod artık çoğu kullanıcı için iyi çalışıyor, ancak bazı kullanıcılar için belirli bir neden olmaksızın hala geçersiz_ bağış, geçersiz_ kimlik bilgileri vb. Alıyorum.
Allen King

56

Bu eski bir soru olmasına rağmen, pek çok kişi hala onunla karşılaşıyor gibi görünüyor - bunu takip etmek için günler harcadık.

OAuth2 spesifikasyonunda, "geçersiz_ bağış", geçersiz / süresi dolmuş / iptal edilmiş belirteçlerle (yetkilendirme izni veya yenileme belirteci) ilgili tüm hatalar için bir çeşit tümünü yakalama türüdür.

Bizim için sorun iki katıydı:

  1. Kullanıcı, uygulamamıza erişimi aktif olarak iptal etti
    Mantıklı, ancak şunu anlayın: İptal işleminden 12 saat sonra, Google yanıtlarında hata mesajını göndermeyi durdurur : “error_description” : “Token has been revoked.”
    Bu oldukça yanıltıcıdır çünkü hata mesajının her zaman orada olduğunu varsayarsınız. dava. Uygulamanızın hâlâ erişim izni olup olmadığını uygulama izin sayfasından kontrol edebilirsiniz .

  2. Kullanıcı, Google şifresini sıfırladı / kurtardı
    Aralık 2015'te, Google , Google Apps kullanmayan kullanıcılar için şifre sıfırlama işlemlerinin, kullanıcının tüm uygulama yenileme jetonlarını otomatik olarak iptal etmesini sağlayacak şekilde varsayılan davranışını değiştirdi . İptal edildiğinde, hata mesajı önceki durumla aynı kuralı izler, bu nedenle ilk 12 saat içinde yalnızca "error_description" öğesini alırsınız. Kullanıcının erişimi manuel olarak iptal edip etmediğini (kasıtlı olarak) veya bir şifre sıfırlama nedeniyle mi (yan etki) olduğunu bilmenin herhangi bir yolu yok gibi görünüyor.

Bunların dışında, hatayı tetikleyebilecek sayısız başka potansiyel neden var:

  1. Sunucu saati / saati senkronize değil
  2. Çevrimdışı erişim için yetkili değil
  3. Google tarafından kısıtlandı
  4. Süresi dolmuş yenileme jetonlarını kullanma
  5. Kullanıcı 6 aydır hareketsiz
  6. İstemci kimliği yerine hizmet çalışanı e-postasını kullanın
  7. Kısa sürede çok fazla erişim jetonu
  8. İstemci SDK'sı eski olabilir
  9. Yanlış / eksik yenileme simgesi

Suçluyu bulmaya yardımcı olmak için her öğeyi bazı hata ayıklama kılavuzlarıyla özetleyen kısa bir makale yazdım . Umarım yardımcı olur.


1
Diğer bir senaryo, aynı kimlik doğrulama kodundan birden çok kez jeton almaya çalışırsanız.
bilinenasilya

Bu tam olarak benim sorunumdu, sadece uygulamayı kazayla iptal etmek. Daha sonra, başka bir yetkilendirme kodu oluşturmak için yenilemeToken.php'yi terminal aracılığıyla yeniden çalıştırmak ve ardından bu istemci kimliği için her yerde yenilemeToken'i değiştirmek zorunda kaldı.
Robert Sinclair

7

Ben de aynı problemle karşılaştım. Benim için bunu, client_id parametre değeri için İstemci Kimliği yerine E-posta Adresi (... @ developer.gserviceaccount.com ile biten dize) kullanarak düzelttim. Google tarafından belirlenen adlandırma burada kafa karıştırıcı.


6
Bu, @aroth tarafından bir yıldan daha önce verilen yanıtın aynısı
Bryan Ash

3

Sorunum şu URL'yi kullanmamdı:

https://accounts.google.com/o/oauth2/token

Bu URL'yi ne zaman kullanmalıydım:

https://www.googleapis.com/oauth2/v4/token

Bu, Depolama motoruna çevrimdışı erişim isteyen bir hizmet hesabını test ediyordu .


2

Aynı " geçersiz_ bağış " hata mesajını aldım ve bunun nedeni authResult ['kod'] javascript'in istemci tarafından gönderilen sunucuda doğru şekilde alınmamasıydı.

Doğru olup olmadığını ve boş bir dize olmadığını görmek için sunucudan geri çıktısını almayı deneyin.


1

scribe kitaplığı kullanıyorsanız, bonkydog'un önerdiği gibi, sadece çevrimdışı modu ayarlayın, burada kod:

OAuthService service = new ServiceBuilder().provider(Google2Api.class).apiKey(clientId).apiSecret(apiSecret)
                .callback(callbackUrl).scope(SCOPE).offline(true)
                .build();

https://github.com/codolutions/scribe-java/


1

Bir Android clientId kullanarak (client_secret yok) aşağıdaki hata yanıtını alıyordum:

{
 "error": "invalid_grant",
 "error_description": "Missing code verifier."
}

'Code_verifier' alanı için herhangi bir belge bulamıyorum, ancak bunu hem yetkilendirme hem de belirteç isteklerinde eşit değerlere ayarlarsanız bu hatayı kaldıracağını keşfettim. Amaçlanan değerin ne olması gerektiğinden veya güvenli olup olmayacağından emin değilim. Minimum uzunluğu (16? Karakter) var, ancak ayarın nullda işe yaradığını buldum .

Bir setCodeVerifier()işlevi olan Android istemcimde yetkilendirme isteği için AppAuth kullanıyorum .

AuthorizationRequest authRequest = new AuthorizationRequest.Builder(
                                    serviceConfiguration,
                                    provider.getClientId(),
                                    ResponseTypeValues.CODE,
                                    provider.getRedirectUri()
                            )
                            .setScope(provider.getScope())
                            .setCodeVerifier(null)
                            .build();

Düğümdeki örnek bir simge isteği:

request.post(
  'https://www.googleapis.com/oauth2/v4/token',
  { form: {
    'code': '4/xxxxxxxxxxxxxxxxxxxx',
    'code_verifier': null,
    'client_id': 'xxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com',
    'client_secret': null,
    'redirect_uri': 'com.domain.app:/oauth2redirect',
    'grant_type': 'authorization_code'
  } },
  function (error, response, body) {
    if (!error && response.statusCode == 200) {
      console.log('Success!');
    } else {
      console.log(response.statusCode + ' ' + error);
    }

    console.log(body);
  }
);

Test ettim ve bu hem https://www.googleapis.com/oauth2/v4/tokenve hem dehttps://accounts.google.com/o/oauth2/token .

GoogleAuthorizationCodeTokenRequestBunun yerine kullanıyorsanız :

final GoogleAuthorizationCodeTokenRequest req = new GoogleAuthorizationCodeTokenRequest(
                    TRANSPORT,
                    JSON_FACTORY,
                    getClientId(),
                    getClientSecret(),
                    code,
                    redirectUrl
);
req.set("code_verifier", null);          
GoogleTokenResponse response = req.execute();



1

Valid_grant hatasının, Yenileme Belirteci ve Erişim Belirteci için POST isteğinden önce dikkat etmeniz gereken iki ana nedeni vardır .

  1. İstek başlığı "content-type: application / x-www-form-urlencoded" içermelidir
  2. İstek yükünüz url kodlu Form Verileri olmalıdır, json nesnesi olarak göndermeyin.

RFC 6749 OAuth 2.0 , valid_grant'ı şu şekilde tanımladı : Sağlanan yetkilendirme izni (ör. Yetkilendirme kodu, kaynak sahibi kimlik bilgileri) veya yenileme simgesi geçersiz, süresi dolmuş, iptal edilmiş, yetkilendirme isteğinde kullanılan yeniden yönlendirme URI'siyle eşleşmiyor veya başka bir istemciye verilmiş .

Burada başka bir güzel makale buldum bu hatanın diğer birçok nedenini bulacaksınız.

https://blog.timekit.io/google-oauth-invalid-grant-nightmare-and-how-to-fix-it-9f4efaf1da35


Neredeyse aynı iki yanıtı mı göndermek istediniz? Diğerinde ek bir satır olduğu için bunu silmek isteyebilirsiniz.
Blastfurnace

1

Bunu postacı / uykusuzlukta test ediyorsanız ve sadece çalıştırmaya çalışıyorsanız, ipucu: sunucu kimlik doğrulama kodu (kod parametresi) yalnızca bir kez kullanılabilir. Yani, istekteki diğer parametrelerden herhangi birini doldurursanız ve 400'ü geri alırsanız, yeni bir sunucu yetkilendirme kodu kullanmanız gerekir, yoksa sadece bir 400 daha alırsınız.



0

Buradaki diğer tüm yolları düşündükten ve denedikten sonra , sağlanan yöntem yerine jetonları almak için kullandığım modül googleapisile birlikte requestmodülle birlikte nodejs'deki sorunu nasıl çözdüm getToken():

const request = require('request');

//SETUP GOOGLE AUTH
var google = require('googleapis');
const oAuthConfigs = rootRequire('config/oAuthConfig')
const googleOAuthConfigs = oAuthConfigs.google

//for google OAuth: https://github.com/google/google-api-nodejs-client
var OAuth2 = google.auth.OAuth2;
var googleOAuth2Client = new OAuth2(
    process.env.GOOGLE_OAUTH_CLIENT_ID || googleOAuthConfigs.clientId, 
    process.env.GOOGLE_OAUTH_CLIENT_SECRET || googleOAuthConfigs.clientSecret, 
    process.env.GOOGLE_OAUTH_CLIENT_REDIRECT_URL || googleOAuthConfigs.callbackUrl);

/* generate a url that asks permissions for Google+ and Google Calendar scopes
https://developers.google.com/identity/protocols/googlescopes#monitoringv3*/
var googleOAuth2ClientScopes = [
    'https://www.googleapis.com/auth/plus.me',
    'https://www.googleapis.com/auth/userinfo.email'
];

var googleOAuth2ClientRedirectURL = process.env.GOOGLE_OAUTH_CLIENT_REDIRECT_URL || googleOAuthConfigs.callbackUrl; 

var googleOAuth2ClientAuthUrl = googleOAuth2Client.generateAuthUrl({
  access_type: 'offline', // 'online' (default) or 'offline' (gets refresh_token)
  scope: googleOAuth2ClientScopes // If you only need one scope you can pass it as string
});

//AFTER SETUP, THE FOLLOWING IS FOR OBTAINING TOKENS FROM THE AUTHCODE


        const ci = process.env.GOOGLE_OAUTH_CLIENT_ID || googleOAuthConfigs.clientId
        const cs = process.env.GOOGLE_OAUTH_CLIENT_SECRET || googleOAuthConfigs.clientSecret
        const ru = process.env.GOOGLE_OAUTH_CLIENT_REDIRECT_URL || googleOAuthConfigs.callbackUrl
        var oauth2Client = new OAuth2(ci, cs, ru);

        var hostUrl = "https://www.googleapis.com";
        hostUrl += '/oauth2/v4/token?code=' + authCode + '&client_id=' + ci + '&client_secret=' + cs + '&redirect_uri=' + ru + '&grant_type=authorization_code',
        request.post({url: hostUrl}, function optionalCallback(err, httpResponse, data) {
            // Now tokens contains an access_token and an optional refresh_token. Save them.
            if(!err) {
                //SUCCESS! We got the tokens
                const tokens = JSON.parse(data)
                oauth2Client.setCredentials(tokens);

                //AUTHENTICATED PROCEED AS DESIRED.
                googlePlus.people.get({ userId: 'me', auth: oauth2Client }, function(err, response) {
                // handle err and response
                    if(!err) {
                        res.status(200).json(response);
                    } else {
                        console.error("/google/exchange 1", err.message);
                        handleError(res, err.message, "Failed to retrieve google person");
                    }
                });
            } else {
                console.log("/google/exchange 2", err.message);
                handleError(res, err.message, "Failed to get access tokens", err.code);
            }
        });

requestApi isteğini burada açıklandığı gibi HTTP aracılığıyla yapmak için kullanıyorum : https://developers.google.com/identity/protocols/OAuth2WebServer#offline

POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=8819981768.apps.googleusercontent.com&
client_secret={client_secret}&
redirect_uri=https://oauth2.example.com/code&
grant_type=authorization_code


0

Gelecek millet için ... Çok sayıda makale ve blog okudum ama aşağıdaki çözümle şansım oldu ...

GoogleTokenResponse tokenResponse =
      new GoogleAuthorizationCodeTokenRequest(
          new NetHttpTransport(),
          JacksonFactory.getDefaultInstance(),
          "https://www.googleapis.com/oauth2/v4/token",
          clientId,
          clientSecret,
          authCode,
          "") //Redirect Url
     .setScopes(scopes)
     .setGrantType("authorization_code")
     .execute();

Bu blog, "invalid_grant" hatasının geldiği farklı durumları göstermektedir.

Zevk almak!!!


0

benim redirect_uriiçin geliştirici konsolundaki ile tam olarak eşleştiğinden emin olmalıydım Authorised redirect URIs, bu benim için düzeltildi, hata ayıklayabildim ve geçişten sonra sorunun tam olarak ne olduğunu biliyordum https://accounts.google.com/o/oauth2/token.https://www.googleapis.com/oauth2/v4/token

Uygun bir hata aldım:

{"error": "redirect_uri_mismatch",  "error_description": "Bad Request"}

0

Google konsolunda yeni bir hizmet API'sini etkinleştirdikten ve daha önce yapılmış kimlik bilgilerini kullanmaya çalıştıktan sonra bu sorunu yaşadım.

Sorunu çözmek için, kimlik bilgileri sayfasına geri dönmem, kimlik bilgisi adına tıklamam ve tekrar "Kaydet" e tıklamam gerekiyordu . Ondan sonra, gayet iyi doğrulayabilirim.


0

Benim durumumda sorun benim kodumdaydı. Yanlışlıkla aynı tokenlerle müşteriyi 2 kez başlatmaya çalıştım. Yukarıdaki yanıtların hiçbiri yardımcı olmadıysa, istemcinin 2 örneğini oluşturmadığınızdan emin olun.

Düzeltmeden önceki kodum:

def gc_service
      oauth_client = Signet::OAuth2::Client.new(client_options)
      oauth_client.code = params[:code]
      response = oauth_client.fetch_access_token!
      session[:authorization] = response
      oauth_client.update!(session[:authorization])

      gc_service = Google::Apis::CalendarV3::CalendarService.new
      gc_service.authorization = oauth_client

      gc_service
    end
primary_calendar_id = gc_service.list_calendar_lists.items.select(&:primary).first.id

gc_service.insert_acl(primary_calendar_id, acl_rule_object, send_notifications: false)

olarak değiştirir değiştirmez (yalnızca bir örnek kullanın):

@gc_service = gc_service
primary_calendar_id = @gc_service.list_calendar_lists.items.select(&:primary).first.id

@gc_service.insert_acl(primary_calendar_id, acl_rule_object, send_notifications: false)

hibe türüyle ilgili sorunlarımı çözdü.


0

Benim için sorunlar, projemde birden fazla müşterim olmasıydı ve bunun tamamen iyi olduğundan oldukça eminim, ancak bu proje için tüm istemciyi sildim ve yeni bir tane oluşturdum ve hepsi benim için çalışmaya başladım (WP_SMTP eklenti yardımından bu fikri aldım destek forumu) Referans için bu bağlantıyı bulamıyorum


0

Kullanıcı girdisini temizliyorsanız (Örneğin, $_GET["code"]php'de) Koddaki bir şeyi yanlışlıkla değiştirmediğinizden emin olun.

Kullandığım normal ifade şimdi /[^A-Za-z0-9\/-]/


0

Şuna bakın https://dev.to/risafj/beginner-s-guide-to-oauth-understanding-access-tokens-and-authorization-codes-2988

Öncelikle bir erişim jetonuna ihtiyacınız var:

$code = $_GET['code'];

$clientid = "xxxxxxx.apps.googleusercontent.com";
$clientsecret = "xxxxxxxxxxxxxxxxxxxxx";

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://www.googleapis.com/oauth2/v4/token");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "client_id=".urlencode($clientid)."&client_secret=".urlencode($clientsecret)."&code=".urlencode($code)."&grant_type=authorization_code&redirect_uri=". urlencode("https://yourdomain.com"));
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$server_output = curl_exec($ch);
curl_close ($ch);

$server_output = json_decode($server_output);
$access_token = $server_output->access_token;
$refresh_token = $server_output->refresh_token;
$expires_in = $server_output->expires_in;

Bir Veritabanında Erişim Jetonunu ve Yenileme Jetonunu ve expire_in güvenliğini sağlayın. Erişim Jetonunun süresi $ expires_in saniye sonra dolar. Daha sonra, aşağıdaki Talep ile yeni bir Erişim Jetonu almanız (ve Veri Tabanında saklamanız gerekir):

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://www.googleapis.com/oauth2/v4/token");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "client_id=".urlencode($clientid)."&client_secret=".urlencode($clientsecret)."&refresh_token=".urlencode($refresh_token)."&grant_type=refresh_token");
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$server_output = curl_exec($ch);
curl_close ($ch);

$server_output = json_decode($server_output);
$access_token = $server_output->access_token;
$expires_in = $server_output->expires_in;

Redirect_uri Etki Alanını Google Konsolunuzdaki Etki Alanlarınıza eklemeyi unutmayın: "OAuth 2.0-Client-IDs" Sekmesinde https://console.cloud.google.com/apis/credentials . Burada ayrıca Müşteri Kimliğinizi ve Müşteri Sırrınızı da bulabilirsiniz.


0

Kullanıcıyı google kimlik doğrulama sayfasına ilk kez yönlendirdiğinizde (ve bir kodu geri aldığınızda) ve döndürülen kodu alıp simge url'sine gönderdiğinizde arasında belgelenmemiş bir zaman aşımı vardır. "Belgelenmemiş e-posta adresinin" aksine, Google tarafından sağlanan gerçek client_id ile benim için iyi çalışıyor. Sadece işleme yeniden başlamam gerekiyordu.

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.