@@ -15,16 +15,16 @@ import (
1515
1616// Manager holds certificates from filesystem watched for changes
1717type Manager struct {
18- mutex sync.Mutex
19- config clientcredentials.Config
20- requestTimeout time.Duration
21- tickFrequency time.Duration
22- startRefreshToken time.Time
23- token * oauth2.Token
24- httpClient * http.Client
25- tokenErr error
26- doneWg sync.WaitGroup
27- done chan struct {}
18+ mutex sync.Mutex
19+ config clientcredentials.Config
20+ requestTimeout time.Duration
21+ tickFrequency time.Duration
22+ nextTokenRenewalTime time.Time
23+ token * oauth2.Token
24+ httpClient * http.Client
25+ tokenErr error
26+ doneWg sync.WaitGroup
27+ done chan struct {}
2828}
2929
3030// NewManagerFromConfiguration creates a new oauth manager which refreshing token.
@@ -40,18 +40,19 @@ func NewManagerFromConfiguration(config Config, tlsCfg *tls.Config) (*Manager, e
4040 Transport : t ,
4141 Timeout : config .RequestTimeout ,
4242 }
43- token , startRefreshToken , err := getToken (cfg , httpClient , config .RequestTimeout )
43+ token , nextTokenRenewalTime , err := getToken (cfg , httpClient , config .RequestTimeout )
4444 if err != nil {
4545 return nil , err
4646 }
47+ log .Infof ("client credential token is refreshed, the next refresh token occurs after %v" , nextTokenRenewalTime )
4748
4849 mgr := & Manager {
49- config : cfg ,
50- token : token ,
51- startRefreshToken : startRefreshToken ,
52- requestTimeout : config .RequestTimeout ,
53- httpClient : httpClient ,
54- tickFrequency : config .TickFrequency ,
50+ config : cfg ,
51+ token : token ,
52+ nextTokenRenewalTime : nextTokenRenewalTime ,
53+ requestTimeout : config .RequestTimeout ,
54+ httpClient : httpClient ,
55+ tickFrequency : config .TickFrequency ,
5556
5657 done : make (chan struct {}),
5758 }
@@ -78,7 +79,23 @@ func (a *Manager) Close() {
7879}
7980
8081func (a * Manager ) shouldRefresh () bool {
81- return time .Now ().After (a .startRefreshToken )
82+ /*
83+ We cannot use time.Now().After(a.nextTokenRenewalTime ) because
84+ golang using monotonic clock for comparision.
85+
86+ So if we have 2 times:
87+ // update time on PC to future eg: `date MMDDHHMM`
88+ t1 := time.Now() eg (2021-06-15T12:00:00)
89+ // return back time on PC: `date MMDDHHMM`
90+ t2 := time.Now() eg (2021-06-01T12:00:00)
91+ and then you call t2.After(t1) - it's return true :)
92+
93+ more info: https://github.com/golang/go/blob/master/src/time/time.go
94+
95+ the issue can occurs when pc hibernates.
96+ */
97+
98+ return time .Now ().UnixNano () > a .nextTokenRenewalTime .UnixNano ()
8299}
83100
84101func getToken (cfg clientcredentials.Config , httpClient * http.Client , requestTimeout time.Duration ) (* oauth2.Token , time.Time , error ) {
@@ -88,24 +105,26 @@ func getToken(cfg clientcredentials.Config, httpClient *http.Client, requestTime
88105 ctx = context .WithValue (ctx , oauth2 .HTTPClient , httpClient )
89106
90107 token , err := cfg .Token (ctx )
91- var startRefreshToken time.Time
108+ var nextTokenRenewalTime time.Time
92109 if err == nil {
93110 now := time .Now ()
94- startRefreshToken = now .Add (token .Expiry .Sub (now ) * 2 / 3 )
111+ nextTokenRenewalTime = now .Add (token .Expiry .Sub (now ) * 2 / 3 )
95112 }
96- return token , startRefreshToken , err
113+ return token , nextTokenRenewalTime , err
97114}
98115
99116func (a * Manager ) refreshToken () {
100- token , startRefreshToken , err := getToken (a .config , a .httpClient , a .requestTimeout )
117+ token , nextTokenRenewalTime , err := getToken (a .config , a .httpClient , a .requestTimeout )
101118 if err != nil {
102119 log .Errorf ("cannot refresh token: %v" , err )
120+ } else {
121+ log .Infof ("client credential token is refreshed, the next refresh token occurs after %v" , nextTokenRenewalTime )
103122 }
104123 a .mutex .Lock ()
105124 defer a .mutex .Unlock ()
106125 a .token = token
107126 a .tokenErr = err
108- a .startRefreshToken = startRefreshToken
127+ a .nextTokenRenewalTime = nextTokenRenewalTime
109128}
110129
111130func (a * Manager ) watchToken () {
0 commit comments