Skip to content

Commit 43d6b0c

Browse files
authored
Merge domoinc/DOMO-352334 to check token expiration before making requests
DOMO-352334: Extracting expiration date from access token and checkin…
2 parents 356d8ac + 747eacb commit 43d6b0c

File tree

1 file changed

+35
-4
lines changed

1 file changed

+35
-4
lines changed

pydomo/Transport.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import requests
22
import json
3+
import base64
34
from collections import namedtuple
45
from requests.auth import HTTPBasicAuth
56
from requests_toolbelt.utils import dump
7+
from datetime import datetime, timezone
68

79

810
class DomoAPITransport:
@@ -71,23 +73,52 @@ def request(self, url, method, headers, params=None, body=None):
7173
'params': params, 'data': body, 'stream': True}
7274
if self.request_timeout:
7375
request_args['timeout'] = self.request_timeout
74-
response = requests.request(**request_args)
75-
if response.status_code == requests.codes.UNAUTHORIZED:
76+
77+
# Expiration date should be in UTC
78+
if datetime.now(timezone.utc).timestamp() > self.token_expiration:
79+
self.logger.debug("Access token is expired")
7680
self._renew_access_token()
7781
headers['Authorization'] = 'bearer ' + self.access_token
78-
response = requests.request(**request_args)
79-
return response
82+
83+
return requests.request(**request_args)
8084

8185
def _renew_access_token(self):
8286
self.logger.debug("Renewing Access Token")
8387
url = self.apiHost + '/oauth/token?grant_type=client_credentials'
8488
response = requests.post(url=url, auth=HTTPBasicAuth(self.clientId, self.clientSecret))
8589
if response.status_code == requests.codes.OK:
8690
self.access_token = response.json()['access_token']
91+
self.token_expiration = self._extract_expiration(self.access_token)
8792
else:
8893
self.logger.debug('Error retrieving access token: ' + self.dump_response(response))
8994
raise Exception("Error retrieving a Domo API Access Token: " + response.text)
9095

96+
def _extract_expiration(self, access_token):
97+
expiration_date = 0
98+
try:
99+
decoded_payload_dict = self._decode_payload(access_token)
100+
101+
if 'exp' in decoded_payload_dict.keys():
102+
expiration_date = decoded_payload_dict['exp']
103+
self.logger.debug('Token expiration: {}'
104+
.format(expiration_date))
105+
except Exception as err:
106+
# If an Exception is raised, log and continue. expiration_date will
107+
# either be 0 or set to the value in the JWT.
108+
self.logger.debug('Ran into error parsing token for expiration. '
109+
'Setting expiration date to 0. '
110+
'{}: {}'.format(type(err).__name__, err))
111+
return expiration_date
112+
113+
def _decode_payload(self, access_token):
114+
token_parts = access_token.split('.')
115+
116+
# Padding required for the base64 library
117+
payload_bytes = bytes(token_parts[1], 'utf-8') + b'=='
118+
decoded_payload_bytes = base64.urlsafe_b64decode(payload_bytes)
119+
payload_string = decoded_payload_bytes.decode('utf-8')
120+
return json.loads(payload_string)
121+
91122
def dump_response(self, response):
92123
data = dump.dump_all(response)
93124
return str(data.decode('utf-8'))

0 commit comments

Comments
 (0)