Gmail登录获取access_token返回invalid_grant Bad Request错误求助
接入Gmail第三方登录调用谷歌OAuth令牌接口时返回400状态码,响应体如下:
{ "error": "invalid_grant", "error_description": "Bad Request" }
重定向URI完全不匹配
谷歌OAuth对redirect_uri做精确字符串校验,三个环节的地址必须逐字符完全一致:发起授权跳转时传的redirect_uri、调用令牌接口时传的redirect_uri、谷歌云控制台「已授权重定向URI」列表里配置的地址。协议(http/https)、域名、端口、路径、末尾斜杠、携带的查询参数任意一处不一致,都会直接触发该错误。不要对令牌接口传入的redirect_uri做额外URL编码,传原始字符串即可。授权码失效
谷歌返回的授权码有效期仅10分钟,且仅能使用1次,使用后立刻作废。授权码超时、重复调用令牌接口、用户在授权页停留过久才确认授权,都会导致code失效触发错误。请求格式不符合要求
谷歌令牌接口仅接受application/x-www-form-urlencoded格式的参数,不支持JSON格式传参。当前代码直接将参数数组赋值给$request->body,大概率是HTTP客户端默认用了错误的Content-Type(比如multipart/form-data或application/json),或者参数格式不对。
修正后的代码参考:protected function getAccessToken($code) { $request = new \XLite\Core\HTTP\Request(static::TOKEN_REQUEST_URL); // 明确指定请求头 $request->setHeader('Content-Type', 'application/x-www-form-urlencoded'); // 拼接为form格式参数 $request->body = http_build_query([ 'code' => $code, 'client_id' => $this->getClientId(), 'client_secret' => $this->getClientSecret(), 'redirect_uri' => $this->getRedirectUrl(), 'grant_type' => 'authorization_code', ]); $response = $request->sendRequest(); $accessToken = null; if (200 == $response->code) { $data = json_decode($response->body, true); $accessToken = $data['access_token']; } else { // 补充错误日志,方便定位问题 \XLite\Logger::logCustom('google_oauth', [ 'request_params' => [ 'code' => $code, 'client_id' => $this->getClientId(), 'redirect_uri' => $this->getRedirectUrl() ], 'response_code' => $response->code, 'response_body' => $response->body ]); } return $accessToken; }客户端凭证错误
核对代码中配置的client_id、client_secret和谷歌云控制台生成的凭证完全一致,注意不同客户端类型(Web应用、安卓、iOS、桌面端)的凭证不通用,不要混用;如果近期重置过客户端密钥,需要同步更新代码配置。
- 打印发起授权、换token两个环节的
redirect_uri,逐字符和谷歌云后台配置的地址做对比 - 走完整授权流程,拿到code后立刻发起换token请求,不要做等待、不要重复触发请求
- 抓包确认换token请求的Content-Type、参数格式是否符合要求
- 核对客户端ID、密钥配置是否正确
内容的提问来源于stack exchange,提问作者Saeed Rehman

