166

invalid_grantGoogle から oAuth トークンを取得して連絡先 API に接続しようとすると、エラーが発生し続けます。すべての情報は正しいので、私はこれをトリプルチェックしました。

この問題の原因を知っている人はいますか? 別のクライアントIDを設定しようとしましたが、同じ結果が得られました。強制認証を試すなど、さまざまな方法で接続しようとしましたが、それでも同じ結果です。

4

29 に答える 29

106
于 2016-07-18T10:08:28.633 に答える
79

access_typebonkydog の回答に従って、リクエストで「オフライン」を指定したにもかかわらず、この同じ問題に遭遇しました。簡単に言えば、ここで説明されている解決策がうまくいったことがわかりました。

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

基本的に、Google API のコンソールに OAuth2 クライアントを追加すると、Google から「クライアント ID」と「メール アドレス」が提供されます (クライアント タイプとして「webapp」を選択した場合)。client_idまた、Google の誤解を招く命名規則にもかかわらず、Google は、OAuth2 API にアクセスするときにパラメーター の値として「メール アドレス」を送信することを期待しています。

これは、次の URL の両方を呼び出す場合に適用されます。

最初の URL の呼び出しは、「メール アドレス」の代わりに「クライアント ID」を使用して呼び出した場合に成功することに注意してください。ただし、2 番目の URL からベアラー トークンを取得しようとすると、その要求から返されたコードを使用しても機能しません。代わりに、「エラー 400」と「invalid_grant」メッセージが表示されます。

于 2013-09-27T00:51:07.070 に答える
70

ユーザーを OAuth に送信するときに「オフライン」アクセスを明示的に要求しなかったときに、この問題に遭遇しました。ページ。

リクエストで必ず access_type=offline を指定してください。

詳細はこちら: https://developers.google.com/accounts/docs/OAuth2WebServer#offline

(また、Google は 2011 年後半にこの制限を追加したと思います。それ以前の古いトークンをお持ちの場合は、オフラインでの使用を承認するためにユーザーを許可ページに送る必要があります。)

于 2012-05-14T21:57:24.390 に答える
5

私の問題は、次の URL を使用したことです。

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

この URL を使用する必要があった場合:

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

これは、ストレージ エンジンへのオフライン アクセスを必要とするサービス アカウントをテストしていました。

于 2016-01-12T16:55:21.977 に答える
5

これはばかげた答えですが、私にとっての問題は、保存に失敗した Google ユーザーのアクティブな oAuth トークンが既に発行されていることに気付かなかったことです。この場合の解決策は、API コンソールに移動してクライアント シークレットをリセットすることです。

SO には他にも多数の回答があります。たとえば、 クライアント シークレットのリセット OAuth2 - クライアントはアクセスを再許可する必要がありますか?

于 2017-04-10T16:40:21.250 に答える
4

Android clientId (client_secret なし) を使用すると、次のエラー応答が返されました。

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

フィールド 'code_verifier' に関するドキュメントは見つかりませんでしたが、承認リクエストとトークン リクエストの両方で同じ値に設定すると、このエラーが解消されることがわかりました。意図した値がどうあるべきか、それが安全であるべきかどうかはわかりません。最小の長さ (16? 文字) がありますが、 に設定してnullも機能することがわかりました。

関数を持つ Android クライアントでの承認要求に AppAuth を使用してい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();
于 2017-03-30T00:35:15.577 に答える
2

ユーザーの同意後に URL で取得したコードの有効期限は非常に短いです。もう一度コードを取得して、数秒以内にアクセス トークンを取得してみてください (急いでください)。動作するはずです。コードの有効期限はわかりませんが、文字通り非常に短いです。

于 2021-01-26T09:08:12.127 に答える
1

ここで他のすべての方法を検討して試した後、提供されたメソッドの代わりにトークンをフェッチするために使用した、モジュールgoogleapisと組み合わせてモジュールを使用して nodejs で問題を解決した方法を次に示します。requestgetToken()

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ここで説明されているように、HTTP 経由で API リクエストを作成するために 使用するだけです: 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
于 2017-01-04T11:25:12.917 に答える
1

このサイトで console.developers.google.com

このコンソール ボードは、あなたのプロジェクトを選択し、誓いの URL を入力します。oauth が成功すると、oauth コールバック URL がリダイレクトされます。

于 2016-01-14T01:05:52.170 に答える
1

私の場合、問題は私のコードにありました。誤って、同じトークンでクライアントを 2 回開始しようとしました。上記の回答のいずれも役に立たなかった場合は、クライアントのインスタンスを 2 つ生成しないようにしてください。

修正前の私のコード:

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)

変更するとすぐに(インスタンスを1つだけ使用します):

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

付与タイプに関する問題を修正しました。

于 2019-07-26T11:58:57.557 に答える