@@ -145,6 +145,23 @@ def perform_interactive_login(self):
145145 self .cli .print (f'Authenticated to tenant { self .tenant } via interactive login.' )
146146 break
147147
148+ @staticmethod
149+ def extract_field_from_jwt (token : str , field : str , verify : bool = False ):
150+ try :
151+ return jwt .decode (
152+ token ,
153+ # validation of the token will occur on the Britive backend
154+ # so not verifying everything here is okay since we are just
155+ # trying to extract the token expiration time so we can store
156+ # it in the ~/.britive/pybritive.credentials[.encrypted] file
157+ options = {
158+ 'verify_signature' : verify ,
159+ 'verify_aud' : verify
160+ }
161+ )[field ]
162+ except Exception :
163+ return None
164+
148165 @staticmethod
149166 def _extract_exp_from_jwt (token : str , verify : bool = False , convert_to_ms : bool = False ):
150167 try :
@@ -247,20 +264,22 @@ def _get_token(self):
247264
248265 def get_token (self ):
249266 if not self .has_valid_credentials (): # no credentials or expired creds for the tenant so do interactive login
250-
267+ self . cli . debug ( 'has_valid_credentials = False' )
251268 # both methods below write the credentials out and update self.credentials as needed
252269 if self .federation_provider :
253270 self .perform_federation_provider_authentication ()
254271 else :
255272 self .perform_interactive_login ()
256273
257- return self ._get_token ()
274+ token = self ._get_token ()
275+ return token
258276
259277 def has_valid_credentials (self ):
260278 if not self .credentials or self .credentials == {}:
261279 self .cli .print (f'Credentials for tenant { self .tenant } not found.' )
262280 return False
263281 if int (time .time () * 1000 ) <= int (self .credentials .get ('safeExpirationTime' , 0 )):
282+ self .cli .debug ('credentials.py::has_valid_credentials - credentials exist and are not expired so are valid' )
264283 return True
265284 self .cli .print (f'Credentials for tenant { self .tenant } have expired.' )
266285 return False
@@ -292,8 +311,11 @@ def save(self, credentials: dict):
292311 full_credentials = self .load (full = True )
293312 if credentials is None :
294313 full_credentials .pop (self .alias , None )
314+ self .credentials = None
295315 else :
296316 full_credentials [self .alias ] = credentials
317+ # effectively a deep copy
318+ self .credentials = json .loads (json .dumps (credentials ))
297319
298320 config = configparser .ConfigParser ()
299321 config .optionxform = str # maintain key case
@@ -302,7 +324,13 @@ def save(self, credentials: dict):
302324 # write the new credentials file
303325 with open (str (self .path ), 'w' , encoding = 'utf-8' ) as f :
304326 config .write (f , space_around_delimiters = False )
305- self .credentials = credentials
327+
328+ jti = self .extract_field_from_jwt (
329+ token = (self .credentials or {}).get ('accessToken' ),
330+ verify = False ,
331+ field = 'jti'
332+ )
333+ self .cli .debug (f'credentials.py::FileCredentialManager::save - set credentials to jwt id { jti } ' )
306334
307335 def delete (self ):
308336 self .save (None )
@@ -353,6 +381,7 @@ def save(self, credentials: dict):
353381 full_credentials = self .load (full = True )
354382 if credentials is None :
355383 full_credentials .pop (self .alias , None )
384+ self .credentials = None
356385 else :
357386 credentials ['accessToken' ] = self .encrypt (credentials ['accessToken' ])
358387 full_credentials [self .alias ] = credentials
@@ -367,5 +396,12 @@ def save(self, credentials: dict):
367396 with open (str (self .path ), 'w' , encoding = 'utf-8' ) as f :
368397 config .write (f , space_around_delimiters = False )
369398
399+ jti = self .extract_field_from_jwt (
400+ token = (self .credentials or {}).get ('accessToken' ),
401+ verify = False ,
402+ field = 'jti'
403+ )
404+ self .cli .debug (f'credentials.py::FileCredentialManager::save - set credentials to jwt id { jti } ' )
405+
370406 def delete (self ):
371407 self .save (None )
0 commit comments