func providerAuthHeaderWorks(tokenURL string) bool {
	for _, s := range brokenAuthHeaderProviders {
		if strings.HasPrefix(tokenURL, s) {
			return false
		}
	}
	if u, err := url.Parse(tokenURL); err == nil {
		for _, s := range brokenAuthHeaderDomains {
			if strings.HasSuffix(u.Host, s) {
				return false
			}
		}
	}
	return true
}
providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL
implements the OAuth2 spec correctly
See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
In summary:
- Reddit only accepts client secret in the Authorization header
- Dropbox accepts either it in URL param or Auth header, but not both.
- Google only accepts URL param (not spec compliant?), not Auth header
- Stripe only accepts client secret in Auth header with Bearer method, not Basic
package internal
import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"mime"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
	"golang.org/x/net/context/ctxhttp"
)
type Token struct {
	AccessToken string
	TokenType string
	RefreshToken string
	Expiry time.Time
	Raw interface{}
}
type tokenJSON struct {
	AccessToken  string         `json:"access_token"`
	TokenType    string         `json:"token_type"`
	RefreshToken string         `json:"refresh_token"`
	ExpiresIn    expirationTime `json:"expires_in"`  
	Expires      expirationTime `json:"expires"`     
}
func (e *tokenJSON) expiry() (t time.Time) {
	if v := e.ExpiresIn; v != 0 {
		return time.Now().Add(time.Duration(v) * time.Second)
	}
	if v := e.Expires; v != 0 {
		return time.Now().Add(time.Duration(v) * time.Second)
	}
	return
}
type expirationTime int32
func (e *expirationTime) UnmarshalJSON(b []byte) error {
	var n json.Number
	err := json.Unmarshal(b, &n)
	if err != nil {
		return err
	}
	i, err := n.Int64()
	if err != nil {
		return err
	}
	*e = expirationTime(i)
	return nil
}
var brokenAuthHeaderProviders = []string{
	"https://accounts.google.com/",
	"https://api.codeswholesale.com/oauth/token",
	"https://api.dropbox.com/",
	"https://api.dropboxapi.com/",
	"https://api.instagram.com/",
	"https://api.netatmo.net/",
	"https://api.odnoklassniki.ru/",
	"https://api.pushbullet.com/",
	"https://api.soundcloud.com/",
	"https://api.twitch.tv/",
	"https://id.twitch.tv/",
	"https://app.box.com/",
	"https://api.box.com/",
	"https://connect.stripe.com/",
	"https://login.mailchimp.com/",
	"https://login.microsoftonline.com/",
	"https://login.salesforce.com/",
	"https://login.windows.net",
	"https://login.live.com/",
	"https://login.live-int.com/",
	"https://oauth.sandbox.trainingpeaks.com/",
	"https://oauth.trainingpeaks.com/",
	"https://oauth.vk.com/",
	"https://openapi.baidu.com/",
	"https://slack.com/",
	"https://test-sandbox.auth.corp.google.com",
	"https://test.salesforce.com/",
	"https://user.gini.net/",
	"https://www.douban.com/",
	"https://www.googleapis.com/",
	"https://www.linkedin.com/",
	"https://www.strava.com/oauth/",
	"https://www.wunderlist.com/oauth/",
	"https://api.patreon.com/",
	"https://sandbox.codeswholesale.com/oauth/token",
	"https://api.sipgate.com/v1/authorization/oauth",
	"https://api.medium.com/v1/tokens",
	"https://log.finalsurge.com/oauth/token",
	"https://multisport.todaysplan.com.au/rest/oauth/access_token",
	"https://whats.todaysplan.com.au/rest/oauth/access_token",
	"https://stackoverflow.com/oauth/access_token",
	"https://account.health.nokia.com",
	"https://accounts.zoho.com",
}
var brokenAuthHeaderDomains = []string{
	".auth0.com",
	".force.com",
	".myshopify.com",
	".okta.com",
	".oktapreview.com",
}
func RegisterBrokenAuthHeaderProvider(tokenURL string) {
	brokenAuthHeaderProviders = append(brokenAuthHeaderProviders, tokenURL)
}