Google OAuth2获取的Access Token无法解码问题及相关咨询
Google OAuth2获取的Access Token无法解码(段数不足)问题排查
我在实现Google OAuth2功能时,从token_endpoint拿到的access token用JWT解码时报错“段数不足”。虽然这个token能正常调用Google API,但它本身不包含用户数据,也无法解码。想知道问题出在哪,以及如何获取能提取用户信息的有效token。
使用的配置和端点
import os GOOGLE_CLIENT_ID = os.getenv("GOOGLE_CLIENT_ID") GOOGLE_SECRET = os.getenv("GOOGLE_SECRET") GOOGLE_URL = "https://accounts.google.com/o/oauth2/v2/auth?" GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token?" GOOGLE_SCOPE = "openid" GOOGLE_REDIRECT_URI = "http://localhost:8050/google-callback"
获取Access Token的代码
from urllib.parse import urlparse, parse_qs import requests AUTHORIZATION_CODE = "authorization_code" def get_access_token(url: str, token_url: str, client_id: str, redirect_uri, client_secret=None) -> str: """Calls the oauth server and gets the access token based on the code""" query_params = urlparse(url).query code = parse_qs(query_params)['code'][0] body = { "client_id": client_id, "grant_type": AUTHORIZATION_CODE, "code": code, "redirect_uri": redirect_uri } if client_secret is not None: body['client_secret'] = client_secret response = requests.post(url=token_url, data=body) access_token = response.json()['access_token'] return access_token
回调函数中解码Token的代码
from flask import request import jwt @server.route("/google-callback") def google_callback_route(): access_token = get_access_token(request.full_path, GOOGLE_TOKEN_URL, GOOGLE_CLIENT_ID, GOOGLE_REDIRECT_URI, GOOGLE_SECRET) decoded_token = jwt.decode(options={'verify_signature': False}, jwt=access_token, algorithms=["RS256"]) print(decoded_token)
获取到的Access Token示例
ya29.a0Ad52N3-2qdB7R3aueWNS9suZOnhInzqQnQqG1z6fYMYkZEkc3rPgdE4haXIJqP8DF-oEwvQiYAx7c8jx3JTyC6FQo9aSnz6dl9EPxUq3q4dUd9p8gYPIApLpoqN7CZlo0y5wIJI6-gaDzHZa8-ZULqq9ypgbAWrJ7waCgYKAdgSARISFQHGX2Mi0edxqQO-szLpEjKt-LrQ6Q0169
问题原因与解决方案
1. 为什么这个Access Token无法解码
你拿到的ya29.xxx开头的是Google的不透明Access Token,它不是JWT格式,只是一个授权凭证字符串,本身不包含任何用户信息,自然无法用JWT解码工具解析(JWT需要三段式结构,而这个token没有分隔符)。它的作用是作为身份凭证调用Google的各类API,但不能直接提取用户数据。
2. 如何获取可提取用户信息的Token
要获取包含用户信息的可解码Token,需要使用OpenID Connect流程(你已经加了openid scope,但还需要调整细节):
- 调整授权Scope:在
GOOGLE_SCOPE中添加需要的用户信息权限,比如email、profile:GOOGLE_SCOPE = "openid email profile" - 获取ID Token:调用token_endpoint时,响应中除了
access_token,还会返回id_token字段,这个id_token是标准JWT格式,可以解码出用户的邮箱、姓名等信息。修改get_access_token函数返回id_token:def get_access_token(url: str, token_url: str, client_id: str, redirect_uri, client_secret=None): # ... 现有代码不变 response_data = response.json() return response_data['access_token'], response_data['id_token'] - 解码ID Token:在回调函数中解码
id_token而不是access_token:@server.route("/google-callback") def google_callback_route(): access_token, id_token = get_access_token(request.full_path, GOOGLE_TOKEN_URL, GOOGLE_CLIENT_ID, GOOGLE_REDIRECT_URI, GOOGLE_SECRET) # 生产环境请开启签名验证,使用Google公钥验证token合法性 decoded_token = jwt.decode(options={'verify_signature': False}, jwt=id_token, algorithms=["RS256"]) print(decoded_token) # 这里会输出用户的邮箱、姓名、sub(唯一标识)等信息
3. 生产环境注意事项
不要关闭verify_signature选项,应该通过Google的公开密钥端点获取公钥,验证id_token的签名,确保token是由Google官方签发,避免伪造。
内容的提问来源于stack exchange,提问作者0xJanAbe
相关产品推荐
相关产品推荐

