我一直invalid_grant
在尝试从Google获取oAuth令牌以连接到其联系人api时遇到错误。所有的信息都是正确的,我已经三联检查过这种情况。
有谁知道是什么原因导致此问题?我尝试为其设置不同的客户端ID,但得到的结果相同,我尝试连接许多不同的方法,包括尝试强制身份验证,但结果仍然相同。
我一直invalid_grant
在尝试从Google获取oAuth令牌以连接到其联系人api时遇到错误。所有的信息都是正确的,我已经三联检查过这种情况。
有谁知道是什么原因导致此问题?我尝试为其设置不同的客户端ID,但得到的结果相同,我尝试连接许多不同的方法,包括尝试强制身份验证,但结果仍然相同。
Answers:
当我向用户发送OAuth时没有明确请求“脱机”访问时,我遇到了这个问题。“您是否要授予此应用触摸内容的权限?” 页。
确保在请求中指定access_type = offline。
此处的详细信息:https : //developers.google.com/accounts/docs/OAuth2WebServer#offline
(此外:我认为Google在2011年末增加了此限制。如果您之前拥有旧令牌,则需要将用户发送到权限页面以授权离线使用。)
access_type
为offline
,此错误仍然会发生。
尽管access_type
按照bonkydog的回答在请求中指定了“离线” ,但我还是遇到了同样的问题。长话短说,我发现这里描述的解决方案对我有用:
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的调用将成功。但是,尝试从第二个URL获取承载令牌时,无法使用从该请求返回的代码。相反,您会收到“错误400”和“ invalid_grant”消息。
尽管这是一个古老的问题,但似乎仍有很多人遇到了我们-我们花了数天的时间自己追踪这个问题。
在OAuth2规范中,“ invalid_grant”是针对与无效/过期/吊销的令牌(身份验证授权或刷新令牌)相关的所有错误的综合解决方案。
对于我们来说,问题有两个:
用户主动撤消了对我们应用的访问这样
做是有道理的,但是请注意:撤消12小时后,Google停止在其响应中发送错误消息:
“error_description” : “Token has been revoked.”
这很容易引起误解,因为您会假设错误消息一直存在案子。您可以在“ 应用程序权限”页面上检查您的应用程序是否仍然具有访问权限。
用户已重置/恢复了自己的Google密码
2015年12月,Google更改了默认行为,以便为非Google Apps用户重置密码会自动撤消所有用户的应用刷新令牌。吊销后,错误消息将遵循与以前相同的规则,因此您只会在前12小时内收到“ error_description”。似乎没有任何方法可以知道用户是手动撤消了访问(故意的)还是由于密码重置而发生了(副作用)。
除此之外,还有许多其他可能导致错误的潜在原因:
我写了一篇简短的文章,对每个项目进行了概述,并提供了一些调试指导,以帮助找到罪魁祸首。希望能帮助到你。
我有相同的错误消息'invalid_grant',这是因为 从客户端javascript发送的 authResult ['code']未在服务器上正确接收。
尝试将其从服务器输出回去,以查看它是否正确而不是空字符串。
如果您使用的是抄写员库,则只需设置脱机模式,例如bonkydog,建议代码如下:
OAuthService service = new ServiceBuilder().provider(Google2Api.class).apiKey(clientId).apiSecret(apiSecret)
.callback(callbackUrl).scope(SCOPE).offline(true)
.build();
使用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();
这是一个愚蠢的答案,但是对我来说,问题是我未能意识到自己已经为我的Google用户获得了有效的oAuth令牌,但我未能对其进行存储。在这种情况下,解决方案是转到api控制台并重置客户端密码。
SO上还有许多其他答案可以解决此问题,例如, 重置客户端密钥OAuth2-客户端是否需要重新授予访问权限?
您可能必须删除陈旧/无效的OAuth响应。
信用:node.js谷歌oauth2示例停止工作invalid_grant
注意:如果更改了初始授权中使用的密码,OAuth响应也将变为无效。
如果在bash环境中,则可以使用以下命令来删除过时的响应:
rm /Users/<username>/.credentials/<authorization.json>
无效_授予错误有两个主要原因,在对刷新令牌和访问令牌进行POST请求之前,您必须要小心。
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。oauth成功时,oauth回调URL将重定向
在考虑并尝试了所有其他方式之后,下面是我如何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
对于未来的人们...我阅读了许多文章和博客,但在下面的解决方案方面很幸运...
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”错误的不同情况。
请享用!!!
就我而言,问题出在我的代码中。错误地,我尝试使用相同的令牌启动客户端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)
我将其更改为(仅使用一个实例)后:
@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)
它解决了我与赠款类型有关的问题。
对我来说,问题是我的项目中有多个客户端,我可以肯定这是完全可以的,但是我删除了该项目的所有客户端,并创建了一个新客户端,所有这些客户端都开始为我工作(WP_SMTP插件帮助了支持论坛)我无法找到该链接以供参考
首先,您需要一个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控制台中的域中:“ OAuth 2.0-Client-IDs”标签中的https://console.cloud.google.com/apis/credentials。您还可以在其中找到您的客户ID和客户秘密。
如果您要在邮递员/失眠症患者中进行测试,并且只是想使其正常运行,则提示:服务器身份验证代码(代码参数)只可以使用一次。这意味着,如果您在请求中填充其他任何参数并取回400,则需要使用新的服务器身份验证代码,否则将仅获得400。