Skip to content

Commit 1e7f329

Browse files
oauth2: add ReuseTokenSourceWithExpiry
Add a constructor which allows for the configuration of the expiryDelta buffer. Due to the construction of reuseTokenSource and Token we need to store the new delta in both places, so the behavior of Valid is consistent regardless of where it is called from. Fixes golang#623 Change-Id: I89f9c206a9cc16bb473b8c619605c8410a82fff0 Reviewed-on: https://go-review.googlesource.com/c/oauth2/+/479676 Run-TryBot: Roland Shoemaker <[email protected]> Reviewed-by: Cody Oss <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 86850e0 commit 1e7f329

File tree

3 files changed

+49
-4
lines changed

3 files changed

+49
-4
lines changed

oauth2.go

+31
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"net/url"
1717
"strings"
1818
"sync"
19+
"time"
1920

2021
"golang.org/x/oauth2/internal"
2122
)
@@ -290,6 +291,8 @@ type reuseTokenSource struct {
290291

291292
mu sync.Mutex // guards t
292293
t *Token
294+
295+
expiryDelta time.Duration
293296
}
294297

295298
// Token returns the current token if it's still valid, else will
@@ -305,6 +308,7 @@ func (s *reuseTokenSource) Token() (*Token, error) {
305308
if err != nil {
306309
return nil, err
307310
}
311+
t.expiryDelta = s.expiryDelta
308312
s.t = t
309313
return t, nil
310314
}
@@ -379,3 +383,30 @@ func ReuseTokenSource(t *Token, src TokenSource) TokenSource {
379383
new: src,
380384
}
381385
}
386+
387+
// ReuseTokenSource returns a TokenSource that acts in the same manner as the
388+
// TokenSource returned by ReuseTokenSource, except the expiry buffer is
389+
// configurable. The expiration time of a token is calculated as
390+
// t.Expiry.Add(-earlyExpiry).
391+
func ReuseTokenSourceWithExpiry(t *Token, src TokenSource, earlyExpiry time.Duration) TokenSource {
392+
// Don't wrap a reuseTokenSource in itself. That would work,
393+
// but cause an unnecessary number of mutex operations.
394+
// Just build the equivalent one.
395+
if rt, ok := src.(*reuseTokenSource); ok {
396+
if t == nil {
397+
// Just use it directly, but set the expiryDelta to earlyExpiry,
398+
// so the behavior matches what the user expects.
399+
rt.expiryDelta = earlyExpiry
400+
return rt
401+
}
402+
src = rt.new
403+
}
404+
if t != nil {
405+
t.expiryDelta = earlyExpiry
406+
}
407+
return &reuseTokenSource{
408+
t: t,
409+
new: src,
410+
expiryDelta: earlyExpiry,
411+
}
412+
}

token.go

+12-2
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ import (
1616
"golang.org/x/oauth2/internal"
1717
)
1818

19-
// expiryDelta determines how earlier a token should be considered
19+
// defaultExpiryDelta determines how earlier a token should be considered
2020
// expired than its actual expiration time. It is used to avoid late
2121
// expirations due to client-server time mismatches.
22-
const expiryDelta = 10 * time.Second
22+
const defaultExpiryDelta = 10 * time.Second
2323

2424
// Token represents the credentials used to authorize
2525
// the requests to access protected resources on the OAuth 2.0
@@ -52,6 +52,11 @@ type Token struct {
5252
// raw optionally contains extra metadata from the server
5353
// when updating a token.
5454
raw interface{}
55+
56+
// expiryDelta is used to calculate when a token is considered
57+
// expired, by subtracting from Expiry. If zero, defaultExpiryDelta
58+
// is used.
59+
expiryDelta time.Duration
5560
}
5661

5762
// Type returns t.TokenType if non-empty, else "Bearer".
@@ -127,6 +132,11 @@ func (t *Token) expired() bool {
127132
if t.Expiry.IsZero() {
128133
return false
129134
}
135+
136+
expiryDelta := defaultExpiryDelta
137+
if t.expiryDelta != 0 {
138+
expiryDelta = t.expiryDelta
139+
}
130140
return t.Expiry.Round(0).Add(-expiryDelta).Before(timeNow())
131141
}
132142

token_test.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,13 @@ func TestTokenExpiry(t *testing.T) {
4343
want bool
4444
}{
4545
{name: "12 seconds", tok: &Token{Expiry: now.Add(12 * time.Second)}, want: false},
46-
{name: "10 seconds", tok: &Token{Expiry: now.Add(expiryDelta)}, want: false},
47-
{name: "10 seconds-1ns", tok: &Token{Expiry: now.Add(expiryDelta - 1*time.Nanosecond)}, want: true},
46+
{name: "10 seconds", tok: &Token{Expiry: now.Add(defaultExpiryDelta)}, want: false},
47+
{name: "10 seconds-1ns", tok: &Token{Expiry: now.Add(defaultExpiryDelta - 1*time.Nanosecond)}, want: true},
4848
{name: "-1 hour", tok: &Token{Expiry: now.Add(-1 * time.Hour)}, want: true},
49+
{name: "12 seconds, custom expiryDelta", tok: &Token{Expiry: now.Add(12 * time.Second), expiryDelta: time.Second * 5}, want: false},
50+
{name: "5 seconds, custom expiryDelta", tok: &Token{Expiry: now.Add(time.Second * 5), expiryDelta: time.Second * 5}, want: false},
51+
{name: "5 seconds-1ns, custom expiryDelta", tok: &Token{Expiry: now.Add(time.Second*5 - 1*time.Nanosecond), expiryDelta: time.Second * 5}, want: true},
52+
{name: "-1 hour, custom expiryDelta", tok: &Token{Expiry: now.Add(-1 * time.Hour), expiryDelta: time.Second * 5}, want: true},
4953
}
5054
for _, tc := range cases {
5155
if got, want := tc.tok.expired(), tc.want; got != want {

0 commit comments

Comments
 (0)