invalid_grantがGoogleからoAuthトークンを取得しようとしています


120

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

誰かがこの問題を引き起こしている可能性があることを知っていますか?別のクライアントIDを設定しようとしましたが、同じ結果が得られました。強制認証など、さまざまな方法で接続しようとしましたが、結果は同じです。


私にとっての問題はgoogleの認証情報ページにありました...別のページを作成しました...そして問題を解決しました...
costamatrix

回答:


59

ユーザーをOAuthに送るときに「オフライン」アクセスを明示的に要求しなかったときに、この問題に遭遇しました。「このアプリに、自分のアイテムにアクセスする許可を与えますか?」ページ。

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

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

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


9
@アダーズ同意する。に設定access_typeしてもoffline、このエラーはまだ発生します。
slideshowp2

これは受け入れられる答えではありません。
Kishan Solanki

このdeveloper.google.com/android-publisher/authorizationのドキュメントに目を通し、実装するすべてを読みます
Kishan Solanki

70

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

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

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

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

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


66
まったくばかげています:特に、初期更新トークンを取得した場合にclient_idと連動する部分。GoogleのAPIとそのドキュメントはめちゃくちゃです。
Traubenfuchs 2015年

7
私はこの問題に何時間も頭をぶつけていました。「client_id」が「client_id」フィールドに期待されたものと異なることを期待していませんでした。あなたがrefresh_tokenを取得してそれが機能する時折の時間を除いて。私が現時点でグーグルのために持っている言葉はSOで言うことができないことをかなり確信してください。
ジャスティン

6
こんにちは。私はあなたたちが話している「メール」アドレスを見つけることができません。これは私のコンソールにあるものです-> pbs.twimg.com/media/CVVcEBWUwAAIiCy.png:large
omarojo

4
そのメールアドレスはどこにありますか?私は同じ問題を抱えています
Haro

4
Googleのドキュメントを信頼しないでください。CrapiestのドキュメントとAPIは、世界で最も価値のある会社であるGoogleから提供されています。Google APIを使用するには数え切れないほどの時間を費やさなければなりませんでした。さまざまな依存関係の問題などが原因で、さまざまなAPIの独自の.Netライブラリが一緒にコンパイルされないという問題が次々に発生しました。コードは現在、ほとんどのユーザーに適していますが、特定の理由なく、invalid_grant、invalid_credentialsなどを取得するユーザーもいます。
アレンキング

56

これは古い質問ですが、まだ多くの人が遭遇しているようです。私たちは自分でこれを追跡するのに何日も費やしました。

OAuth2仕様では、「invalid_grant」は、無効/期限切れ/取り消されたトークン(認証付与トークンまたは更新トークン)に関連するすべてのエラーのキャッチオールです。

私たちにとって、問題は2つありました。

  1. ユーザーがアプリへのアクセスを積極的に取り消した
    が理にかなっているが、これを取得する:取り消しの12時間後、Googleは応答でエラーメッセージの 送信を停止し“error_description” : “Token has been revoked.”
    ます。ケース。アプリのアクセス許可ページで、アプリがまだアクセスできるかどうかを確認できます

  2. ユーザーがGoogleパスワードをリセット/回復した
    2015年12月、Googleはデフォルトの動作を変更し、Google Appsを使用していないユーザーのパスワードをリセットすると、ユーザーのすべてのアプリの更新トークンが自動的に取り消されるようになりました。失効時、エラーメッセージは前のケースと同じルールに従うため、最初の12時間でのみ「error_description」が取得されます。ユーザーが手動でアクセスを取り消したか(意図的)、またはパスワードのリセットが原因で発生したか(副作用)を知る方法はないようです。

それらとは別に、エラーをトリガーする可能性のある他の無数の潜在的な原因があります。

  1. サーバーのクロック/時刻が同期していません
  2. オフラインアクセスは許可されていません
  3. グーグルによるスロットル
  4. 期限切れの更新トークンの使用
  5. ユーザーは6か月間非アクティブでした
  6. クライアントIDの代わりにサービスワーカーのメールを使用する
  7. 短時間でアクセストークンが多すぎる
  8. クライアントSDKが古い可能性があります
  9. 正しくない/不完全な更新トークン

犯人を見つけるのに役立つデバッグガイダンスとともに各項目を要約した短い記事を書きました。それが役に立てば幸い。


1
別のシナリオは、同じ認証コードから複数回トークンを取得しようとした場合です。
Knowasilya 2016

