it-swarm.com.ru

invalid_grant пытается получить токен oAuth от Google

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

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

91
André Figueira

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

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

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

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

51
bonkydog

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

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

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

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

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

55
aroth

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

В спецификации OAuth2 «invalid_grant» является своего рода универсальным средством для всех ошибок, связанных с недействительными/просроченными/отозванными токенами (аутентификационное предоставление или обновление токена).

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

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

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

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

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

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

41
laander

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

7
Tony Vu

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

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

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

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

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

2
Brad Lee

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

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

2
Mihai Crăiță

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

Credit: node.js пример google oauth2 перестал работать invalid_grant

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

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

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

1
Lindauson

Существуют две основные причины ошибки 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

1
Hisham Javed

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

SO есть множество других ответов на этот вопрос, например Сброс секрета клиента OAuth2 - Нужно ли клиентам повторно предоставлять доступ?

1
paul

если вы используете библиотеку 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/

1
Oleksii Kyslytsyn

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

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

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

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

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

Вот пример запроса токена в узле:

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

Я проверил, и это работает с https://www.googleapis.com/oauth2/v4/token и https://accounts.google.com/o/oauth2/token.

Если вы используете вместо этого 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

Попробуйте изменить ваш URL для запроса 

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

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

эта консольная панель выберите ваш проект, введите URL-адрес присяги . URL-адрес обратного вызова oauth будет перенаправлен при успешном выполнении oauth

0
user5699596

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

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

Это блог описывает различные случаи, когда возникает ошибка "invalid_grant".

Наслаждаться!!!

0
Kanishk Gupta

После рассмотрения и опробования всех других способов здесь, вот как я решил проблему в 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
0
lwdthe1

для меня я должен был убедиться, что redirect_uri точно соответствует тому, что в консоли разработчика Authorised redirect URIs, который исправил это для меня, я смог отладить и знать, в чем именно заключалась проблема после переключения с https://accounts.google.com/o/oauth2/token на https://www.googleapis.com/oauth2/v4/token

Я получил правильную ошибку:

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