The Trouble With Tokens (Refresh Tokens, that is...)

85 views
Skip to first unread message

Andrew Watson

unread,
Feb 20, 2018, 4:11:09 PM2/20/18
to golang-nuts
So, I built something that uses the 3 step OAuth 2.0 Dance to get access to gmail.  It stores the OAuth tokens after encrypting them with Vault transit keys and then I built something that decrypts those tokens, constructs an OAuth 2.0 client using them and goes looking for things in my inbox.  

That's all fine and great except... the access tokens expire in an hour and my client just falls apart without even bothering to refresh the token.

At first, I wasn't even getting a refresh token but i finally figured this out:

oauthConfig.AuthCodeURL(state, oauth2.AccessTypeOffline)

So I'm getting a refresh token and the access token works fine for about an hour but then...

It all goes down the tubes. I've looked into all kinds of workarounds including ReuseAccessToken() etc but when i use TokenSource() the Token() method causes a panic!


Thanks

func (p *InboxPoller) searchGMail(c types.Customer) error {
ctx := context.Background()
fmt.Printf("Decrypting Token for %s\n", c.Email)
authToken, err := p.transitClient.Decrypt(c.Email, c.EmailToken)
if err != nil {
return errors.Wrap(err, "Unable to Decrypt Email Token for "+c.Email)
}
config, err := google.ConfigFromJSON([]byte(authToken), gmail.GmailModifyScope)
 // Important Bits!
t := &oauth2.Token{}
json.Unmarshal([]byte(authToken), &t)
fmt.Printf("(CACHED) Access %s Refresh %s Expiry %s\n", t.AccessToken, t.RefreshToken, t.Expiry)
client := config.Client(ctx, t)
 // End Important Bits
gmailService, err := gmail.New(client)
if err != nil {
return errors.Wrap(err, "Unable to create Gmail Client")
}
msgs, err := gmailService.Users.Messages.List("me").Q("from:auto-c...@amazon.com -(label:Remedy)").Do()
if err != nil {
return errors.Wrap(err, "Failure to fetch messages")
}
seenMessages := []string{}
if msgs.Messages != nil {
fmt.Printf("%d Messages\n", len(msgs.Messages))
for _, m := range msgs.Messages {
msg, err := gmailService.Users.Messages.Get("me", m.Id).Do()
if err != nil {
return errors.Wrap(err, "Error Fetching Email")
}
decodedBody, _ := base64.StdEncoding.DecodeString(msg.Payload.Body.Data)
msgLen := len(decodedBody)
if msgLen > 512 {
msgLen = 512
}
fmt.Printf("ID: %s Body: %s\n", msg.Id, string(decodedBody[0:msgLen]))
seenMessages = append(seenMessages, msg.Id)
}
labelResp, err := gmailService.Users.Labels.List("me").Do()
if err != nil {
return errors.Wrap(err, "Unable to search labels")
}
remedyLabelId := ""
for _, l := range labelResp.Labels {
if l.Name == "Remedy" {
remedyLabelId = l.Id
}
}
if remedyLabelId == "" {
newRemedyLabel, err := gmailService.Users.Labels.Create("me", &gmail.Label{Id: "Remedy"}).Do()
if err != nil {
return errors.Wrap(err, "Unable to create Remedy label")
}
remedyLabelId = newRemedyLabel.Id
}
batchModifyRequest := &gmail.BatchModifyMessagesRequest{
AddLabelIds: []string{remedyLabelId},
Ids:         seenMessages,
}
err = gmailService.Users.Messages.BatchModify("me", batchModifyRequest).Do()
if err != nil {
return errors.Wrap(err, "Unable to apply Remedy label")
}
}
return nil
}

Andrew Watson

unread,
Feb 20, 2018, 9:32:47 PM2/20/18
to golang-nuts
I fixed my problem myself.  It turns out the app that consumes the tokens also needs to load the oauth2 config with client id, secret etc.  I did not know this!
msgs, err := gmailService.Users.Messages.List("me").Q("from:auto-con...@amazon.com -(label:Remedy)").Do()
Reply all
Reply to author
Forward
0 new messages