okta / okta-jwt-verifier-python

okta-jwt-verifier-python
https://github.com/okta/okta-jwt-verifier-python
Apache License 2.0
32 stars 15 forks source link

AccessTokenVerifier verify fails when first retrieving JWK #22

Closed tl24 closed 2 years ago

tl24 commented 2 years ago

We are having an issue that seems to be on first call to verify when it tries to retrieve the JWK. It looks like a timeout value is not being passed to acachecontrol somewhere. But I guess it still gets cached as subsequent calls succeed.

I get this issue calling AcessTokenVerifier.verify with an auth token from a custom okta auth server.

 File "/home/someuser/venvs/myproject/lib/python3.8/site-packages/okta_jwt_verifier/jwt_verifier.py", line 96, in verify_access_token
    okta_jwk = await self.get_jwk(headers['kid'])
  File "/home/someuser/venvs/myproject/lib/python3.8/site-packages/okta_jwt_verifier/jwt_verifier.py", line 198, in get_jwk
    jwks = await self.get_jwks()
  File "/home/someuser/venvs/myproject/lib/python3.8/site-packages/okta_jwt_verifier/jwt_verifier.py", line 218, in get_jwks
    jwks = await self.request_executor.get(jwks_uri, headers=headers)
  File "/home/someuser/venvs/myproject/lib/python3.8/site-packages/okta_jwt_verifier/request_executor.py", line 32, in fire_request
    async with cached_sess.get(uri, **params) as resp:
  File "/home/someuser/venvs/myproject/lib/python3.8/site-packages/acachecontrol/request_context_manager.py", line 17, in __aenter__
    await self.cache.register_new_key(self.key, self.timeout)
  File "/home/someuser/venvs/myproject/lib/python3.8/site-packages/acachecontrol/cache.py", line 115, in register_new_key
    if total_wait_time >= timeout:
TypeError: '>=' not supported between instances of 'float' and 'NoneType'

I'm using okta-jwt-verifier 0.2.0 Calling code:

from functools import lru_cache
from okta_jwt_verifier import AccessTokenVerifier, JWTUtils

# cache this so we cache the jwk keys
@lru_cache
def get_verifier(issuer, audience):
    return AccessTokenVerifier(issuer, audience)

async def decode_token(token, issuer, audience):
    """Decode an JWT token"""
    verifier = get_verifier(issuer, audience)
    await verifier.verify(token)
    _, claims, _, _ = JWTUtils.parse_token(token)

    return claims
serhiibuniak-okta commented 2 years ago

@tl24 Thanks for posting this issue. I'll take a look. But first, I'd like to clarify few things regarding your code: 1) entrypoint is decode_token func, right? 2) why do you cache verifier if it should cache jwks by itself https://github.com/okta/okta-jwt-verifier-python/blob/master/okta_jwt_verifier/jwt_verifier.py#L24 ?

serhiibuniak-okta commented 2 years ago

@tl24 Yes, you're right, timeout value is not being passed. As a temporary workaround I can suggest use custom RequestExecutor, where you can pass timeout via fire_request method. Meanwhile, I'll fix this issue.

tl24 commented 2 years ago
  1. entrypoint is decode_token, correct
  2. If I'm reading the code correctly, the JWKs are only cached within that instance of the JWTVerifier instance not at a class level. That is why I'm caching the verifier instance. Am I correct on that?
serhiibuniak-okta commented 2 years ago

Yes, thanks. Fix is ready and currently pending review. I'll post here when we release new version.

serhiibuniak-okta commented 2 years ago

@tl24 jwt-verifier v0.2.1 has been released. I'm closing this issue as resolved. Feel free to reopen this issue or create a new one if your problem exists still