それはまさに私の問題でした、単に偶然にアプリを取り消すだけです。次に、ターミナルを通じてrefreshToken.phpを再実行して、別の認証コードを生成し、このclientIDのすべての場所でrefreshTokenを置き換える必要がありました。
ロバート・シンクレア、

7

同じ問題が発生しました。私は、client_idパラメータ値のクライアントIDではなく、電子メールアドレス(... @ developer.gserviceaccount.comで終わる文字列)を使用してこれを修正しました。Googleが設定した命名は、ここでは混乱しています。


6
これは1年以上前の@arothの回答と同じです
ブライアンアッシュ

3

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

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

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

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

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


2

同じエラーメッセージ「invalid_grant」がありましたが、それはauthResult ['code']が原因でした 、クライアント側のJavaScriptから送信されがサーバーで正しく受信されなかったためです。

それをサーバーから出力して、空の文字列ではなく、正しいかどうかを確認してください。



1

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

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

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

setCodeVerifier()機能のあるAndroidクライアントの承認リクエストにAppAuthを使用しています。

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

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

たとえば、 クライアントシークレットOAuth2をリセットする-クライアントはアクセスを再度許可する必要がありますか?



1

リフレッシュトークンとアクセストークンのPOSTリクエストの前に注意する必要があるinvalid_grantエラーの主な理由は2つあります。

  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


ほぼ同じ2つの回答を投稿するつもりでしたか?他の行に追加の行があるため、これを削除したい場合があります。
高炉2017


0

ここで他のすべての方法を検討して試した後、googleapisモジュールと組み合わせてrequestモジュールを使用してnodejsの問題を解決した方法を次に示します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ここで説明するように、私は単に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


0

将来の人々のために...私は多くの記事やブログを読みましたが、以下の解決策で運が良かった...

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

私にとってredirect_uriは、これが開発者コンソールのAuthorised redirect URIsそれと完全に一致していることを確認する必要がありました。それによって修正されました。デバッグして、に切り替えた後、問題を正確に知ることができまし https://accounts.google.com/o/oauth2/tokenhttps://www.googleapis.com/oauth2/v4/token

私は適切なエラーを受け取りました:

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

0

Googleコンソールで新しいサービスAPIを有効にし、以前に作成した認証情報を使用しようとした後、この問題が発生しました。

この問題を解決するには、認証情報ページに戻り、認証情報名をクリックして、もう一度 [保存]をクリックする必要がありました。その後、問題なく認証できました。


0

私の場合、問題は私のコードにありました。誤って、同じトークンでクライアントを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)

助成金の種類に関する私の問題を修正しました。


0

私にとって問題は、プロジェクトに複数のクライアントがあり、これで問題がないことを確信していますが、そのプロジェクトのすべてのクライアントを削除して新しいクライアントを作成し、すべてが私のために機能し始めました(WP_SMTPプラグインのヘルプからこのアイデアを得ました)サポートフォーラム)参照用のリンクを見つけることができません


0

ユーザー入力($_GET["code"]phpなど)をサニタイズしている場合は、コード内の何かを誤って置き換えないようにしてください。

私が使用している正規表現は今です /[^A-Za-z0-9\/-]/


0

これを見てくださいhttps://dev.to/risafj/beginner-s-guide-to-oauth-understanding-access-tokens-and-authorization-codes-2988

まず、access_tokenが必要です。

$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;

データベース内のアクセストークン、更新トークン、およびexpire_inを保護します。アクセストークンは$ expires_in秒後に期限切れになります。次のリクエストを使用して、新しいアクセストークンを取得する(そしてデータベースで安全にする)必要があります。

$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ドメインをGoogleコンソールのドメインに追加してください:https : //console.cloud.google.com/apis/credentialsタブの「OAuth 2.0-Client-IDs」。そこには、クライアントIDとクライアントシークレットもあります。


0

ユーザーを最初にGoogle認証ページにリダイレクトして(そしてコードを取得して)から、返されたコードを取得してトークンのURLに投稿するまでの間に、文書化されていないタイムアウトがあります。「ドキュメント化されていないメールアドレス」ではなく、実際にGoogleが提供するclient_idを使用すると、問題なく動作します。プロセスをもう一度開始する必要がありました。


0

これを郵便配達員/不眠症でテストしていて、それを機能させようとしているだけの場合、ヒント:サーバー認証コード(コードパラメータ)は1回だけ有効です。リクエストの他のパラメーターを詰め込んで400を取得した場合、新しいサーバー認証コードを使用する必要があります。そうしないと、さらに400が取得されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.