@@ -167,10 +167,17 @@ def _get_tokens(self):
167167 """
168168 Get the current access and refresh tokens.
169169
170+ This is a protected method that can be overridden to look up tokens
171+ from an external source (the inverse of the `store_tokens` callback).
172+
173+ This method does not need to update this object's private token
174+ attributes. Its caller in :class:`OAuth2` is responsible for that.
175+
170176 :return:
171177 Tuple containing the current access token and refresh token.
178+ One or both of them may be `None`, if they aren't set.
172179 :rtype:
173- `tuple` of (`unicode`, `unicode`)
180+ `tuple` of (( `unicode` or `None`), ( `unicode` or `None`) )
174181 """
175182 return self ._access_token , self ._refresh_token
176183
@@ -181,16 +188,24 @@ def refresh(self, access_token_to_refresh):
181188
182189 :param access_token_to_refresh:
183190 The expired access token, which needs to be refreshed.
191+ Pass `None` if you don't have the access token.
184192 :type access_token_to_refresh:
185- `unicode`
193+ `unicode` or `None`
194+ :return:
195+ Tuple containing the new access token and refresh token.
196+ The refresh token may be `None`, if the authentication scheme
197+ doesn't use one, or keeps it hidden from this client.
198+ :rtype:
199+ `tuple` of (`unicode`, (`unicode` or `None`))
186200 """
187201 with self ._refresh_lock :
188- access_token , refresh_token = self ._get_tokens ()
202+ access_token , refresh_token = self ._get_and_update_current_tokens ()
189203 # The lock here is for handling that case that multiple requests fail, due to access token expired, at the
190204 # same time to avoid multiple session renewals.
191- if access_token_to_refresh == access_token :
192- # If the active access token is the same as the token needs to be refreshed, we make the request to
193- # refresh the token.
205+ if (access_token is None ) or (access_token_to_refresh == access_token ):
206+ # If the active access token is the same as the token needs to
207+ # be refreshed, or if we don't currently have any active access
208+ # token, we make the request to refresh the token.
194209 return self ._refresh (access_token_to_refresh )
195210 else :
196211 # If the active access token (self._access_token) is not the same as the token needs to be refreshed,
@@ -213,11 +228,37 @@ def _get_state_csrf_token():
213228 return 'box_csrf_token_' + '' .join (ascii_alphabet [int (system_random .random () * ascii_len )] for _ in range (16 ))
214229
215230 def _store_tokens (self , access_token , refresh_token ):
216- self ._access_token = access_token
217- self ._refresh_token = refresh_token
231+ self ._update_current_tokens (access_token , refresh_token )
218232 if self ._store_tokens_callback is not None :
219233 self ._store_tokens_callback (access_token , refresh_token )
220234
235+ def _get_and_update_current_tokens (self ):
236+ """Get the current access and refresh tokens, while also storing them in this object's private attributes.
237+
238+ :return:
239+ Same as for :meth:`_get_tokens()`.
240+ """
241+ tokens = self ._get_tokens ()
242+ self ._update_current_tokens (* tokens )
243+ return tokens
244+
245+ def _update_current_tokens (self , access_token , refresh_token ):
246+ """Store the latest tokens in this object's private attributes.
247+
248+ :param access_token:
249+ The latest access token.
250+ May be `None`, if it hasn't been provided.
251+ :type access_token:
252+ `unicode` or `None`
253+ :param refresh_token:
254+ The latest refresh token.
255+ May be `None`, if the authentication scheme doesn't use one, or if
256+ it hasn't been provided.
257+ :type refresh_token:
258+ `unicode` or `None`
259+ """
260+ self ._access_token , self ._refresh_token = access_token , refresh_token
261+
221262 def send_token_request (self , data , access_token , expect_refresh_token = True ):
222263 """
223264 Send the request to acquire or refresh an access token.
@@ -262,7 +303,7 @@ def revoke(self):
262303 Revoke the authorization for the current access/refresh token pair.
263304 """
264305 with self ._refresh_lock :
265- access_token , refresh_token = self ._get_tokens ()
306+ access_token , refresh_token = self ._get_and_update_current_tokens ()
266307 token_to_revoke = access_token or refresh_token
267308 if token_to_revoke is None :
268309 return
0 commit comments