Internal Server Error, rather than raised AuthError response from Auth0 - python

I have my flask-restful app.py which contains all of my main functions. I have created a server.py file as instructed from here: https://auth0.com/docs/quickstart/backend/python
In my app.py file from server i import AuthError and requires_auth. I have then put #requires_auth in front of my functions.
When I have a valid jwt, it works perfectly. When the jwt is not valid it fails. Failing is good, because the requests shouldn't work. But the response i get from my api is "Internal Server Error" rather than the detailed response in the raise AuthError section in the server.py file.
I get 2 errors:
Traceback (most recent call last):
File "C:\Users\ME\code\server.py", line 88, in decorated
issuer="https://"+AUTH0_DOMAIN+"/"
File "C:\Users\ME\lib\site-packages\jose\jwt.py", line 150, in decode
options=defaults)
File "C:\Users\ME\lib\site-packages\jose\jwt.py", line 457, in _validate_claims
_validate_exp(claims, leeway=leeway)
File "C:\Users\ME\lib\site-packages\jose\jwt.py", line 299, in _validate_exp
raise ExpiredSignatureError('Signature has expired.')
jose.exceptions.ExpiredSignatureError: Signature has expired.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\ME\lib\site-packages\flask\app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\ME\lib\site-packages\flask\app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:\Users\ME\lib\site-packages\flask_restful\__init__.py", line 480, in wrapper
resp = resource(*args, **kwargs)
File "C:\Users\ME\lib\site-packages\flask\views.py", line 88, in view
return self.dispatch_request(*args, **kwargs)
File "C:\Users\ME\lib\site-packages\flask_restful\__init__.py", line 595, in dispatch_request
resp = meth(*args, **kwargs)
File "C:\Users\ME\code\server.py", line 92, in decorated
"description": "token is expired"}, 401)
server.AuthError: ({'code': 'token_expired', 'description': 'token is expired'}, 401)
How do i get the AuthError as the response to the call, rather than just my Internal Server Error?
Thanks!

There is an issue with this specific tutorial in Auth0, it instructs you to include the error handler in auth.py:
#app.errorhandler(AuthError)
def handle_auth_error(ex):
response = jsonify(ex.error)
response.status_code = ex.status_code
return response
Instead, you have to include this handler in your app.py, where you actually use #requires_auth.
Notice that to do so, you need to add relevant imports:
from auth import AuthError
from flask import jsonify
Notice: To be able to import from auth.py you need to add an empty file __init__.py in the same directory.

Try setting app.config[“PROPAGATE_EXCEPTIONS”] = True

Uou could maybe use an errorhandler to explicitly catch those errors and return some explicit json based on them.

Related

How to use asyncio with Flask?

