okta / okta-jwt-verifier-python

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

RuntimeError: There is no current event loop in thread #14

Closed summersz closed 3 years ago

summersz commented 3 years ago

I have implemented the examples into a Flask api but receive the following error: RuntimeError: There is no current event loop in thread 'Thread-3'

It seems that get_event_loop() will only create a new event loop if it is running on the main thread. Is there a reason that the event loop is created like this rather than using asyncio.run()?

Alternatively, can the event loop be created using the following:

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)

I am unfamiliar with asyncio and am not sure what the ramifications are of using either option.

serhiibuniak-okta commented 3 years ago

@summersz Could you please, provide more details, maybe share some code or post some instructions what and when it happens, etc.?

Upd: asyncio.run() - introduced in Python3.7, you can use it. But if someone need to make it working with Python3.6+, then should use given approach

summersz commented 3 years ago

Thanks @serhiibuniak-okta. I have the below module to create a decorator that is called on protected routes. The error is thrown when a request is made to a protected route. I am using Python 3.7 so will proceed with using asyncio.run().

import asyncio
from flask import current_app, request
from okta_jwt_verifier import JWTVerifier
from functools import wraps

class JWTBaseException(Exception):
    pass

class NoAuthorizationError(JWTBaseException):
    pass

loop = asyncio.get_event_loop()

def token_required(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        try:
            verify_token()
        except:
            return "Unauthorized", 401
        return f(*args, **kwargs)
    return wrapper

def verify_token():
    if request.method == 'OPTIONS':
        return
    try:
        token = request.headers.get("Authorization").split("Bearer ")[1]
    except:
        raise NoAuthorizationError
    try: 
        is_access_token_valid(token) 
    except NoAuthorizationError:
        raise

def is_access_token_valid(token):
    jwt_verifier = JWTVerifier(current_app.config['OKTA_ISSUER'],current_app.config['OKTA_CLIENT_ID'], current_app.config['OKTA_AUDIENCE'])
    try:
        loop.run_until_complete(jwt_verifier.verify_access_token(token))
        # asyncio.run(jwt_verifier.verify_access_token(token))
        return
    except Exception:
        raise NoAuthorizationError
Traceback (most recent call last):
  File "C:\Users\summersra\Python\AutopilotAPI\AutopilotAPI\__init__.py", line 4, in <module>
    from AutopilotAPI.routes import initialize_routes
  File "C:\Users\summersra\Python\AutopilotAPI\AutopilotAPI\routes.py", line 3, in <module>
    from .Resources.CHK.BFM import *
  File "C:\Users\summersra\Python\AutopilotAPI\AutopilotAPI\Resources\CHK\BFM.py", line 1, in <module>
    from AutopilotAPI.okta_auth import token_required
  File "C:\Users\summersra\Python\AutopilotAPI\AutopilotAPI\okta_auth.py", line 12, in <module>
    loop = asyncio.get_event_loop()
  File "C:\Python38\Lib\asyncio\events.py", line 639, in get_event_loop
    raise RuntimeError('There is no current event loop in thread %r.'
RuntimeError: There is no current event loop in thread 'Thread-3'.
serhiibuniak-okta commented 3 years ago

@summersz , usually, this kind of error happens, when no event loop is started. It would be good to see full code, but looks like the problem is in "token_required" function, from this doc https://flask.palletsprojects.com/en/2.0.x/async-await/ it should be like the following:

def extension(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        ...  # Extension logic
        return current_app.ensure_sync(func)(*args, **kwargs)

    return wrapper

A bit another approach how to handle async code, you can find within these samples https://github.com/okta/samples-python-flask

Let me know if anything helps. Otherwise, it would be good to see the whole code (without any sensitive info, of course) and I'll be able to help more.

serhiibuniak-okta commented 3 years ago

@summersz I'm closing this issue as stalled. Feel free to reopen this issue or create a new one if your problem exists still.