CSRF Token Error when using gunicorn and Flask
Asked Answered
E

2

5

I've developed a web app that includes the functionality for users to log in and signup. I've done everything as per documentation and tutorials, and everything works fine with the flask server.

The issue is: I use gunicorn and start a web server, open the address (localhost:8000) on few different browsers (Brave and Firefox on Linux, and Brave on Android), I can only log in (Single or multiple different users) from only one client. When I try to do so from another one, it throws 400 Bad Request (CSRF Session token missing or CSRF Session tokens do no match).

Now, this doesn't happen when using Flasks Server. It only happens while using gunicorn.

I've deployed the application to Heroku (Using the Free plan), and I want multiple users to sign in at the same time. This happens on all of the other forms my app has.

All environment variables, secret keys are correctly configured, everything works as intended when using Flask Server. Using Gunicorn doesn't cause any other issues except this. Sometimes, logging in from a single client doesn't work too.

Any help would be appreciated. I've already looked at other threads/questions that were related, but they didn't mention the problem I have

Engud answered 16/12, 2019 at 16:39 Comment(2)
Perhaps you could give more information how this is configured, some example that others can use to reproduce the problem?Sitology
Also see this question/Answer: #39684864Lodi
F
7

Sorry for the late reply (Maybe it can help someone in the future)

The short answer :
use :

with app.app_context():
    your code

instead of :

app.app_context().push()

which is never closed

The long answer :

I guess you use Flask-WTF for managing CSRF, If yes, there is an if bloc (https://github.com/wtforms/flask-wtf/blob/0.15.x/src/flask_wtf/csrf.py#L53) in the generate_csrf function, which check the flask g variable before generating a new CSRF token. It works perfectly, but when the g variable doesn't reinitilize on each new request (see below for the cause) it creates a conflict between the different users trying to log in.

The principal cause of not reinitilizing the flask g variable is an app context which is pushed manually (usually by : app.app_context().push()) but not closed, in this case the app context is never torn down see : Flask app.teardown_appcontext not being called when DEBUG is false

Finally, i think there is something in the flask DEBUG mode, which force tearing down the app context and reinitilize the g variable.

Ferula answered 2/6, 2021 at 14:21 Comment(2)
THANK YOU!!! After 2 full days of anguish, your solution did the trick for me. I had pushed my context.Rapturous
This post was a lifesaver. Thank you!Alleviate
C
0

When running gunicorn with multiple workers this problem showed up (not when running it with only a single worker). Upon closer inspection I realized that some of the links created in flask were set like this: redirect_uri=url_for("callback", _external=True) Flask uses the currently served scheme, which in my case (running behind gunicorn) was "http". However, the gunicorn communication with the auth0 server (this was my issue where the csrf token error popped up) was done using https (served by gunicorn). Setting the following solved the problem: redirect_uri=url_for("callback", _external=True, _scheme="https").

I hope this helps someone.

Castiron answered 26/12, 2023 at 16:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.