MissingIdentityError on token refresh
csparker247 opened this issue · 6 comments
Last week, I transitioned to using the experimental UserApp
class with JSONTokenStorage
:
from pathlib import Path
from globus_sdk.experimental.globus_app import UserApp, GlobusAppConfig
from globus_sdk.experimental.tokenstorage import JSONTokenStorage
import globus_sdk
# set up app
app_name = 'foo'
app_ns = 'com.foo'
client_id = '#####'
token_store_path = Path().home() / '.globusconf.json'
token_store = JSONTokenStorage(token_store_path, namespace=app_ns)
app = UserApp(app_name=app_name, client_id=client_id,
config=GlobusAppConfig(token_storage=token_store, request_refresh_tokens=True))
# login
app.login()
# create transfer client
client = globus_sdk.TransferClient(app=app, app_name=app_name)
# test endpoint access
# note: I still have to do this to make sure I'm completely logged in
endpoint_uuid = '#####'
try:
client.operation_ls(endpoint_uuid, path='/')
except globus_sdk.TransferAPIError as err:
if not err.info.consent_required:
raise
client.add_app_scope(err.info.consent_required.required_scopes)
app.login() # login again now that scopes have been added
### code to do some file transfers ###
This was working pretty consistently in my tests, so I set up some script runs on timers to do some transfers. The first of these timed script executions completed successfully, but after a while, everything started failing with a MissingIdentityError
at the point that I test the login with operation_lc
:
Traceback (most recent call last):
File "/home/FOO/transfer/copy_tool/copy_tool.py", line 93, in <module>
main()
File "/home/FOO/transfer/copy_tool/copy_tool.py", line 40, in main
client.operation_ls(uuid, path="/")
File "/home/FOO/transfer/venv/lib/python3.10/site-packages/globus_sdk/services/transfer/client.py", line 1214, in operation_ls
self.get(f"operation/endpoint/{endpoint_id}/ls", query_params=query_params)
File "/home/FOO/transfer/venv/lib/python3.10/site-packages/globus_sdk/client.py", line 254, in get
return self.request(
File "/home/FOO/transfer/venv/lib/python3.10/site-packages/globus_sdk/client.py", line 424, in request
r = self.transport.request(
File "/home/FOO/transfer/venv/lib/python3.10/site-packages/globus_sdk/transport/requests.py", line 315, in request
self._set_authz_header(authorizer, req)
File "/home/FOO/transfer/venv/lib/python3.10/site-packages/globus_sdk/transport/requests.py", line 251, in _set_authz_header
authz_header = authorizer.get_authorization_header()
File "/home/FOO/transfer/venv/lib/python3.10/site-packages/globus_sdk/authorizers/renewing.py", line 168, in get_authorization_header
self.ensure_valid_token()
File "/home/FOO/transfer/venv/lib/python3.10/site-packages/globus_sdk/authorizers/renewing.py", line 162, in ensure_valid_token
self._get_new_access_token()
File "/home/FOO/transfer/venv/lib/python3.10/site-packages/globus_sdk/authorizers/renewing.py", line 135, in _get_new_access_token
self.on_refresh(res)
File "/home/FOO/transfer/venv/lib/python3.10/site-packages/globus_sdk/experimental/tokenstorage/base.py", line 108, in store_token_response
self.store_token_data_by_resource_server(token_data_by_resource_server)
File "/home/FOO/transfer/venv/lib/python3.10/site-packages/globus_sdk/experimental/globus_app/_validating_token_storage.py", line 121, in store_token_data_by_resource_server
self._validate_token_data_by_resource_server_meets_identity_requirements(
File "/home/FOO/transfer/venv/lib/python3.10/site-packages/globus_sdk/experimental/globus_app/_validating_token_storage.py", line 194, in _validate_token_data_by_resource_server_meets_identity_requirements
raise MissingIdentityError(
globus_sdk.experimental.globus_app.errors.MissingIdentityError: Token grant response doesn't contain an id_token. This normally occurs if the auth flow didn't include 'openid' alongside other scopes.
After debugging this a bit, it seems that the token has expired and the app is trying to refresh the token, but the new token for the transfer.api.globus.org
resource server does not include the identity_id
field. Despite the suggestion in the exception message, I cannot see how to add the openid
scope to the transfer client scopes (my attempts to do so produce an UnmetScopeRequirementsError
).
The only thing I can do to get this working again is to delete my token store .json
file. app.login(force=True)
does force me to login again, but does not fix the MissingIdentityError
. I do understand that I'm using an experimental API.
Hi there! I think you've uncovered a bug in the implementation.
Every login flow needs to have the openid
scope present, but it sounds like the logic which determines which scopes to present does not ensure this correctly. I'm still trying to work out exactly what's going wrong here -- I think it hinges on the scope requirement for openid
being implicit rather than explicit -- so that we can fix it. Thanks for the bug report!
One minor note on this, as we're working on it right now. I was incorrect about the cause -- there isn't a likely case in which the openid
scope is missing. Instead, the issue is that there's a code path under a UserApp which expects to be getting tokens from a login flow, but is used generically to handle both new tokens from login and the renewed tokens from a refresh.
The token response from refresh has some different characteristics in terms of the data it contains, and needs explicit handling.
We have a series of changes to apply, which will make it simple for the two cases to be distinguished, and will add the appropriate handling for token refreshes.
Just checking in and it seems like this will be fixed by #1055 in the next release, correct? For my own planning, is there an expected date for the next release?
Yep, this was fixed by #1055. We're expecting to cut a release this week (no specific date within the week as of yet) which includes this bugfix.
Excellent! Thank you all for your help and the quick fix.
Of course, thanks for reaching out when you did!
You helped us catch a pretty gnarly bug that would've otherwise likely made it out of experimental!