googleworkspace / go-samples

Go samples for Google Workspace APIs
Apache License 2.0
216 stars 100 forks source link

Golang Gmail Api #37

Open reddragon09 opened 5 years ago

reddragon09 commented 5 years ago

Expected Behavior

Run code in https://developers.google.com/gmail/api/quickstart/go success

Actual Behavior

I got error: Go to the following link in your browser then type the authorization code: https://accounts.google.com/o/oauth2/auth?access_type=offline&client_id=547117123835-tkhmlkohvj3rncvahj0h1o59vl4kgjpk.apps.googleusercontent.com&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.readonly&state=state-token 2019/10/09 18:19:30 Unable to read authorization code: EOF

Steps to Reproduce the Problem

  1. Flow steps in https://developers.google.com/gmail/api/quickstart/go
  2. Access link to get authCode: https://accounts.google.com/o/oauth2/auth?access_type=offline&client_id=547117123835-tkhmlkohvj3rncvahj0h1o59vl4kgjpk.apps.googleusercontent.com&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.readonly&state=state-token
  3. Run project

Specifications

reddragon09 commented 5 years ago

My code

package mail_process

import (
    "encoding/json"
    "fmt"
    "github.com/astaxie/beego"
    "io/ioutil"
    "log"
    "net/http"
    "os"

    "golang.org/x/net/context"
    "golang.org/x/oauth2"
    "golang.org/x/oauth2/google"
    "google.golang.org/api/gmail/v1"
)

// MailsController operations for Mails
type CloneMailsController struct {
    beego.Controller
    //libs.Middleware
}

// URLMapping ...
func (c *CloneMailsController) URLMapping() {
    c.Mapping("Post", c.Post)
}

// CloneMail
// @Title CloneMail
// @Description CloneMail
// @Param   Authorization   header  string  false   "token"
// @Success 201 {int}
// @Failure 403 body is empty <br> 211 Variable is not json type <br> 217 Variable required <br> 303 Save data failures
//
// @router / [post]
func (c *CloneMailsController) CloneMail() {
    GetMail()
    c.Data["json"] = ""
    c.ServeJSON()
}

//Get mail from mail server
func GetMail() {
    b, err := ioutil.ReadFile("./storage/mail_process/credentials.json")
    if err != nil {
        log.Fatalf("Unable to read client secret file: %v", err)
    }

    // If modifying these scopes, delete your previously saved token.json.
    config, err := google.ConfigFromJSON(b, gmail.GmailReadonlyScope)
    if err != nil {
        log.Fatalf("Unable to parse client secret file to config: %v", err)
    }
    client := getClient(config)
    fmt.Println("---------------------------------------------------------------")
    fmt.Println(config)
    fmt.Println(client)
    srv, err := gmail.New(client)
    if err != nil {
        log.Fatalf("Unable to retrieve Gmail client: %v", err)
    }
    fmt.Println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
    fmt.Println(srv)
    user := "me"
    r, err := srv.Users.Labels.List(user).Do()
    if err != nil {
        log.Fatalf("Unable to retrieve labels: %v", err)
    }
    if len(r.Labels) == 0 {
        fmt.Println("No labels found.")
        return
    }
    fmt.Println("Labels:")
    for _, l := range r.Labels {
        fmt.Printf("- %s\n", l.Name)
    }
}

// Retrieve a token, saves the token, then returns the generated client.
func getClient(config *oauth2.Config) *http.Client {
    // The file token.json stores the user's access and refresh tokens, and is
    // created automatically when the authorization flow completes for the first
    // time.
    tokFile := "./storage/mail_process/token.json"
    tok, err := tokenFromFile(tokFile)
    if err != nil {
        tok = getTokenFromWeb(config)
        saveToken(tokFile, tok)
    }
    return config.Client(context.Background(), tok)
}

// Request a token from the web, then returns the retrieved token.
func getTokenFromWeb(config *oauth2.Config) *oauth2.Token {
    authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
    fmt.Printf("Go to the following link in your browser then type the "+
        "authorization code: \n%v\n", authURL)

    var authCode string = "4/rwFbig35HHvO6fps4tsup3wNP1ZW8onrmHxa1_kEq5BpYst0udZ8bkw"
    if _, err := fmt.Scan(&authCode); err != nil {
        log.Fatalf("Unable to read authorization code: %v", err)
    }

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

// Retrieves a token from a local file.
func tokenFromFile(file string) (*oauth2.Token, error) {
    f, err := os.Open(file)
    if err != nil {
        return nil, err
    }
    defer f.Close()
    tok := &oauth2.Token{}
    err = json.NewDecoder(f).Decode(tok)
    fmt.Println(f)
    fmt.Println(tok)
    return tok, err
}

// Saves a token to a file path.
func saveToken(path string, token *oauth2.Token) {
    fmt.Printf("Saving credential file to: %s\n", path)
    f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
    if err != nil {
        log.Fatalf("Unable to cache oauth token: %v", err)
    }
    defer f.Close()
    json.NewEncoder(f).Encode(token)
}

`

hi-Ernest commented 2 years ago

you need add your account as test user of OAuth consent screen

etiennepericat commented 1 year ago

exact same problem here, even with test account properly saved, do you have any fix ?

porridge commented 1 year ago

From your source:

    var authCode string = "4/rwFbig35HHvO6fps4tsup3wNP1ZW8onrmHxa1_kEq5BpYst0udZ8bkw"

This variable must be empty for fmt.Scan to work as intended. But in the 2023 era even if you fix that, you'll hit another problem as described in #76 😉