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
}