oauth2: expire the tokens 10 seconds earlier

It avoids the late expiration due to the server time mismatch.

Change-Id: I126a76cff112fbeb92b71dd036195555b20e637b
Reviewed-on: https://go-review.googlesource.com/3307
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/token.go b/token.go
index e04a2dd..9852ceb 100644
--- a/token.go
+++ b/token.go
@@ -10,6 +10,11 @@
 	"time"
 )
 
+// expiryDelta determines how earlier a token should be considered
+// expired than its actual expiration time. It is used to avoid late
+// expirations due to client-server time mismatches.
+const expiryDelta = 10 * time.Second
+
 // Token represents the crendentials used to authorize
 // the requests to access protected resources on the OAuth 2.0
 // provider's backend.
@@ -90,7 +95,7 @@
 	if t.Expiry.IsZero() {
 		return false
 	}
-	return t.Expiry.Before(time.Now())
+	return t.Expiry.Add(-expiryDelta).Before(time.Now())
 }
 
 // Valid reports whether t is non-nil, has an AccessToken, and is not expired.
diff --git a/token_test.go b/token_test.go
index 74d6366..739eeb2 100644
--- a/token_test.go
+++ b/token_test.go
@@ -4,7 +4,10 @@
 
 package oauth2
 
-import "testing"
+import (
+	"testing"
+	"time"
+)
 
 func TestTokenExtra(t *testing.T) {
 	type testCase struct {
@@ -28,3 +31,20 @@
 		}
 	}
 }
+
+func TestTokenExpiry(t *testing.T) {
+	now := time.Now()
+	cases := []struct {
+		name string
+		tok  *Token
+		want bool
+	}{
+		{name: "12 seconds", tok: &Token{Expiry: now.Add(12 * time.Second)}, want: false},
+		{name: "10 seconds", tok: &Token{Expiry: now.Add(expiryDelta)}, want: true},
+	}
+	for _, tc := range cases {
+		if got, want := tc.tok.expired(), tc.want; got != want {
+			t.Errorf("expired (%q) = %v; want %v", tc.name, got, want)
+		}
+	}
+}