Open evgenyfadeev opened 2 years ago
@evgenyfadeev This library designed to be used with Okta, thus some features (for example, get jwk for verifying signature) may not work with other oidc providers (the only working case - URI for jwk is being constructed in the same way).
On the other hand, it is possible to use this library and override all methods you might need. Also, there is a separate module https://github.com/okta/okta-jwt-verifier-python/blob/master/okta_jwt_verifier/jwt_utils.py which have common methods such as parse_token
and should work with any jwt.
Thanks! Perhaps you could set the jwk_url
as an additional parameter to IDTokenVerifier
and AccessTokenVerifier
? I could make a PR for that...
That doesn't align with our design. On the other hand you can inherit and override anything.
This worked for me - a subclass of BaseJWTVerifier
that receives jwks_uri
and overrides the _construct_jwks_uri
method.
Later to validate the tokens I called the verify_access_token
and verify_id_token
the same way as in the
Btw, not sure why you're not relying on the discovery data for the jwks_uri instead of making assumptions about this url.
from okta_jwt_verifier import BaseJWTVerifier
class JWTVerifier(BaseJWTVerifier):
"""Wrapper around the `BaseJwtVerifier`
main purpose is to allow passing the `jwks_uri`
and not be making an assumption about the url structure.
"""
def __init__(self,
issuer=None,
client_id=None,
jwks_uri=None,
audience=None,
max_retries=1,
request_timeout=30,
max_requests=10,
leeway=120,
cache_jwks=True,
proxy=None):
self.jwks_uri = jwks_uri
super().__init__(issuer=issuer,
client_id=client_id,
audience=audience,
max_retries=max_retries,
request_timeout=request_timeout,
max_requests=max_requests,
leeway=leeway,
cache_jwks=cache_jwks,
proxy=proxy)
def _construct_jwks_uri(self):
"""Bypasses the okta assumptions"""
return self.jwks_uri`
@evgenyfadeev I'm glad that you've found a solution. Do you mean an additional network call by "discovery data for the jwks_uri"? In this case, we don't need unnecessary network calls: this jwks uri for Okta's orgs has been designed in that way and hasn't been changed for years. What I see from your approach - you can tweak it easily for your needs, I believe, it's fine. I can suggest one more approach: basically, in order to validate token you need to perform the following steps:
All of these steps are defined within okta_jwt_verifier/jwt_utils.py
, so in theory you can write something like this (it's just a sample pseudocode):
from okta_jwt_verifier import JWTUtils
def verify_access_token(token, jwk):
headers, claims, signing_input, signature = JWTUtils.parse_token(token)
JWTUtils.verify_claims(claims, claims_to_verify=['iss', 'aud', 'exp'])
JWTUtils.verify_signature(token, jwk)
@all can we use this library in flask based web application synchronously since most methods are asynchronous in my case i need verify signature each and every call but my public key is available in remote server.
do i need to do following steps
1. I need to download JWK from server then I need to pass key explicitly
JWTUtils.verify_signature(token, jwk)
@kadhir-p44 There are few options:
1) https://flask.palletsprojects.com/en/2.0.x/async-await/
2) use asyncio.run
to call async methods
3) maybe something else is possible within Flask, but need to investigate
@kadhir-p44 There are few options:
- https://flask.palletsprojects.com/en/2.0.x/async-await/
- use
asyncio.run
to call async methods- maybe something else is possible within Flask, but need to investigate
@serhiibunaik
my concern is every request i need call asyncio.run () eventually it create another thread and i need to wait for result and it cause slow down my service isn't it? i expect something like java library
meanwhile i am getting following error on python 3.8 and ubuntu 20.04
okta_jwt_verifier.exceptions.JWTValidationException: 0, message='Attempt to decode JSON with unexpected mimetype: text/plain;charset=utf-8', url=URL('https://****/oauth2/v1/keys')
Regarding your error you are receiving. Can you run:
import aiohttp
import asyncio
async def main():
keys_url = 'https://{YOUR_ORG}/oauth2/default/v1/keys'
async with aiohttp.ClientSession() as session:
async with await session.get(keys_url) as resp:
print(await resp.json())
asyncio.run(main())
And let us know what is returned? If the above returns an error still, could you try swapping the resp.json
to be await resp.json(content_type=None)
Just a question - as is the title. I'm looking for a generic implementation of openid-connect. Can the token verifier be configured for use with other oidc providers?
Thanks!