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

Google OAuth2无法获取Refresh Token及授权弹窗异常问题

无法通过Go的oauth2.Exchange()获取Google OAuth2 Refresh Token

在测试Go应用时,调用oauth2.Exchange()获取Google OAuth2令牌时,始终无法拿到refresh_token。执行代码:

config.Exchange(ctx, code, oauth2.AccessTypeOffline, oauth2.ApprovalForce)

返回的Token对象里没有refresh_token字段。同时oauth2.ApprovalForce参数未按预期每次触发授权弹窗,仅首次授权时弹出,且首次授权后仍无法获取refresh_token。

通过调试器查看请求体,确认已发送以下参数:

access_type=offline&client_id=...&client_secret=...&grant_type=authorization_code&prompt=consent&redirect_uri=...

说明oauth2库本身参数传递正常。

尝试过的方法:

  • 添加自定义参数SetAuthURLParam("approval_prompt", "force"),但无效果。

补充代码片段

初始化OAuth流程

func TestRegister(ctx context.Context, c *app.RequestContext) {
    var err error
    var req register.RegisterReq

    // ...

    var oauthState string
    if oauthState, err = getOAuthState(c); err != nil {
        c.JSON(400, map[string]any{"Error": err.Error()})
        return
    }

    url := config.AuthCodeURL(oauthState)
    c.Redirect(http.StatusTemporaryRedirect, []byte(url))
    return
}

func getOAuthState(c *app.RequestContext) (string, error) {
    expiration := 60 * 60 * 24
    cookieName := "authstate"
    b := make([]byte, 16)
    var err error
    if _, err = rand.Read(b); err != nil {
        return "", err
    }
    state := base64.URLEncoding.EncodeToString(b)
    c.SetCookie(cookieName, state, expiration, "/", "localhost", protocol.CookieSameSiteLaxMode, false, false)
    return state, nil
}

OAuth回调处理

func TestOauthCallback(ctx context.Context, c *app.RequestContext) {
    var err error
    var req register.OauthCallbackReq

    // ...

    queryArgs := &register.OauthCallbackReq{}
    if err = c.BindQuery(queryArgs); err != nil {
        c.JSON(500, map[string]any{"Error": err.Error()})
        return
    }

    var token *oauth2.Token
    if token, err = oauthAuthorize(ctx, queryArgs); err != nil {
        c.JSON(500, map[string]any{"Error": err.Error()})
        return
    }

    _ = token

    // ...
}

func oauthAuthorize(ctx context.Context, queryArgs *register.OauthCallbackReq) (*oauth2.Token, error) {
    var token *oauth2.Token
    var err error
    if token, err = config.Exchange(ctx, code, oauth2.AccessTypeOffline, oauth2.ApprovalForce); err != nil {
        return nil, err
    }
    return token, err
}

补充说明

后续发现问题根源:oauth2.AccessTypeOffline和oauth2.ApprovalForce参数应该在调用AuthCodeURL()时传入,而非在Exchange()方法中传递。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 22:27:34