
google 登录返回的 id token 是经过签名的 jwt,服务端无需调用 oauth2 交换流程,而应直接验证并解析该令牌以获取用户资料。
google 登录返回的 id token 是经过签名的 jwt,服务端无需调用 oauth2 交换流程,而应直接验证并解析该令牌以获取用户资料。
在使用 Google Sign-In 的 Web 应用中,前端通过 googleUser.getAuthResponse().id_token 获取到的是一个 ID Token(JWT 格式),而非授权码(authorization code)或访问令牌(access token)。你的服务端代码错误地将 ID Token 当作 code 传入 conf.Exchange(),导致 Google OAuth2 端点返回 invalid_grant 错误——因为 Exchange() 仅接受一次性授权码,不接受已签发的 ID Token。
✅ 正确做法是:跳过 OAuth2 令牌交换,直接验证并解析 ID Token。ID Token 本身已包含经 Google 签名认证的用户身份信息(如 sub、email、name、picture 等),只要完成以下三步即可安全提取:
- 验证签名:使用 Google 提供的公钥(JWKS)验证 JWT 签名有效性;
-
校验声明(Claims):确认
iss == "https://accounts.google.com"、aud匹配你的 Client ID、exp未过期、iat合理; - 解析载荷(Payload):解码 Base64Url 编码的 payload,获取用户信息。
以下是 Go 服务端推荐实现(使用 github.com/golang-jwt/jwt/v5 + Google JWKS):
通过 Gemini 搜索落地(主)和 Custom Search JSON API(备)进行 Google 网页搜索。用途:(1) 附引用的综合回答(落地搜索),(2) 含摘要的原始链接结果,(3) 图片搜索。希伯来语支持极佳。优于内置 web_search (Perplexity)。
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"github.com/golang-jwt/jwt/v5"
"golang.org/x/oauth2/google"
)
// Google ID Token 验证器(含 JWKS 自动刷新)
var googleKeySet = jwt.NewCachingKeySet(
google.KeysURL,
jwt.WithRefreshInterval(24*time.Hour),
)
func verifyGoogleIDToken(ctx context.Context, idToken string) (*jwt.Token, error) {
token, err := jwt.Parse(idToken, googleKeySet.KeyFunc)
if err != nil {
return nil, fmt.Errorf("failed to parse token: %w", err)
}
if !token.Valid {
return nil, fmt.Errorf("token is invalid")
}
// 检查标准声明
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
return nil, fmt.Errorf("invalid claims format")
}
if iss, ok := claims["iss"]; !ok || iss != "https://accounts.google.com" {
return nil, fmt.Errorf("invalid issuer")
}
if aud, ok := claims["aud"]; !ok || aud != "YOUR_CLIENT_ID.apps.googleusercontent.com" {
return nil, fmt.Errorf("invalid audience")
}
if exp, ok := claims["exp"]; !ok || int64(exp.(float64)) <p>⚠️ 注意事项:</p>
-
绝不将
id_token传给conf.Exchange():该方法专用于code → token流程,ID Token 是终端凭证,非交换输入; -
必须验证签名和关键声明:防止伪造令牌(如篡改
aud或exp); -
Client ID 必须严格匹配:
aud字段需与服务端配置的 Google OAuth2 Client ID 完全一致; -
前端应禁用
response_type=id_token(隐式流):现代应用推荐使用response_type=code+ PKCE(更安全),但若沿用id_token,确保前端调用getAuthResponse().id_token且未被篡改; -
JWT 库版本兼容性:使用
jwt/v5(非 v3/v4),因其对 Google JWKS 和kid处理更健壮。
总结:ID Token 不是“需要兑换的票据”,而是“已签发的身份证书”。服务端职责是验证其真实性与完整性,而非二次请求 Google API。这不仅避免了额外网络开销和潜在的 invalid_grant 错误,也符合 OIDC 规范的最佳实践。