Hello everyone I will explain my problem as clearly as possible. I have a Flask application and I want to retrieve the uid from the url settings and then check if the user exists in my Firebase Cloud Firestore using an await.
But I have an error, when my application has to process the same request several times in a short time, I have this error:
127.0.0.1 - - [27/Sep/2022 22:37:04] "GET /firestore/petale?uid=user123456789 HTTP/1.1" 200 -
[2022-09-27 22:37:08,883] ERROR in app: Exception on /firestore/petale?uid=user123456789 [GET]
Traceback (most recent call last):
File "C:\Users\HP\IdeaProjects\flaskapp\lib\site-packages\flask\app.py", line 2525, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\HP\IdeaProjects\flaskapp\lib\site-packages\flask\app.py", line 1822, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\HP\IdeaProjects\flaskapp\lib\site-packages\flask\app.py", line 1820, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\HP\IdeaProjects\flaskapp\lib\site-packages\flask\app.py", line 1796, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
File "C:\Users\HP\PycharmProjects\flaskapp\routes\petale.py", line 14, in index
loop = asyncio.run(checkUid(uid))
File "C:\Users\HP\AppData\Local\Programs\Python\Python310\lib\asyncio\runners.py", line 44, in run
return loop.run_until_complete(main)
File "C:\Users\HP\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 646, in run_until_complete
return future.result()
File "C:\Users\HP\PycharmProjects\flaskapp\routes\petale.py", line 21, in checkUid
uid_doc = await document.get()
File "C:\Users\HP\IdeaProjects\flaskapp\lib\site-packages\google\cloud\firestore_v1\async_document.py", line 367, in get
response_iter = await self._client._firestore_api.batch_get_documents(
File "C:\Users\HP\IdeaProjects\flaskapp\lib\site-packages\google\api_core\grpc_helpers_async.py", line 168, in error_remapped_callable
call = callable_(*args, **kwargs)
File "C:\Users\HP\IdeaProjects\flaskapp\lib\site-packages\grpc\aio\_channel.py", line 168, in __call__
call = UnaryStreamCall(request, deadline, metadata, credentials,
File "C:\Users\HP\IdeaProjects\flaskapp\lib\site-packages\grpc\aio\_call.py", line 555, in __init__
self._send_unary_request_task = loop.create_task(
File "C:\Users\HP\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 436, in create_task
self._check_closed()
File "C:\Users\HP\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 515, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
127.0.0.1 - - [27/Sep/2022 22:37:08] "GET /firestore/petale?uid=user123456789 HTTP/1.1" 500 -
The highlighted error is: RuntimeError: Event loop is closed
You should know that I'm quite new to all the async/await methods, I come from Android with Java and it's not common for me. After several tests I could see that it comes from the line that retrieves the user's document with the await uid_doc = await document.get()
Searching on the internet I could see that people have this problem when they use the asyncio package, but I had not used it in my code. I decided to use it but I still have the same error and I don't know how to fix the problem. I don't really understand how to use asyncio.
import asyncio
from flask import Blueprint, request
from firebase_admin import firestore_async
petale = Blueprint("petale", __name__)
collection = firestore_async.client().collection('xxxx')
#petale.route("/petale", methods=['GET'])
def index():
uid = request.args.get('uid')
asyncio.set_event_loop(asyncio.new_event_loop())
loop = asyncio.run(checkUid(uid))
return loop
async def checkUid(uid):
document = collection.document(uid)
uid_doc = await document.get()
if uid_doc.exists:
return "Exists"
else:
return "Error"
I tried aioflask but there are many problems with it, I tried installing pip install flask[async] but it doesn't work either.
I'm a bit desperate, can you help me?
Thanks a lot!

eBay and Authlib Unconventional token type

I'm trying to use Authlib library to access new eBay REST API (as Authorization code grant)
Here is my code;
import json
import os
import webbrowser
from time import time
from authlib.integrations.requests_client import OAuth2Session
from rpi_order_data_sync import settings
def auth(seller):
def token_updater(token, seller=seller):
if not os.path.exists(seller):
open(seller, "w").close()
with open(seller, "w") as token_file:
json.dump(token, token_file)
scope = ["https://api.ebay.com/oauth/api_scope/sell.fulfillment.readonly"]
if not os.path.exists(seller):
ebay = OAuth2Session(
settings.E_APP_ID,
settings.E_CERT_ID,
redirect_uri=settings.E_RU_NAME,
scope=scope,
)
uri, state = ebay.create_authorization_url(
"https://auth.sandbox.ebay.com/oauth2/authorize",
)
print("Please go to {} and authorize access.".format(uri))
try:
webbrowser.open_new_tab(uri)
except webbrowser.Error:
pass
authorization_response = input("Please enter callback URL: ") # nosec
token = ebay.fetch_token(
"https://api.sandbox.ebay.com/identity/v1/oauth2/token",
authorization_response=authorization_response,
)
print(token)
token_updater(token)
return ebay
The problem is eBay's token response has an unconventional token type named "User Access Token" instead of "Bearer". Therefore I get this error;
Traceback (most recent call last):
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/authlib/integrations/requests_client/oauth2_session.py", line 37, in __call__
req.url, req.headers, req.body = self.prepare(
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/authlib/oauth2/auth.py", line 91, in prepare
sign = self.SIGN_METHODS[token_type.lower()]
KeyError: 'user access token'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/bin/rods", line 11, in <module>
load_entry_point('rpi-order-data-sync', 'console_scripts', 'rods')()
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/click/core.py", line 829, in __call__
return self.main(*args, **kwargs)
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/click/core.py", line 782, in main
rv = self.invoke(ctx)
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/click/core.py", line 1259, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/click/core.py", line 1066, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
File "/home/thiras/HDD/freelancer/contentassasin/rpi-order-data-sync/rpi_order_data_sync/main.py", line 132, in sync_ebay_orders
orders = ebay.get(
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/requests/sessions.py", line 543, in get
return self.request('GET', url, **kwargs)
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/authlib/integrations/requests_client/oauth2_session.py", line 113, in request
return super(OAuth2Session, self).request(
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/requests/sessions.py", line 516, in request
prep = self.prepare_request(req)
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/requests/sessions.py", line 449, in prepare_request
p.prepare(
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/requests/models.py", line 318, in prepare
self.prepare_auth(auth, url)
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/requests/models.py", line 549, in prepare_auth
r = auth(self)
File "/home/thiras/.local/share/virtualenvs/rpi-order-data-sync-tA0i1rrc/lib/python3.8/site-packages/authlib/integrations/requests_client/oauth2_session.py", line 41, in __call__
raise UnsupportedTokenTypeError(description=description)
authlib.integrations.base_client.errors.UnsupportedTokenTypeError: unsupported_token_type: Unsupported token_type: 'user access token'
I've noticed Compliance fix for non-standard section at Authlib documentation but couldn't figure out how to do this fix or even possible in this way.
I've found a solution and it also works with requests-oauthlib package. It seems working flawlessly so far. The main struggle was to create a fake request.Response model since request.Response has no setter for .text or .content attributes so modifying them was impossible.
So I've created a FakeResponse class that only mimics .json() method since it was the only method used by Authlib.
class FakeResponse:
""" Fake Class for Request Response class. """
def __init__(self, data):
self.data = data
def json(self):
""" Mocks requests.Response.json(). """
return self.data
After that I've created an access_token_response hook;
def non_compliant_token_type(resp):
data = resp.json()
data["token_type"] = "Bearer"
fake_resp = FakeResponse(data=data)
return fake_resp
Please let me know if you have a better answer or any recommendations to improve it.

Using url_for in flask for external URLs returns werkzeug.routing.BuildError

I have written a flask server which in some cases redirects the user to external sites. I wrote some unit tests using python unittest module. For some of them which are testing the redirect part, I get werkzeug.routing.BuildError. Here is the code for one of the test cases:
with app.app_context(), app.test_request_context():
response = self.app.get('/{0}'.format(test_url), follow_redirects=False)
self.assertEqual(response.status_code, 302)
self.assertEqual(response.location, url_for('https://www.linkedin.com/in/zeinab-abbasimazar-0327aa47', _external=True, _scheme='https'))
And this is the full stack trace:
Ran 1 test in 3.211s
FAILED (errors=1)
Error
Traceback (most recent call last):
File "/usr/lib/python3.6/unittest/case.py", line 59, in testPartExecutor
yield
File "/usr/lib/python3.6/unittest/case.py", line 605, in run
testMethod()
File "/home/zeinab/PycharmProjects/url_shortener/tests.py", line 167, in test_get_long_existing_url
self.assertEqual(response.location, url_for(long_url, _external=True, _scheme='https'))
File "/home/zeinab/.local/lib/python3.6/site-packages/flask/helpers.py", line 370, in url_for
return appctx.app.handle_url_build_error(error, endpoint, values)
File "/home/zeinab/.local/lib/python3.6/site-packages/flask/app.py", line 2215, in handle_url_build_error
reraise(exc_type, exc_value, tb)
File "/home/zeinab/.local/lib/python3.6/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/home/zeinab/.local/lib/python3.6/site-packages/flask/helpers.py", line 358, in url_for
endpoint, values, method=method, force_external=external
File "/home/zeinab/.local/lib/python3.6/site-packages/werkzeug/routing.py", line 2020, in build
raise BuildError(endpoint, values, method, self)
werkzeug.routing.BuildError: Could not build url for endpoint 'https://www.linkedin.com/in/zeinab-abbasimazar-0327aa47'. Did you mean 'static' instead?
Assertion failed
I have also following line in the setUp method:
app.config['PREFERRED_URL_SCHEME'] = 'https'
I tried patching url_for method as described in this question; but it didn't change my result.
I also tried the _force_https method explained here and saw no change.
I printed out the app.config['wsgi.url_scheme'] when I read this page and it was https.
I am using python 3.6 on an Ubuntu system. Can anyone help me fix this error?
Use directly string with url without url_for()
self.assertEqual(response.location, 'https://www.linkedin.com/in/zeinab-abbasimazar-0327aa47')
Normally url_for() also creates string with url but it do it only for function names in your code - url_for(function_name) - not for urls.

Flask: requests to subdirectory of static return 500

I'm aware that once I have everything up and running on a production server, nginx or apache are supposed to be serving static assets instead of Flask. In the interest of getting started quickly though, I'm running into an issue with Flask and requests to files in subdirectories of static.
A request for /static/test.css returns correctly, but a request for /static/test/test.css returns a 500 and throws this exception:
Traceback (most recent call last):
File "/home/tim/shadowcraft-ui-python/venv/lib/python3.5/site-packages/flask/app.py", line 1991, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/home/tim/shadowcraft-ui-python/venv/lib/python3.5/site-packages/flask/app.py", line 1567, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/tim/shadowcraft-ui-python/venv/lib/python3.5/site-packages/flask/_compat.py", line 33, in reraise
raise value
File "/home/tim/shadowcraft-ui-python/venv/lib/python3.5/site-packages/flask/app.py", line 1988, in wsgi_app
response = self.full_dispatch_request()
File "/home/tim/shadowcraft-ui-python/venv/lib/python3.5/site-packages/flask/app.py", line 1642, in full_dispatch_request
response = self.make_response(rv)
File "/home/tim/shadowcraft-ui-python/venv/lib/python3.5/site-packages/flask/app.py", line 1731, in make_response
raise ValueError('View function did not return a response')
ValueError: View function did not return a response
A bit of searching on that error returns mostly simple cases where someone forgot a return in a request handler, but nothing for when making direct requests for assets. It also does the same thing if trying to use url_for in a template to request the file from the subdirectory.
This ended up being an error in my code. I have a route handler that takes three parts as arguments, and since that handler isn't implemented yet, it caused Flask to throw the exception above. I ended up implementing the solution from Does Flask support regular expressions in its URL routing? for that handler since I know the first part is always one of a few different values, and the static handler can run as normal.

Flask-Sijax callbacks are "working outside of request context"

While inside a callback function, I lose the ability to access flask.session, flask.g, or functions such as url_for(). They all throw an error saying that I'm "working outside of request context".
Debugging middleware caught exception in streamed response at a point where response headers were already sent.
Traceback (most recent call last):
File "C:\Python27\site-packages\sijax\response\streaming.py", line 136, in _process_call_chain
for string in generator:
File "C:\Python27\site-packages\sijax\response\streaming.py", line 109, in _process_callback
response = self._perform_handler_call(callback, args)
File "C:\Python27\site-packages\sijax\response\base.py", line 258, in _perform_handler_call
return callback(self, *args)
File "C:\Dropbox\Code\Python 2.7\FlaskTesting\testpage.py", line 18, in myformhandler
sql_session = flask.g.sql_session
File "C:\Python27\lib\site-packages\werkzeug\local.py", line 336, in __getattr__
return getattr(self._get_current_object(), name)
File "C:\Python27\lib\site-packages\werkzeug\local.py", line 295, in _get_current_object
return self.__local()
File "C:\Python27\lib\site-packages\flask\globals.py", line 19, in _lookup_object
raise RuntimeError('working outside of request context')
RuntimeError: working outside of request context
192.168.1.141 - - [20/Jun/2012 16:33:04] "POST /testpage HTTP/1.1" 200 -
I've been unable to find out how to get around this problem. Any help would be appreciated.
Python v2.7
Flask v0.8
Flask-Sijax v0.3
You may have a try with stream_with_context. The code example copied from http://flask.pocoo.org/docs/0.12/patterns/streaming/#streaming-with-context
from flask import stream_with_context, request, Response
#app.route('/stream')
def streamed_response():
def generate():
yield 'Hello '
yield request.args['name']
yield '!'
return Response(stream_with_context(generate()))
It would be helpful if you posted your code, but try wrapping your code like this:
with app.app_context():
# do stuff...
or maybe this:
with app.test_request_context():
# do stuff...

Categories