miguelgrinberg / Flask-HTTPAuth

Simple extension that provides Basic, Digest and Token HTTP authentication for Flask routes
MIT License
1.27k stars 227 forks source link

Token is `None` in containerized setup #161

Open finngaida opened 1 year ago

finngaida commented 1 year ago

Posting here as I'm struggling to find information in other corners of the web. I'm running Flask on a Kubernetes Pod and struggling to properly authenticate my requests.

auth = HTTPTokenAuth(scheme="Bearer")

@auth.verify_token
def auth_verify_token(token: str):
    # ^ here I receive a value of `None`
    return "user"

# app setup, etc... 

@app.route("/test", methods=["GET"])
def test():
    print(request.headers.get('Authorization')) # prints "Bearer <token>" as expected
    return "OK" 

@app.route("/test2", methods=["GET"])
@auth.login_required
def test2():
    # this code is never run, as we get a 401 based on the issue above
    return "OK" 

I should note that when I run this setup locally via flask run everything works as expected.

Any hints, tips, suggestions greatly appreciated.

miguelgrinberg commented 1 year ago

Same versions of everything? You are likely using different versions of Flask, Werkzeug or Flask-HTTPAuth. I suggest you make sure you use the most up to date version of Flask-HTTPAuth, the recent releases of Flask broke some functionality that I had to fix.

finngaida commented 1 year ago

I am on Flask==2.3.2 and Flask-HTTPAuth==4.8.0, do you mean I should pull it from main?

miguelgrinberg commented 1 year ago

What about werkzeug? Did you have all the same versions compared to your working case locally?

finngaida commented 1 year ago

werkzeug==2.3.4 Yes, I built the container from the same source code I run locally, just behind gunicorn instead of the flask run debug server.

miguelgrinberg commented 1 year ago

Well, then I do not know. You must be missing some difference between the working and non working cases. The use of containers does not affect the way this extension works in any way, so I don't see how that can cause this.

finngaida commented 1 year ago

I'll update you here if I find out more

zivsh222 commented 1 year ago

Hi @miguelgrinberg , I also faced this issue. Seems like the token in 'verify_token' (Basic authentication) is None. I upgraded python version from 3.7 to 3.8 and in the requirements we don't lock versions for 'flask' and 'Flask-HTTPAuth'. After seeing this open issue I looked at the versions used. Indeed the versions were different than when it used to work. When locking the versions as they were in python3.7 (but still using 3.8) it does work. Is there any recommendation regarding the versions' combination? This is the combination that does work -

Werkzeug == 2.2.3
flask == 2.2.5
Flask-HTTPAuth == 4.8.0
(both python 3.7 and python 3.8)

This is the combination that didn't work (python 3.8)-

flask-2.3.2
Flask_HTTPAuth-4.8.0
Werkzeug-2.3.6
miguelgrinberg commented 1 year ago

@zivsh222 Thanks for the additional information. There were some compatibility issues with the release of Flask 2.3, but those are fixed in the 4.8.0 version. I'm testing with the token_auth.py example in this repo and I'm not seeing any problems with the versions you reported as being problematic.

zivsh222 commented 1 year ago

Hi @miguelgrinberg , Thanks for checking. I haven't tried this example, but it seems like this sample uses 'bearer' while in my case it's 'basic'. Could it be related?

app = Flask(__name__)
app.auth = HTTPTokenAuth(scheme='Basic')

Also, we're using the decorator as @app.auth.verify_token instead of @auth.verify_token, but I don't think it matters.

miguelgrinberg commented 1 year ago

@zivsh222 You can't send a token with the Basic scheme, there are rules about this scheme that tie it to the Basic Authentication described in the HTTP spec.

Flask 2.3 uses a more robust parser for the Authorization header, for that reason your token now is not parsed anymore. I suggest you switch to the Bearer scheme, which is intended for tokens.

zivsh222 commented 1 year ago

@miguelgrinberg , I don't have access to the calling API, I just implemented the app that gets the requests, but looking here It looks like it is in use. (we use HTTPS)

miguelgrinberg commented 1 year ago

The example you linked shows username and password, that is not a token. Run the code through a base64 decoder to see the actual credentials.

LachlanGreen commented 1 year ago

I solved this issue by changing my Werkzeug version to 2.2.3, i.e, I ran

pip install Werkzeug==2.2.3

and added this line to my requirements.txt:

Werkzeug==2.2.3

It was failing with these:

Flask==2.1.0
Flask-HTTPAuth==4.7.0
Werkzeug==2.3.6

And it is now working with these:

Flask==2.1.0
Flask-HTTPAuth==4.7.0
Werkzeug==2.2.3

All 2.3. versions cause failure.

miguelgrinberg commented 1 year ago

@LachlanGreen this is not a great solution. As I explained above, the problem is that your application is incorrectly using the Authorization header. In older versions of Werkzeug, the bad usage was not detected. Werkzeug 2.3 correctly rejects those bad headers, and for that reason your application fails. Instead of downgrading Werkzeug, you should fix your application to make correct use of the Authorization header.

Roobxyz commented 1 year ago

I am experiencing this too, using the Bearer scheme. Think something is wrong.

prophund commented 12 months ago

I am experiencing this too, using the Bearer scheme.

Upgrade to 4.8.0 of flask-httpauth as there were improvements in getting the token from the auth packet. That fixed it for me.

flask==2.3.3 Flask-HTTPAuth==4.8.0