集成Google OAuth实现Gmail登录注册:Web端获取Access Token报错排查
问题
我正在开发一款支持App和Web端的应用,要集成Google OAuth实现Gmail登录/注册,目标获取用户的name、profile_pic、dob、sub等数据。
App端已经用以下代码实现成功:
from google.oauth2 import id_token from google.auth.transport import requests id_info = id_token.verify_oauth2_token(token, requests.Request(), google_client_id) print(id_info['sub'], id_info['email'])
能正常获取所有用户数据。
现在Web端尝试用Google API调用实现:Web端从Google回调请求中拿到code参数,想用code换取access_token,再用令牌获取用户数据,代码如下:
data = { 'code': code, 'client_id': my_client_id, 'client_secret': my_client_secret_key, 'redirect_uri': redirect_uri, 'grant_type': 'authorization_code' } response = requests.post('https://oauth2.googleapis.com/token', data=data) if not response.ok: logger.info('Could not get access token from Google.') return access_token = response.json()['access_token'] response2 = requests.get( 'https://www.googleapis.com/oauth2/v2/userinfo', params={'access_token': access_token} ) return response2.json()
现在用有效access_token能正常获取数据,但用code换access_token时出现错误,要么返回:
{'error': 'invalid_grant', 'error_description': 'Bad Request'}
要么返回:
{'error': 'unauthorized_client', 'error_description': 'Unauthorized'}
已经确认凭证正确,请问哪里出错了?
解决方案
针对你遇到的两个错误,逐个排查:
关于 unauthorized_client 错误
- 核对OAuth客户端类型:Web端必须使用「Web应用」类型的客户端ID,不能复用App端的「Android」或「iOS」客户端ID。去Google Cloud控制台的OAuth 2.0客户端ID页面,确认当前用的client_id属于Web应用类型。
- 检查重定向URI配置:Google Cloud控制台中,Web应用的「已授权的重定向URI」必须和代码里的
redirect_uri完全一致——包括http/https协议、域名、路径,甚至大小写都不能错,多一个斜杠少一个斜杠都会触发错误。 - 确认客户端密钥匹配:确保
my_client_secret_key是当前Web应用客户端ID对应的密钥,不是其他客户端的密钥。
关于 invalid_grant 错误
- code是否重复使用:Google的authorization code只能用一次,用过就失效。如果调试时反复用同一个code测试,或者代码里存在重复请求的逻辑,就会报这个错。
- 检查code时效性:authorization code的有效期只有10分钟,拿到后要立即去换access_token,搁置太久会失效。
- 重定向URI一致性:用户授权时的redirect_uri必须和换token时的
redirect_uri完全相同,哪怕细微差异(比如末尾多了斜杠)都会导致错误。 - 请求参数格式验证:确保post请求是form-data格式,你的代码用
data=data是对的(requests.post默认会把字典转成form-data),但如果之前手动设置了Content-Type: application/json请求头,一定要删掉,否则会触发错误。
另外给个优化建议:Web端其实可以直接用App端类似的id_token验证方式,不用走code换token再拿用户信息的流程,更简单安全。示例代码:
from google.oauth2 import id_token from google.auth.transport import requests # 这里的token是从前端拿到的id_token,不是authorization code id_info = id_token.verify_oauth2_token(token, requests.Request(), google_client_id) # 验证签发方,确保是Google授权服务器 if id_info['iss'] not in ['accounts.google.com', 'https://accounts.google.com']: raise ValueError('非法签发方') # 直接获取用户数据 print(id_info['sub'], id_info['name'], id_info['picture'])
内容的提问来源于stack exchange,提问作者Frid-j
相关产品推荐
相关产品推荐

