web-dev-qa-db-fra.com

invalid_grant essaie d'obtenir le jeton oAuth de Google

Je continue à avoir une erreur invalid_grant en essayant d'obtenir un jeton oAuth de Google pour se connecter à l'API de leurs contacts. Toutes les informations sont correctes et j'ai triplement vérifié cette sorte de perplexité.

Est-ce que quelqu'un sait ce qui peut causer ce problème? J'ai essayé de configurer un identifiant client différent pour celui-ci, mais le résultat est identique. J'ai essayé de connecter plusieurs méthodes, notamment d'essayer l'authentification forcée, mais toujours avec le même résultat.

91
André Figueira

J'ai rencontré ce problème alors que je ne demandais pas explicitement un accès "hors connexion" lors de l'envoi de l'utilisateur à l'OAuth "Voulez-vous donner à cette application la permission de toucher à vos données?" page.

Assurez-vous de spécifier access_type = offline dans votre demande.

Détails ici: https://developers.google.com/accounts/docs/OAuth2WebServer#offline

(En outre: je pense que Google a ajouté cette restriction à la fin de 2011. Si vous possédez d'anciens jetons, vous devez envoyer vos utilisateurs à la page des autorisations pour autoriser leur utilisation hors connexion.)

51
bonkydog

J'ai rencontré ce même problème malgré la spécification du access_type "hors ligne" dans ma demande, conformément à la réponse de bonkydog. En résumé, j'ai trouvé que la solution décrite ici fonctionnait pour moi:

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

En substance, lorsque vous ajoutez un client OAuth2 à la console de votre API Google, Google vous attribue un "ID client" et une "adresse électronique" (en supposant que vous sélectionniez "webapp" comme type de client). Et malgré les conventions de dénomination trompeuses de Google, ils s'attendent à ce que vous envoyiez "Adresse e-mail" en tant que valeur du paramètre client_id lorsque vous accédez à leur API OAuth2. 

Ceci s’applique lors de l’appel de ces deux URL:

Notez que l'appel à la première URL réussira si vous l'appelez avec votre "ID client" au lieu de votre "adresse électronique". Toutefois, l'utilisation du code renvoyé par cette demande ne fonctionnera pas si vous tentez d'obtenir un jeton de support à partir de la deuxième URL. Au lieu de cela, vous obtiendrez un message "Erreur 400" et un message "invalid_grant". 

55
aroth

Bien que ce soit une vieille question, il semble que beaucoup le rencontrent encore - nous avons passé des journées entières à le retrouver nous-mêmes.

Dans la spécification OAuth2, "invalid_grant" est une sorte de solution miracle pour toutes les erreurs liées aux jetons invalides/expirés/révoqués (autorisation d'autorisation ou jeton d'actualisation).

Pour nous, le problème était double: 

  1. L'utilisateur a activement révoqué l'accès à notre application
    Cela a du sens, mais obtenez ceci: 12 heures après la révocation, Google arrête d’envoyer le message d’erreur dans leur réponse: “error_description” : “Token has been revoked.”
    C'est plutôt trompeur parce que vous supposerez que le message d'erreur est toujours présent, ce qui n'est pas le cas. Vous pouvez vérifier si votre application a toujours accès à la page d'autorisation de apps .

  2. L'utilisateur a réinitialisé/récupéré son mot de passe Google
    En décembre 2015, Google a modifié leur comportement par défaut afin que les réinitialisations de mot de passe pour les utilisateurs autres que Google Apps révoquent automatiquement tous les jetons d'actualisation des applications de l'utilisateur. Lors de la révocation, le message d'erreur suit la même règle que précédemment, vous ne recevrez donc que la "description_erreur" au cours des 12 premières heures. Il semble qu'il n'y ait aucun moyen de savoir si l'utilisateur a révoqué manuellement l'accès (intentionnel) ou si cela s'est produit en raison d'une réinitialisation du mot de passe (effet secondaire).

En dehors de ceux-ci, il existe une myriade d'autres causes potentielles pouvant déclencher l'erreur:

  1. L'horloge du serveur/l'heure est désynchronisée
  2. Non autorisé pour un accès hors ligne
  3. Étranglé par Google
  4. Utilisation des jetons d'actualisation expirés
  5. L'utilisateur est inactif depuis 6 mois
  6. Utiliser le courrier électronique du technicien de service au lieu de l'ID client
  7. Trop de jetons d'accès en peu de temps
  8. Le SDK client est peut-être obsolète
  9. Jeton d'actualisation incorrect/incomplet

J'ai écrit un court article résumant chaque élément avec des conseils de débogage pour aider à trouver le coupable. J'espère que ça aide.

41
laander

J'ai rencontré le même problème. Pour moi, j'ai résolu ce problème en utilisant Email Address (la chaîne qui se termine par ... @ developer.gserviceaccount.com) au lieu de l'ID client pour la valeur du paramètre client_id. La dénomination définie par Google est confuse ici.

7
Tony Vu

Mon problème était que j'ai utilisé cette URL:

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

Quand j'aurais dû utiliser cette URL:

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

Il s'agissait de tester un compte de service qui souhaitait un accès hors connexion au Moteur de stockage .

2
Brad Lee

J'avais le même message d'erreur 'invalid_grant' et c'était parce que l'envoi authResult ['code'] Du côté client javascript n'a pas été reçu correctement sur le serveur. 

Essayez de le sortir du serveur pour voir s'il est correct et non une chaîne vide.

2
Mihai Crăiță

Vous devrez peut-être supprimer une réponse OAuth périmée/non valide. 

Credit: node.js google oauth2 Exemple arrêté de fonctionner invalid_grant

Note: une réponse OAuth deviendra également invalide si le mot de passe utilisé dans l'autorisation initiale a été modifié.

Si vous vous trouvez dans un environnement bash, vous pouvez utiliser les éléments suivants pour supprimer la réponse périmée:

rm /Users/<username>/.credentials/<authorization.json>

1
Lindauson

Il y a deux raisons principales de l'erreur invalid_grant que vous devez prendre en compte avant la demande POST pour l'actualisation du jeton et du jeton d'accès.

  1. L'en-tête de demande doit contenir "content-type: application/x-www-form-urlencoded"
  2. Le contenu de votre demande doit être en données de formulaire codées en url. Ne l'envoyez pas en tant qu'objet json.

RFC 6749 OAuth 2.0 défini invalid_grant en tant que: L'autorisation d'autorisation fournie (par exemple, code d'autorisation, informations d'identification du propriétaire de la ressource) ou le jeton d'actualisation est non valide, expiré, révoqué, ne correspond pas à la redirection L'URI utilisé dans la demande d'autorisation ou a été attribué à un autre client.

J'ai trouvé un autre bon article, ici vous trouverez beaucoup d'autres raisons pour cette erreur.

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

1
Hisham Javed

C'est une réponse idiote, mais le problème pour moi était que je n'avais pas réalisé que j'avais déjà reçu un jeton oAuth actif pour mon utilisateur Google que je n'avais pas stocké. Dans ce cas, la solution consiste à accéder à la console de l’API et à réinitialiser le secret du client.

Il existe de nombreuses autres réponses sur SO à cet effet, par exemple Reset Client Secret OAuth2 - Les clients doivent-ils autoriser à nouveau l'accès?

1
paul

si vous utilisez la bibliothèque scribe, configurez simplement le mode hors connexion, comme suggéré par bonkydog voici le code: 

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
Oleksii Kyslytsyn

En utilisant un clientId Android (pas de client_secret) je recevais la réponse d'erreur suivante:

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

Je ne trouve aucune documentation pour le champ 'code_verifier', mais j'ai découvert que si vous le définissez comme valeur égale dans les demandes d'autorisation et de jeton, cette erreur sera supprimée. Je ne suis pas sûr de ce que la valeur prévue devrait être ou si elle devrait être sécurisée. Il a une longueur minimale (16? Caractères) mais je trouve que le réglage sur null fonctionne également.

J'utilise AppAuth pour la demande d'autorisation dans mon client Android, qui possède une fonction setCodeVerifier().

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

Voici un exemple de demande de jeton dans le noeud:

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

J'ai testé et cela fonctionne à la fois avec https://www.googleapis.com/oauth2/v4/token et https://accounts.google.com/o/oauth2/token.

Si vous utilisez plutôt GoogleAuthorizationCodeTokenRequest:

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

Essayez de changer votre URL pour demander à 

https://www.googleapis.com/oauth2/v4/token
0
Sergiy Voytovych

Dans mon cas, le problème était dans mon code. Par erreur, j'ai essayé d'initier le client 2 fois avec les mêmes jetons. Si aucune des réponses ci-dessus ne vous a aidé, assurez-vous de ne pas générer 2 instances du client.

Mon code avant le correctif:

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)

