JWT token error with Zoom API

Summary:
A few days ago, my app which schedules Zoom meetings quit working.
API calls are returning: {“code”:124,“message”:“Invalid access token.”}
Are there any issues around time as part of the JWT token that could be causing me issues?

Detail:

Everything has been working fine for several months and in my local code which is set up identical is executing API calls just fine.

I am using the ZoomUS package(so a server module) as the API wrapper which handles the JWT encoding.

Reading up a little expiration time is an important part of the JWT.
Can anyone think of any quarks around time that could be the issue?
The token expiration uses 60 minutes added to time.time
** I have verified key and secret in the app are correct.

from the package source code:
https://github.com/prschmid/zoomus/blob/develop/zoomus/util.py
Line 262

def generate_jwt(key, secret):
    header = {"alg": "HS256", "typ": "JWT"}

    payload = {"iss": key, "exp": int(time.time() + 3600)}

    token = jwt.encode(payload, secret, algorithm="HS256", headers=header)
    return token

I have also tried the ZoomUS def refresh_token() and rerun but did not work.

The app sets up the Zoom client like this in a server module

from zoomus import ZoomClient

# Get Secrets
api_key = anvil.secrets.get_secret('zoom_jwt_apikey')
api_secret = anvil.secrets.get_secret('zoom_jwt_apisecret')

# create zoom object
client = ZoomClient(api_key, api_secret)

Think I am down the root . . . not sure how to create a global solution. Any ideas

After many hours of trial and error the issue seems to be in the encoding of the token. In comparing the jwt token between Anvil and my local environment I eventually noticed that the token in the Anvil object was a byte object and the local token was a string.

This got me back up and running:

  print(client.config.get("token"))
  client.config['token'] = client.config.get("token").decode("utf-8")
  print(client.config.get("token"))

Is it possible that pyJWT was rolled back in the server packages?

Not an expert on how and when this class instantiates every time I use it. Do I need to add this every time I call the API in a function?

Is it possible to have two versions of pyJWT in server packages? Then how to do I guarantee that the server package that is calling this package uses the correct version?

Little further digging: the PyJWT package switched to returning a string instead of a byte in version 2.0.
Anvils server package is at 1.7.1.

According to change log:
V 2.0 changed output of token from byte to string
https://pyjwt.readthedocs.io/en/latest/changelog.html

Local version of Python using 2.1

An Anvils server packages state

Thanks Support,

Bumped package version and now everything is back to working. :+1:

1 Like

Note To Self

First time I have ever had to deal with a package dependency issue. This is difficult in Anvil because we do not control the packages or have the ability to pin their versions.

Possibly write a script that will check package versions and write to log table. Next time something breaks unexpectedly, I will check for changes in dependencies first.

This can be done inside Python with

>>> import pkg_resources
>>> pkg_resources.get_distribution('construct').version
'2.5.2'

Now, how to get a list of all packages and dependencies, without going through every import and manually looking up the dependency chain?
This might be the start:

1 Like

I wonder if scraping the info directly off this page might be a good idea:

It looks like it keeps up to date, the PyJWT module you had them upgrade is now listed as 2.3.0

2 Likes