You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Go中解析Google OAuth 2.0返回的JWT Token?

问题解决:Go后端正确解析并验证Google ID Token

核心问题分析

你遇到的两个问题根源在于对JWT编码规则和Google ID Token签名机制的误解:

  1. 手动解码时JSON缺失闭合}:因为JWT使用Base64URL编码(而非标准Base64),且可能省略填充符=,直接用base64.StdEncoding解码会导致数据截断。
  2. JWT库解析失败:Google ID Token采用RS256(RSA非对称签名),而非你代码中使用的HMAC对称签名,不能用GOOGLE_SECRET验证,必须用Google官方公钥。

解决方案1:修正手动解码逻辑(不推荐生产用,仅作原理说明)

如果需要手动解码Payload,必须严格遵循Base64URL规则处理:

import (
    "strings"
    "encoding/base64"
    "errors"
)

func decodeJWTPayload(token string) (string, error) {
    parts := strings.Split(token, ".")
    if len(parts) != 3 {
        return "", errors.New("invalid JWT format")
    }

    // 转换Base64URL为标准Base64格式
    payload := parts[1]
    payload = strings.ReplaceAll(payload, "-", "+")
    payload = strings.ReplaceAll(payload, "_", "/")
    // 补全缺失的填充符
    switch len(payload) % 4 {
    case 2:
        payload += "=="
    case 3:
        payload += "="
    }

    decoded, err := base64.StdEncoding.DecodeString(payload)
    if err != nil {
        return "", err
    }
    return string(decoded), nil
}

解决方案2:正确使用JWT库解析并验证签名(生产环境推荐)

使用github.com/golang-jwt/jwt/v5库自动处理签名验证和Claims解析,核心是用Google的公钥集验证RS256签名:

import (
    "context"
    "fmt"
    "os"
    "time"

    "github.com/golang-jwt/jwt/v5"
    "github.com/golang-jwt/jwt/v5/request"
)

func ParseGoogleIDToken(tokenStr string) (jwt.MapClaims, error) {
    clientID := os.Getenv("GOOGLE_CLIENT_ID") // 注意:这里用Client ID,不是Secret
    if clientID == "" {
        return nil, fmt.Errorf("GOOGLE_CLIENT_ID not set")
    }

    // 远程获取并缓存Google的公钥集
    keySet, err := jwt.NewRemoteKeySet(
        context.WithTimeout(context.Background(), 5*time.Second),
        "https://www.googleapis.com/oauth2/v3/certs",
    )
    if err != nil {
        return nil, fmt.Errorf("failed to fetch Google public keys: %w", err)
    }

    // 配置验证规则:RS256签名、受众为你的Client ID、签发者为Google账号服务
    token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
        if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
            return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
        }
        return keySet.GetKey(token)
    },
        jwt.WithAudience(clientID),
        jwt.WithIssuer("https://accounts.google.com"),
        jwt.WithExpirationRequired(),
    )

    if err != nil {
        return nil, fmt.Errorf("invalid token: %w", err)
    }

    claims, ok := token.Claims.(jwt.MapClaims)
    if !ok || !token.Valid {
        return nil, fmt.Errorf("invalid token claims")
    }

    return claims, nil
}

关键注意事项

  • 不要手动修改JSON:缺失}是解码错误导致的,修正编码处理后JSON会自动完整。
  • 签名验证不可省略:手动补JSON只能获取用户数据,但无法确认Token是否被篡改,必须通过Google公钥验证签名合法性。
  • 环境变量使用:验证时用GOOGLE_CLIENT_ID而非GOOGLE_SECRET,Secret仅用于OAuth2授权码流程,不用于ID Token验证。

内容的提问来源于stack exchange,提问作者Andrew Arrow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 01:25:09