dès que je le change en (utilisez une seule instance):

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

il a corrigé mes problèmes avec le type de subvention.

0
Kate Kasinskaya

dans ce site console.developers.google.com

cette console sélectionne votre projet saisissez l'url du serment . l'url de rappel de oauth sera redirigé lorsque le succès de oauth

0
user5699596

J'ai rencontré ce problème après avoir activé une nouvelle API de service sur la console Google et essayé d'utiliser les informations d'identification précédemment fournies.

Pour résoudre le problème, je devais revenir à la page d'informations d'identification, en cliquant sur le nom des informations d'identification, puis en cliquant sur "Enregistrer" encore. Après cela, je pourrais très bien m'authentifier.

0
kimphamg

Pour les futurs gens ... J'ai lu de nombreux articles et blogs mais j'ai eu de la chance avec la solution ci-dessous ...

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

This blog décrit différents cas dans lesquels l'erreur "invalid_grant" survient.

Prendre plaisir!!!

0
Kanishk Gupta

Après avoir examiné et essayé toutes les autres méthodes ici, voici comment j'ai résolu le problème dans nodejs avec le module googleapis en conjonction avec le module request, que j'avais l'habitude de récupérer les jetons au lieu de la méthode getToken() fournie:

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

J'utilise simplement request pour effectuer la demande d'api via HTTP, comme décrit ici: 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
lwdthe1

pour moi, je devais m'assurer que le redirect_uri correspond exactement à celui de la console du développeur Authorised redirect URIs, qui l'a corrigé pour moi, j'ai pu déboguer et savoir exactement quel était le problème après avoir basculé de https://accounts.google.com/o/oauth2/token à https://www.googleapis.com/oauth2/v4/token

J'ai eu une erreur correcte:

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

Pour moi, le problème était que j'avais plusieurs clients dans mon projet et je suis assez sûr que tout va bien, mais j'ai supprimé tous les clients pour ce projet et en ai créé un nouveau et tous ont commencé à travailler pour moi (J'ai eu cette idée pour l'aide du plugin WP_SMTP forum de support) Je ne parviens pas à trouver ce lien pour référence

0
Subrata Fouzdar