Add a consistent 5 minute clock skew accomodation (#145)
diff --git a/google/auth/_helpers.py b/google/auth/_helpers.py
index de86bee..860b827 100644
--- a/google/auth/_helpers.py
+++ b/google/auth/_helpers.py
@@ -22,6 +22,10 @@
from six.moves import urllib
+CLOCK_SKEW_SECS = 300 # 5 minutes in seconds
+CLOCK_SKEW = datetime.timedelta(seconds=CLOCK_SKEW_SECS)
+
+
def copy_docstring(source_class):
"""Decorator that copies a method's docstring from another class.
diff --git a/google/auth/credentials.py b/google/auth/credentials.py
index 8570957..6fb89d8 100644
--- a/google/auth/credentials.py
+++ b/google/auth/credentials.py
@@ -56,8 +56,10 @@
Note that credentials can be invalid but not expired becaue Credentials
with :attr:`expiry` set to None is considered to never expire.
"""
- now = _helpers.utcnow()
- return self.expiry is not None and self.expiry <= now
+ # Err on the side of reporting expiration early so that we avoid
+ # the 403-refresh-retry loop.
+ adjusted_now = _helpers.utcnow() - _helpers.CLOCK_SKEW
+ return self.expiry is not None and self.expiry <= adjusted_now
@property
def valid(self):
diff --git a/google/auth/jwt.py b/google/auth/jwt.py
index 506ba0e..412f122 100644
--- a/google/auth/jwt.py
+++ b/google/auth/jwt.py
@@ -52,8 +52,7 @@
import google.auth.credentials
-_DEFAULT_TOKEN_LIFETIME_SECS = 3600 # 1 hour in sections
-_CLOCK_SKEW_SECS = 300 # 5 minutes in seconds
+_DEFAULT_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds
def encode(signer, payload, header=None, key_id=None):
@@ -161,21 +160,25 @@
"""
now = _helpers.datetime_to_secs(_helpers.utcnow())
- # Make sure the iat and exp claims are present
+ # Make sure the iat and exp claims are present.
for key in ('iat', 'exp'):
if key not in payload:
raise ValueError(
'Token does not contain required claim {}'.format(key))
- # Make sure the token wasn't issued in the future
+ # Make sure the token wasn't issued in the future.
iat = payload['iat']
- earliest = iat - _CLOCK_SKEW_SECS
+ # Err on the side of accepting a token that is slightly early to account
+ # for clock skew.
+ earliest = iat - _helpers.CLOCK_SKEW_SECS
if now < earliest:
raise ValueError('Token used too early, {} < {}'.format(now, iat))
- # Make sure the token wasn't issue in the past
+ # Make sure the token wasn't issued in the past.
exp = payload['exp']
- latest = exp + _CLOCK_SKEW_SECS
+ # Err on the side of accepting a token that is slightly out of date
+ # to account for clow skew.
+ latest = exp + _helpers.CLOCK_SKEW_SECS
if latest < now:
raise ValueError('Token expired, {} < {}'.format(latest, now))