недопустимый грант, пытающийся получить токен oAuth от google

Я продолжаю получать invalid_grant ошибка при попытке получить токен OAuth от Google для подключения к api контактов. Вся информация верна, и я триппл проверил это, так что в тупике.

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

14 ответов


Я столкнулся с этой проблемой, когда я явно не запрашивал "автономный" доступ при отправке пользователя в OAuth "вы хотите дать этому приложению разрешение на прикосновение к вашим вещам?" страница.

убедитесь, что вы указали access_type=offline в своем запросе.

подробности здесь:https://developers.google.com/accounts/docs/OAuth2WebServer#offline

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


я столкнулся с этой же проблемой, несмотря на указание "оффлайн" access_type в моем запросе в соответствии с ответом bonkydog. Короче говоря, я обнаружил, что решение, описанное здесь, сработало для меня:

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

по сути, при добавлении клиента OAuth2 в консоль Google API Google предоставит вам "идентификатор клиента "и" адрес электронной почты "(если вы выберете "webapp" в качестве своего тип клиента.) И, несмотря на вводящие в заблуждение соглашения об именах Google, они ожидают, что вы отправите "адрес электронной почты" как значение client_id параметр при доступе к их API OAuth2.

это применяется при вызове обоих этих URL-адресов:

обратите внимание, что вызов первого URL будет успеха если вы вызываете его с вашим "идентификатором клиента" вместо вашего "адреса электронной почты". Однако использование кода, возвращенного из этого запроса, не будет работать при попытке получить маркер носителя из второго URL-адреса. Вместо этого вы получите сообщение "Error 400" и "invalid_grant".


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

в спецификации OAuth2 "invalid_grant" является своего рода catch-all для всех ошибок, связанных с недопустимыми/истекшими/отозванными токенами (auth grant или refresh token).

для нас проблема была двоякой:

  1. пользователь активно отозвал доступ к нашему приложению
    Имеет смысл, но сделать это через 12 часов после отзыв,Google перестает отправлять сообщение об ошибке в ответ: “error_description” : “Token has been revoked.”
    Это довольно вводит в заблуждение, потому что вы предположите, что сообщение об ошибке существует все время, что не так. Вы можете проверить, имеет ли ваше приложение доступ в страница разрешения приложений.

  2. пользователь сбросил / восстановил свой пароль Google
    В Декабре 2015 Года, Google изменил их поведение по умолчанию так этот сброс пароля для пользователей, не являющихся пользователями Google Apps, автоматически отменит все токены обновления приложений пользователя. При отзыве сообщение об ошибке следует тому же правилу, что и в предыдущем случае, поэтому вы получите "error_description" только в первые 12 часов. Кажется, нет никакого способа узнать, был ли пользователь вручную отозван доступ (intentful) или это произошло из-за сброса пароля (побочный эффект).

помимо них, существует множество других возможностей причины, которые могут вызвать ошибку:

  1. серверные часы / время не синхронизированы
  2. не авторизован для доступа в автономном режиме
  3. Дросселируется Google
  4. использование токенов обновления с истекшим сроком действия
  5. пользователь неактивен в течение 6 месяцев
  6. используйте электронную почту работника службы вместо идентификатора клиента
  7. слишком много доступа токены в короткие сроки
  8. клиент SDK может быть устаревшим
  9. неверный / неполный токен обновления

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


Я столкнулся с той же проблемой. Для меня я исправил это, используя адрес электронной почты (строка, которая заканчивается на ...@developer.gserviceaccount.com) вместо идентификатора клиента для значения параметра client_id. Имя, установленное Google, запутывает здесь.


У меня было такое же сообщение об ошибке "invalid_grant", и это было потому, что authResult ['code'] отправка с клиентской стороны javascript не был получен правильно на сервере.

попробуйте вывести его обратно с сервера, чтобы увидеть, правильно ли это, а не пустая строка.


моя проблема заключалась в том, что я использовал этот URL:

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

когда я должен был использовать этот URL:

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

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


Если вы используете библиотеку scribe, просто настройте автономный режим, как предложил bonkydog вот код:

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

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


используя Android clientId (без client_secret), я получал следующий ответ об ошибке:

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

Я не могу найти документацию для поля "code_verifier", но я обнаружил, что если вы установите для него равные значения в запросах авторизации и токена, он удалит эту ошибку. Я не уверен, какое значение должно быть или должно ли оно быть безопасным. Он имеет некоторую минимальную длину (16? символы), но я нашел параметр null тоже работает.

Я использую AppAuth для запроса авторизации в моем клиенте Android, который имеет :

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

Это глупый ответ, но проблема для меня заключалась в том, что я не понял, что мне уже был выдан активный токен oAuth для моего пользователя google, который я не смог сохранить. Решение в этом случае-перейти в консоль api и сбросить секрет клиента.

есть множество других ответов на SO для этого эффекта, например Reset Client Secret OAuth2-нужно ли клиентам повторно предоставлять доступ?


возможно, вам придется удалить устаревший / недопустимый ответ OAuth.

фото: узел.пример с JS в Google OAuth2, которые перестали работать invalid_grant в

Примечание: ответ OAuth также станет недействительным, если пароль, используемый в первоначальной авторизации, был изменен.

Если в среде bash, вы можете использовать следующее, Чтобы удалить устаревший ответ:

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


есть две основные причины для invalid_grant в ошибка, которую вы должны позаботиться до запроса POST для токена обновления и токена доступа.

  1. заголовок запроса должен содержать "content-type: application / x-www-form-urlencoded"
  2. ваша полезная нагрузка запроса должна быть url-кодированными данными формы, не отправляйте как объект json.

RFC 6749 OAuth 2.0 определена invalid_grant в как: предоставленное разрешение на авторизацию (например, код авторизации, учетные данные владельца ресурса) или токен обновления недействительны, истекли, отозваны, не соответствуют URI перенаправления, используемому в запросе авторизации, или был выдан другому клиенту.

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

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


на этом сайте console.developers.google.com

на этой консоли выберите ваш проект, введите url клятвы. url-адрес обратного вызова oauth будет перенаправлен, когда OAuth success


после рассмотрения и попытки всех других способов здесь, вот как я решил проблему в nodejs с googleapis модуль в сочетании с request модуль, который я использовал для извлечения маркеров вместо предусмотренного 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);
            }
        });

Я просто использовать request чтобы сделать запрос api через HTTP, как описано здесь: 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

попробуйте изменить url-адрес requst на

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