box / box-python-sdk-gen

Repository for generated Box Python SDK
Apache License 2.0
29 stars 5 forks source link

client.search.search_for_content yields jwt error with JWT auth #232

Closed wellsoliver closed 3 months ago

wellsoliver commented 4 months ago

Using JWT auth in the following fashion, with jwt 1.3.1 installed:

jwt_config = JWTConfig.from_config_file(os.environ["BOX_SECRETS_FILE"])
auth = BoxJWTAuth(config=jwt_config)
client = BoxClient(auth)

Auth works, but calling client.search.search_for_content(...) throws a jwt exception:

  File "foo.py", line 27, in <module>
    clip_list = client.search.search_for_content(
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/virtualenvs/foo-n7QfOOfb-py3.11/lib/python3.11/site-packages/box_sdk_gen/managers/search.py", line 545, in search_for_content
    response: FetchResponse = fetch(
                              ^^^^^^
  File "/virtualenvs/foo-n7QfOOfb-py3.11/lib/python3.11/site-packages/box_sdk_gen/networking/fetch.py", line 106, in fetch
    request: APIRequest = __prepare_request(
                          ^^^^^^^^^^^^^^^^^^
  File "/virtualenvs/foo-n7QfOOfb-py3.11/lib/python3.11/site-packages/box_sdk_gen/networking/fetch.py", line 165, in __prepare_request
    headers = __prepare_headers(options, reauthenticate)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/virtualenvs/foo-n7QfOOfb-py3.11/lib/python3.11/site-packages/box_sdk_gen/networking/fetch.py", line 207, in __prepare_headers
    headers['Authorization'] = options.auth.retrieve_authorization_header(
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/virtualenvs/foo-n7QfOOfb-py3.11/lib/python3.11/site-packages/box_sdk_gen/box/jwt_auth.py", line 337, in retrieve_authorization_header
    token: AccessToken = self.retrieve_token(network_session=network_session)
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/virtualenvs/foo-n7QfOOfb-py3.11/lib/python3.11/site-packages/box_sdk_gen/box/jwt_auth.py", line 330, in retrieve_token
    new_token: AccessToken = self.refresh_token(network_session=network_session)
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/virtualenvs/foo-n7QfOOfb-py3.11/lib/python3.11/site-packages/box_sdk_gen/box/jwt_auth.py", line 305, in refresh_token
    assertion: str = create_jwt_assertion(claims, jwt_key, jwt_options)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/virtualenvs/foo-n7QfOOfb-py3.11/lib/python3.11/site-packages/box_sdk_gen/internal/utils.py", line 272, in create_jwt_assertion
    return jwt.encode(
           ^^^^^^^^^^
AttributeError: module 'jwt' has no attribute 'encode'

This can be resolved in a hacky way by also installing pyjwt and I say hacky because both libraries insall into the jwt directory in site-packages, and both contain three files of the same name including jwt.py so it's a matter of making sure pyjwt is installed after jwt.

My full search is a date range which looks like:

filter = MetadataFilter(
    scope="...",
    template_key="...",
    filters={
        "uploadDate": MetadataFieldFilterDateRange(
            gt=date_time_from_string(then.strftime(frtime)),
            lt=date_time_from_string(now.strftime(frtime)),
        )
    },
)

clip_list = client.search.search_for_content(
    ancestor_folder_ids=["0"], mdfilters=[filter]
)

Not sure if there's another way of doing what I am doing, seems like standard (and broken?) API usage when using JWT.

lukaszsocha2 commented 3 months ago

Hi @wellsoliver , installing a pyjwt is not a hacky way, but it is required for JWT Auth to work correctly. In our docs we have a section about using JWT (it can be found here). It is stated that to use JWT Auth you should use pip install box-sdk-gen[jwt] command. That installs all required dependencies for jwt auth including pyjwt - jwt_requires = ['pyjwt>=1.7.0', 'cryptography>=3'] (part of setup.py file). If you use box-sdk-gen in requirements.txt file, just use box-sdk-gen[jwt] there to fetch all requirements.

Installing this https://pypi.org/project/jwt/ library is not necessary at all. We don't use that library in this project. I'm closing this issue as this is done by design, but feel free to reopen it if you have any questions. Best, @lukaszsocha2

wellsoliver commented 3 months ago

Thanks for the detail. Not to reopen, but in case anyone stumbles across this and uses poetry instead of a requirements file, running poetry add pyjwt cryptography helps solve this issue, at the time of writing this with pyjwt 2.8.0 and cryptography 43.0.0 -- no need for jwt itself, as stated. Might be useful to update the box docs with a poetry section re: JWT...