package main import ( "encoding/json" "fmt" "golang.org/x/oauth2" "log" "net/http" "net/http/httptest" "time" ) // ServerToken is used to simulate a token response // from an oauth2 Authorization Server type ServerToken struct { AccessToken string `json:"access_token"` TokenType string `json:"token_type"` ExpiresIn int `json:"expires_in"` RefreshToken string `json:"refresh_token,omitempty"` } const expiresIn = 2 // ensure that token refreshes every time. func main() { currentValidRefreshToken := "" counter := 0 // Handle oauth code exchange and refresh requests ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.RequestURI() { case "/refresh": err := r.ParseForm() if err != nil { http.Error(w, "FormParse: "+err.Error(), 500) return } reqRefreshToken := r.Form.Get("refresh_token") if reqRefreshToken != currentValidRefreshToken { msg := fmt.Sprintf("refresh_token = %s; want %s", reqRefreshToken, currentValidRefreshToken) http.Error(w, msg, 500) } case "/exchange": // exchange any code for new refresh token default: http.Error(w, "Unknown url "+r.URL.RequestURI(), 404) return } counter += 1 currentValidRefreshToken = fmt.Sprintf("REFRESH_TOKEN_%d", counter) tk := &ServerToken{ AccessToken: fmt.Sprintf("NEW_ACCESS_TOKEN_%d", counter), TokenType: "Bearer", ExpiresIn: expiresIn, RefreshToken: currentValidRefreshToken, } payload, err := json.Marshal(tk) if err != nil { http.Error(w, "Json decode: "+err.Error(), 500) return } w.Header().Set("Content-Type", "application/json") w.Write(payload) })) defer ts.Close() config := newConf(ts.URL) // Exchange code for new Token w/ RefreshToken set tk, err := config.Exchange(oauth2.NoContext, "Anycode") if err != nil { log.Fatalf("Exchange faild: %v", err) return } log.Print("Exchange code for token") log.Printf("access_token: %s refresh_token: %s", tk.AccessToken, tk.RefreshToken) // create new token source using token tkSrc := config.TokenSource(oauth2.NoContext, tk) // expire token to force refresh time.Sleep(expiresIn * time.Second) tk, err = tkSrc.Token() if err != nil { log.Fatalf("First Token Refresh failed: %v", err) return } log.Print("First token refresh successful.") log.Printf("access_token: %s refresh_token: %s", tk.AccessToken, tk.RefreshToken) time.Sleep(expiresIn * time.Second) tk, err = tkSrc.Token() if err != nil { log.Fatalf("2nd Token Refresh failed: %v", err) return } // log.Print("2nd token refresh successful.") log.Printf("access_token: %s refresh_token: %s", tk.AccessToken, tk.RefreshToken) } func newConf(url string) *oauth2.Config { return &oauth2.Config{ ClientID: "CLIENT_ID", ClientSecret: "CLIENT_SECRET", RedirectURL: "REDIRECT_URL", Scopes: []string{"user"}, Endpoint: oauth2.Endpoint{ AuthURL: url + "/exchange", TokenURL: url + "/refresh", }, } }