chore: switch to ReuseTokenSource (#26206)

This commit is contained in:
andig 2025-12-27 15:44:31 +01:00 • committed by GitHub
parent 6a11785633
commit 19a30ac9ca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 137 additions and 108 deletions

View file

@ -48,7 +48,7 @@ func TokenSource(log *util.Logger, user, password string) (oauth2.TokenSource, e
token, err := c.authenticate()
return oauth.RefreshTokenSource(token.AsOAuth2Token(), c), err
return oauth.RefreshTokenSource(token.AsOAuth2Token(), c.refreshToken), err
}
func (c *tokenSource) authenticate() (*Token, error) {
@ -72,7 +72,7 @@ func (c *tokenSource) authenticate() (*Token, error) {
return &token, err
}
func (c *tokenSource) RefreshToken(oauthToken *oauth2.Token) (*oauth2.Token, error) {
func (c *tokenSource) refreshToken(oauthToken *oauth2.Token) (*oauth2.Token, error) {
data := struct {
AccessToken string `json:"accessToken"`
RefreshToken string `json:"refreshToken"`

View file

@ -62,14 +62,14 @@ func TokenSource(log *util.Logger, uri, user, password string) (oauth2.TokenSour
if err == nil {
var token Token
if err = c.DoJSON(req, &token); err == nil {
c.TokenSource = oauth.RefreshTokenSource(token.AsOAuth2Token(), c)
c.TokenSource = oauth.RefreshTokenSource(token.AsOAuth2Token(), c.refreshToken)
}
}
return c, err
}
func (c *tokenSource) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
func (c *tokenSource) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
data := url.Values{
"grant_type": {"refresh_token"},
"refresh_token": {token.RefreshToken},

View file

@ -5,7 +5,6 @@ import (
"time"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/oauth"
"github.com/evcc-io/evcc/util/request"
"golang.org/x/oauth2"
)
@ -15,10 +14,10 @@ type tokenSource struct {
}
func TokenSource(log *util.Logger, token *oauth2.Token) oauth2.TokenSource {
return oauth.RefreshTokenSource(token, &tokenSource{log})
return oauth2.ReuseTokenSource(token, &tokenSource{log})
}
func (ts *tokenSource) RefreshToken(_ *oauth2.Token) (*oauth2.Token, error) {
func (ts *tokenSource) Token() (*oauth2.Token, error) {
// "Content-Type: application/json" \
// --request POST \
// https://console.corrently.io/v2.0/auth/requestToken

View file

@ -79,13 +79,13 @@ func NewEdfTempoFromConfig(other map[string]any) (api.Tariff, error) {
t.Client.Transport = &oauth2.Transport{
Base: t.Client.Transport,
Source: oauth.RefreshTokenSource(new(oauth2.Token), t),
Source: oauth2.ReuseTokenSource(nil, oauth.BootstrapTokenSource(t.refreshToken)),
}
return runOrError(t)
}
func (t *EdfTempo) RefreshToken(_ *oauth2.Token) (*oauth2.Token, error) {
func (t *EdfTempo) refreshToken() (*oauth2.Token, error) {
tokenURL := "https://digital.iservices.rte-france.com/token/oauth"
req, _ := request.New(http.MethodPost, tokenURL, nil, map[string]string{
"Authorization": t.basic,

View file

@ -9,10 +9,10 @@ import (
"time"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/oauth"
"github.com/evcc-io/evcc/util/request"
"github.com/evcc-io/evcc/util/transport"
"github.com/hasura/go-graphql-client"
"golang.org/x/oauth2"
)
// BaseURI is Octopus Energy Germany's Kraken API root.
@ -28,7 +28,7 @@ type OctopusDeGraphQLClient struct {
// NewClient returns a new, authenticated instance of OctopusDeGraphQLClient.
func NewClient(log *util.Logger, email, password, accountNumber string) (*OctopusDeGraphQLClient, error) {
ts := oauth.RefreshTokenSource(nil, &TokenSource{
ts := oauth2.ReuseTokenSource(nil, &tokenSource{
log: log,
email: email,
password: password,

View file

@ -12,25 +12,27 @@ import (
"golang.org/x/oauth2"
)
type TokenSource struct {
type tokenSource struct {
log *util.Logger
email, password string
}
var _ oauth2.TokenSource = (*tokenSource)(nil)
// RefreshToken implements oauth.TokenRefresher to obtain a new JWT token.
// It parses the JWT to extract the actual expiry time from the token claims.
func (c *TokenSource) RefreshToken(_ *oauth2.Token) (*oauth2.Token, error) {
func (ts *tokenSource) Token() (*oauth2.Token, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
// Create a temporary client without authentication for the token request
cli := request.NewClient(c.log)
cli := request.NewClient(ts.log)
tempClient := graphql.NewClient(BaseURI, cli)
var q krakenTokenAuthentication
if err := tempClient.Mutate(ctx, &q, map[string]any{
"email": c.email,
"password": c.password,
"email": ts.email,
"password": ts.password,
}); err != nil {
return nil, fmt.Errorf("authentication failed: %w", err)
}

View file

@ -85,7 +85,7 @@ func NewOstromFromConfig(other map[string]any) (api.Tariff, error) {
t.Client.Transport = &oauth2.Transport{
Base: t.Client.Transport,
Source: oauth.RefreshTokenSource(nil, t),
Source: oauth2.ReuseTokenSource(nil, oauth.BootstrapTokenSource(t.refreshToken)),
}
contracts, err := t.getContracts()
@ -158,7 +158,7 @@ func (t *Ostrom) getFixedPrice() (float64, error) {
return 0, errors.New("tariff not found")
}
func (t *Ostrom) RefreshToken(_ *oauth2.Token) (*oauth2.Token, error) {
func (t *Ostrom) refreshToken() (*oauth2.Token, error) {
uri := ostrom.URI_AUTH + "/oauth2/token"
data := url.Values{"grant_type": {"client_credentials"}}
req, _ := request.New(http.MethodPost, uri, strings.NewReader(data.Encode()), map[string]string{

View file

@ -0,0 +1,25 @@
package oauth
import (
"sync"
"golang.org/x/oauth2"
)
type bootstrapTokenSource struct {
mu sync.Mutex
refresher func() (*oauth2.Token, error)
}
func BootstrapTokenSource(refresher func() (*oauth2.Token, error)) oauth2.TokenSource {
return &bootstrapTokenSource{
refresher: refresher,
}
}
func (ts *bootstrapTokenSource) Token() (*oauth2.Token, error) {
ts.mu.Lock()
defer ts.mu.Unlock()
return ts.refresher()
}

View file

@ -7,23 +7,19 @@ import (
"golang.org/x/oauth2"
)
type TokenRefresher interface {
RefreshToken(token *oauth2.Token) (*oauth2.Token, error)
}
type TokenSource struct {
type refreshTokenSource struct {
mu sync.Mutex
token *oauth2.Token
refresher TokenRefresher
refresher func(token *oauth2.Token) (*oauth2.Token, error)
}
func RefreshTokenSource(token *oauth2.Token, refresher TokenRefresher) oauth2.TokenSource {
func RefreshTokenSource(token *oauth2.Token, refresher func(token *oauth2.Token) (*oauth2.Token, error)) oauth2.TokenSource {
if token == nil {
// allocate an (expired) token or mergeToken will fail
token = new(oauth2.Token)
}
ts := &TokenSource{
ts := &refreshTokenSource{
token: token,
refresher: refresher,
}
@ -31,7 +27,7 @@ func RefreshTokenSource(token *oauth2.Token, refresher TokenRefresher) oauth2.To
return ts
}
func (ts *TokenSource) Token() (*oauth2.Token, error) {
func (ts *refreshTokenSource) Token() (*oauth2.Token, error) {
ts.mu.Lock()
defer ts.mu.Unlock()
@ -39,7 +35,7 @@ func (ts *TokenSource) Token() (*oauth2.Token, error) {
return ts.token, nil
}
token, err := ts.refresher.RefreshToken(ts.token)
token, err := ts.refresher(ts.token)
if err != nil {
return ts.token, err
}

View file

@ -8,24 +8,20 @@ import (
"golang.org/x/oauth2"
)
type tkr struct{}
func (tkr *tkr) RefreshToken(_ *oauth2.Token) (*oauth2.Token, error) {
return (&oauth2.Token{
AccessToken: "new",
}).WithExtra(map[string]any{
"foo": "bar",
}), nil
}
func TestMerge(t *testing.T) {
ts := &TokenSource{
ts := &refreshTokenSource{
token: &oauth2.Token{
AccessToken: "access",
RefreshToken: "refresh",
Expiry: time.Now(),
},
refresher: new(tkr),
refresher: func(_ *oauth2.Token) (*oauth2.Token, error) {
return (&oauth2.Token{
AccessToken: "new",
}).WithExtra(map[string]any{
"foo": "bar",
}), nil
},
}
r, err := ts.Token()

View file

@ -6,6 +6,7 @@ import (
"golang.org/x/oauth2"
)
// TokenWithExpiry decorates an oauth2.Token with the expiry from the ExpiresIn property
func TokenWithExpiry(token *oauth2.Token) *oauth2.Token {
if token != nil && token.Expiry.IsZero() && token.ExpiresIn != 0 {
token.Expiry = time.Now().Add(time.Second * time.Duration(token.ExpiresIn))

View file

@ -102,8 +102,8 @@ func (v *Identity) getDeviceID() (string, error) {
return res.ResMsg.DeviceID, err
}
// RefreshToken implements oauth.TokenRefresher
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
// refreshToken renews BlueLink OAuth tokens
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
var res oauth2.Token
uri := v.config.LoginFormHost + TokenURL
@ -144,11 +144,11 @@ func (v *Identity) Login(user, password, language, brand string) (err error) {
return fmt.Errorf("unknown brand (%s)", brand)
}
token, err := v.RefreshToken(&oauth2.Token{RefreshToken: password})
token, err := v.refreshToken(&oauth2.Token{RefreshToken: password})
if err != nil {
return fmt.Errorf("login failed: %w", err)
}
v.TokenSource = oauth.RefreshTokenSource(token, v)
v.TokenSource = oauth.RefreshTokenSource(token, v.refreshToken)
v.deviceID, err = v.getDeviceID()
if err != nil {

View file

@ -64,7 +64,7 @@ func (v *Identity) Login() error {
return fmt.Errorf("login failed: %w", err)
}
v.TokenSource = oauth.RefreshTokenSource(token, v)
v.TokenSource = oauth2.ReuseTokenSource(token, oauth.BootstrapTokenSource(v.login))
return nil
}
@ -96,9 +96,3 @@ func (v *Identity) login() (*oauth2.Token, error) {
Expiry: time.Now().Add(time.Duration(expiresIn) * time.Second),
}, nil
}
// RefreshToken implements oauth.TokenRefresher
// US API doesn't have a refresh endpoint, so we re-login with credentials
func (v *Identity) RefreshToken(_ *oauth2.Token) (*oauth2.Token, error) {
return v.login()
}

View file

@ -49,9 +49,9 @@ func (v *Identity) Login(user, password, hcaptcha string) (oauth2.TokenSource, e
var tok oauth2.Token
if err := settings.Json(v.settingsKey(), &tok); err == nil {
v.log.DEBUG.Println("identity.Login - database token found")
tok, err := v.RefreshToken(&tok)
tok, err := v.refreshToken(&tok)
if err == nil {
ts := oauth2.ReuseTokenSourceWithExpiry(tok, oauth.RefreshTokenSource(tok, v), 15*time.Minute)
ts := oauth2.ReuseTokenSourceWithExpiry(tok, oauth.RefreshTokenSource(tok, v.refreshToken), 15*time.Minute)
return ts, nil
}
v.log.DEBUG.Println("identity.Login - database token invalid. Proceeding to login via user, password and captcha.")
@ -150,7 +150,7 @@ func (v *Identity) Login(user, password, hcaptcha string) (oauth2.TokenSource, e
return nil, err
}
ts := oauth2.ReuseTokenSourceWithExpiry(token, oauth.RefreshTokenSource(token, v), 15*time.Minute)
ts := oauth2.ReuseTokenSourceWithExpiry(token, oauth.RefreshTokenSource(token, v.refreshToken), 15*time.Minute)
return ts, nil
}
@ -179,7 +179,7 @@ func (v *Identity) retrieveToken(data url.Values) (*oauth2.Token, error) {
return tokex, err
}
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
data := url.Values{
"redirect_uri": {RedirectURI},
"refresh_token": {token.RefreshToken},

View file

@ -71,14 +71,14 @@ func (v *Identity) Login() (Token, error) {
token, err := v.login(data)
if err == nil {
v.TokenSource = oauth.RefreshTokenSource(&token.Token, v)
v.TokenSource = oauth.RefreshTokenSource(&token.Token, v.refreshToken)
}
return token, err
}
// RefreshToken implements oauth.TokenRefresher
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
// refreshToken renews the JLR token
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
data := map[string]string{
"grant_type": "refresh_token",
"refresh_token": token.RefreshToken,

View file

@ -75,14 +75,14 @@ func NewIdentity(log *util.Logger, token *oauth2.Token, account string, region s
if !token.Valid() && token.RefreshToken != "" {
v.log.DEBUG.Println("identity.NewIdentity - refreshToken started")
if tok, err := v.RefreshToken(token); err == nil {
if tok, err := v.refreshToken(token); err == nil {
token = tok
}
}
if !token.Valid() {
v.log.DEBUG.Println("identity.NewIdentity - config refreshToken started")
if tok, err := v.RefreshToken(configToken); err == nil {
if tok, err := v.refreshToken(configToken); err == nil {
token = tok
}
}
@ -91,7 +91,7 @@ func NewIdentity(log *util.Logger, token *oauth2.Token, account string, region s
return nil, errors.New("token expired")
}
v.TokenSource = oauth.RefreshTokenSource(token, v)
v.TokenSource = oauth.RefreshTokenSource(token, v.refreshToken)
// add instance
addInstance(account, v)
@ -103,7 +103,7 @@ func (v *Identity) settingsKey() string {
return fmt.Sprintf("mercedes.%s-%s", v.account, v.region)
}
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
v.mu.Lock()
defer v.mu.Unlock()
@ -125,7 +125,7 @@ func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
}
tok := util.TokenWithExpiry(&res)
v.TokenSource = oauth.RefreshTokenSource(tok, v)
v.TokenSource = oauth.RefreshTokenSource(tok, v.refreshToken)
err := settings.SetJson(v.settingsKey(), tok)

View file

@ -57,7 +57,7 @@ func NewIdentity(log *util.Logger, user, password string) (oauth2.TokenSource, e
return nil, err
}
v.TokenSource = oauth.RefreshTokenSource(token, v)
v.TokenSource = oauth.RefreshTokenSource(token, v.refreshToken)
return v, nil
}
@ -149,8 +149,8 @@ func (v *Identity) login() (*oauth2.Token, error) {
return util.TokenWithExpiry(&token), nil
}
// Token implements oauth.TokenSource
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
// refreshToken obtains a renewed oauth token
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
data := url.Values{
"grant_type": {"refresh_token"},
"refresh_token": {token.RefreshToken},

View file

@ -67,7 +67,7 @@ func NewIdentity(log *util.Logger, user, password string) (oauth2.TokenSource, e
return nil, fmt.Errorf("login failed: %w", err)
}
return oauth.RefreshTokenSource(token, v), nil
return oauth.RefreshTokenSource(token, v.refreshToken), nil
}
func (v *Identity) login() (*oauth2.Token, error) {
@ -168,7 +168,7 @@ func (v *Identity) login() (*oauth2.Token, error) {
return OAuth2Config.Exchange(ctx, code, oauth2.VerifierOption(cv))
}
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, v.Client)
ts := oauth2.ReuseTokenSource(token, OAuth2Config.TokenSource(ctx, token))

View file

@ -45,7 +45,7 @@ func NewIdentity(log *util.Logger, brand, user string, oc *oauth2.Config, token
}
if !token.Valid() {
if tok, err := v.RefreshToken(token); err == nil {
if tok, err := v.refreshToken(token); err == nil {
token = tok
}
}
@ -54,7 +54,7 @@ func NewIdentity(log *util.Logger, brand, user string, oc *oauth2.Config, token
return nil, errors.New("token expired")
}
v.TokenSource = oauth.RefreshTokenSource(token, v)
v.TokenSource = oauth.RefreshTokenSource(token, v.refreshToken)
// add instance
addInstance(v.subject, v)
@ -62,7 +62,7 @@ func NewIdentity(log *util.Logger, brand, user string, oc *oauth2.Config, token
return v, nil
}
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
v.mu.Lock()
defer v.mu.Unlock()
@ -77,7 +77,7 @@ func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
return nil, err
}
v.TokenSource = oauth.RefreshTokenSource(tok, v)
v.TokenSource = oauth.RefreshTokenSource(tok, v.refreshToken)
err = settings.SetJson(v.subject, tok)
return tok, err

View file

@ -56,7 +56,7 @@ func (v *Identity) Login() error {
return err
}
v.TokenSource = oauth2.ReuseTokenSourceWithExpiry(token, oauth.RefreshTokenSource(token, v), 15*time.Minute)
v.TokenSource = oauth2.ReuseTokenSourceWithExpiry(token, oauth.RefreshTokenSource(token, v.refreshToken), 15*time.Minute)
return nil
}
@ -112,7 +112,7 @@ func (v *Identity) retrieveToken(data url.Values) (*oauth2.Token, error) {
return nil, err
}
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
data := url.Values{
"refresh_token": {token.RefreshToken},
"grant_type": {"refresh_token"},

View file

@ -30,14 +30,14 @@ func NewIdentity(log *util.Logger, user, password string) (*Identity, error) {
deviceID: lo.RandomString(16, lo.AlphanumericCharset),
}
v.TokenSource = oauth.RefreshTokenSource(nil, v)
v.TokenSource = oauth2.ReuseTokenSource(nil, oauth.BootstrapTokenSource(v.refreshToken))
_, err := v.Token()
return v, err
}
func (v *Identity) RefreshToken(_ *oauth2.Token) (*oauth2.Token, error) {
func (v *Identity) refreshToken() (*oauth2.Token, error) {
token, err := v.login()
if err != nil {
return nil, err

View file

@ -149,11 +149,11 @@ func (v *Identity) fetchTokenCredentials(code string) error {
}
v.uuid = uuid
v.TokenSource = oauth.RefreshTokenSource(util.TokenWithExpiry(&res.Token), v)
v.TokenSource = oauth.RefreshTokenSource(util.TokenWithExpiry(&res.Token), v.refreshToken)
return nil
}
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
uri := fmt.Sprintf("%s/%s", BaseUrl, AccessTokenPath)
data := url.Values{
"client_id": {ClientID},

View file

@ -74,7 +74,7 @@ func NewIdentity(log *util.Logger, oc *oauth2.Config, token *oauth2.Token) (oaut
}
if !token.Valid() && token.RefreshToken != "" {
if tok, err := v.RefreshToken(token); err == nil {
if tok, err := v.refreshToken(token); err == nil {
token = tok
}
}
@ -83,7 +83,7 @@ func NewIdentity(log *util.Logger, oc *oauth2.Config, token *oauth2.Token) (oaut
return nil, errors.New("token expired")
}
v.TokenSource = oauth.RefreshTokenSource(token, v)
v.TokenSource = oauth.RefreshTokenSource(token, v.refreshToken)
// add instance
addInstance(claims.Subject, v)
@ -95,7 +95,7 @@ func (v *Identity) settingsKey() string {
return fmt.Sprintf("tesla-command.%s", v.subject)
}
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
v.mu.Lock()
defer v.mu.Unlock()

View file

@ -138,11 +138,11 @@ func (v *Identity) fetchTokenCredentials(code string) error {
}
v.uuid = uuid
v.TokenSource = oauth.RefreshTokenSource(util.TokenWithExpiry(&res.Token), v)
v.TokenSource = oauth.RefreshTokenSource(util.TokenWithExpiry(&res.Token), v.refreshToken)
return nil
}
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
uri := fmt.Sprintf("%s/%s", BaseUrl, AccessTokenPath)
data := url.Values{
"client_id": {ClientID},

View file

@ -27,7 +27,6 @@ import (
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/oauth"
"github.com/evcc-io/evcc/util/request"
"github.com/evcc-io/evcc/util/sponsor"
"github.com/evcc-io/evcc/vehicle/tronity"
@ -95,7 +94,7 @@ func NewTronityFromConfig(other map[string]any) (api.Vehicle, error) {
// https://app.platform.tronity.io/docs#tag/Authentication
if err != nil {
// use app flow if we don't have tokens
ts = oauth.RefreshTokenSource(nil, v)
ts = tronity.TokenSource(log, oc)
} else {
// use provided tokens generated by code flow
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, request.NewClient(log))
@ -139,26 +138,6 @@ func NewTronityFromConfig(other map[string]any) (api.Vehicle, error) {
return decorateTronity(v, status, odometer, chargeEnable), nil
}
// RefreshToken performs token refresh by logging in with app context
func (v *Tronity) RefreshToken(_ *oauth2.Token) (*oauth2.Token, error) {
data := struct {
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
GrantType string `json:"grant_type"`
}{
ClientID: v.oc.ClientID,
ClientSecret: v.oc.ClientSecret,
GrantType: "app",
}
req, _ := request.New(http.MethodPost, v.oc.Endpoint.TokenURL, request.MarshalJSON(data), request.JSONEncoding)
var token oauth2.Token
err := request.NewHelper(v.log).DoJSON(req, &token)
return util.TokenWithExpiry(&token), err
}
// vehicles implements the vehicles api
func (v *Tronity) vehicles() ([]tronity.Vehicle, error) {
uri := fmt.Sprintf("%s/tronity/vehicles", tronity.URI)

View file

@ -0,0 +1,37 @@
package tronity
import (
"net/http"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/request"
"golang.org/x/oauth2"
)
type tokenSource struct {
log *util.Logger
oc *oauth2.Config
}
func TokenSource(log *util.Logger, oc *oauth2.Config) oauth2.TokenSource {
return oauth2.ReuseTokenSource(nil, &tokenSource{log, oc})
}
func (ts *tokenSource) Token() (*oauth2.Token, error) {
data := struct {
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
GrantType string `json:"grant_type"`
}{
ClientID: ts.oc.ClientID,
ClientSecret: ts.oc.ClientSecret,
GrantType: "app",
}
req, _ := request.New(http.MethodPost, ts.oc.Endpoint.TokenURL, request.MarshalJSON(data), request.JSONEncoding)
var token oauth2.Token
err := request.NewHelper(ts.log).DoJSON(req, &token)
return util.TokenWithExpiry(&token), err
}

View file

@ -84,13 +84,13 @@ func (v *Service) Refresh(token *Token) (*Token, error) {
return &t, err
}
// RefreshToken implements oauth.TokenRefresher
func (v *Service) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
// refreshToken renews the LoginApps token
func (v *Service) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
res, err := v.Refresh((*Token)(token))
return (*oauth2.Token)(res), err
}
// TokenSource creates a refreshing oauth2 token source
func (v *Service) TokenSource(token *Token) oauth2.TokenSource {
return oauth.RefreshTokenSource((*oauth2.Token)(token), v)
return oauth.RefreshTokenSource((*oauth2.Token)(token), v.refreshToken)
}