首页 > 解决方案 > 无法让 Oauth2 TokenSource 刷新从存储中检索到的令牌

问题描述

用户授权 Google Calendar 后,NodeJS 服务将Code、AccessToken 和 RefreshToken保存到存储中。

尝试使用相同的令牌访问使用 Go 编写的不同后端服务的用户日历。当 AccessToken 有效时,数据是可访问的,但是当 AccessToken 过期时,无法获取 config.Exchange() 或 config.TokenSource() 以提供新的令牌,即使令牌有效,在尝试访问事件时也是如此,得到错误:

错误 401:凭据无效,authError 退出状态 1

 tok, err := config.TokenSource(ctx, token).Token() // token is previous valid token
 if err != nil {
    log.Fatalf("Unable to retrieve token from web: %v", err)
 }

还尝试用代码交换新令牌,但无济于事

400 错误请求响应:{“error”:“invalid_grant”,“error_description”:“格式错误的身份验证代码。” }

    tok, err := config.Exchange(context.TODO(), in)
if err != nil {
    log.Fatalf("Unable to retrieve token from web: %v", err)
}

尝试使用 calendar.NewService 访问

srv, _ := calendar.NewService(ctx, option.WithTokenSource(config.TokenSource(ctx, tok)))

如何获得可以离线访问的令牌,而无需用户干预来自其他服务?

更新:将令牌存储到 Redis - RedisJSON 但仍不会获得新的 AccessToken。这是我传递有效令牌的完整功能。它仅在 AccessToken 到期之前有效。

func GetGoogleCalendarEvents(token *oauth2.Token, userid string) *calendar.Events {
tok := &oauth2.Token{}
var config *oauth2.Config
ctx := context.Background()

b, err := ioutil.ReadFile("credentials.json")
if err != nil {
    log.Fatalf("Unable to read client secret file: %v", err)
}

config, err = google.ConfigFromJSON(b, calendar.CalendarScope) //calendar.CalendarScope)
if err != nil {
    log.Fatalf("Unable to parse client secret file to config: %v", err)
}

tok = token

if token.Expiry.Before(time.Now()) {

    tokenSource := config.TokenSource(ctx, token) //oauth2.NoContext

    newToken, err := tokenSource.Token()
    if err != nil {
        log.Fatalln(err)
    }

    if tok.AccessToken != newToken.AccessToken {
        SetAuthCredToCache(userid, tok)
        tok = newToken
        fmt.Println(newToken)
    }
}

fmt.Println(tok.Expiry, tok.Valid(), tok.Type(), tok.RefreshToken, tok.TokenType)

srv, _ := calendar.NewService(ctx, option.WithTokenSource(config.TokenSource(ctx, tok)))

t := time.Now().Format(time.RFC3339)

events, err := srv.Events.List("primary").ShowDeleted(true).
    SingleEvents(true).TimeMin(t).OrderBy("startTime").Do()

if err != nil {
    log.Fatalf("Unable to retrieve next ten of the user's events: %v", err)
}
return events

}

标签: gogoogle-calendar-apigoogle-oauth

解决方案


这是一个解组问题。

从 Node 保存令牌时,它将到期时间序列化为“expiry_date”,而 Go Token 的 json 表示形式为“expiry”。将对象的其余部分解组为 oauth2.Token 对象并向该对象添加到期时间解决了该问题。


推荐阅读