CSRF token not working in Flask app

Hi there,

I keep encountering this error every time I try to submit a form on my Flask home.html page.

Bad Request
The CSRF session token is missing.

I’ve created 3 Flask applications that I’ve deployed on render, and 50+ GitHub commits, looked up Google and ChatGPT to not avail.

Important points to note:

  • The local Flask application works perfectly fine, but not on render.com where I get the above Bad Request error.
  • Every time I refresh the local app, I can see a newly generated CSRF token
  • But when I refresh the Flask app on render.com, the CSRF token is always the same. Why?
  • EDITED: The form only works if there is no Flask-SQLAlchemy models that connects to PostgreSQL, but my application has Flask-SQLAlchemy connected to a free tier PostgreSQL database.
    I don’t see why this should be an issue though as submitting the form has no connection to the postgresql database.

Here are some snippets of my code from various files of my Flask app.

home.html page
<form method = "POST" action="{{url_for('main.home_post')}}">

    <input type="hidden" id="csrf_token" name="csrf_token" value="{{csrf_token()}}">
        <label for="username">username</label>
    <input type="text" required id="username" name="username" placeholder="Enter username...">
    
    <label for="email">email</label>
    <input type="email" required id="email" name="email" placeholder="Enter email...">

    <input type="submit" value="Submit">

</form>


<script>
var token = {{csrf_token()|tojson}};

console.log("TOKEN", token);
    
</script>

####### init.py file for my app

from flask import Flask
from flask_wtf.csrf import CSRFProtect

csrf = CSRFProtect()

def create_app():
    app = Flask(__name__)
    
    csrf.init_app(app)

    return app

Lastly, the backend for handling the home.html form.

@app_main.route("/", methods = ["GET", "POST"])
@app_main.route("/home", methods = ["GET", "POST"])
def home():

    return render_template("home.html", title = "home")



@app_main.route("/home_post", methods = ["POST"])
def home_post():

    csrf_token = session.get('_csrf_token')
    print("CSRF Token (Backend):", csrf_token)

    print("home post")

    if request.method == "POST":

        username = request.form.get("username")
        email = request.form.get("email")

        print("valid home post")
        print(username, email)
        flash("You've submitted successfully", "success")
        return redirect(url_for("main.home"))

Can someone please help me with this? I’ve gone over this for several days, and I’m quite exhausted trying to resolve this.
Is this error because I’m not yet a paid plan yet and am only using the free tier?

UPDATE: I’ve bought a $25/month plan, but still have the same problem with the CSRF token not changing every time I refresh, but I can now submit a form with the CSRF missing token error, which is confusing.

Kind regards,

Michael

Hi Michael,

This is unlikely to be anything on our side - we simply take your code and run it.

What it might be though, is differences in how your application runs between ‘development mode’ and ‘production mode’ when it’s deployed to us. What I’d suggest is running your application locally in ‘production mode’ to duplicate the issue and then use that to debug it locally.

Lastly, here are a few links I found that may offer further guidance:

Let us know if you have any further questions.

Regards,
Mike


Render Support Engineer, MT (UTC-7)

Hi Mike,

I’ve tested my application both locally and remotely on render.com. Locally, it works perfectly fine, but remotely the issue still persists

Basically, the CSRF token doesn’t change, no matter how many times I refresh the page.
Since the CSRF token has a time limit of 1 hour (or 3600 seconds), it expires, and consequently, anytime I try to login, sign up, or do any kind of POST with a form, it gives me the CSRF token has expired error.

The only difference between my local and remote application is that the local uses SQLite, and the remote uses the PostgreSQL from render.com (free tier version).

Until I can get this resolved, the website simply isn’t functional.

Has anyone else encountered this problem, and in particular, while using Flask?

Kind regards,

Michael S. Russell

PS: I wasn’t able to edit my previous reply.

I kept getting a 422 error on this website when trying to save my edited message.

I just wanted to add the link to my Flask app.

https://aws-dev-prod-v1.onrender.com/

There is a basic form on the home page.

My production PostgreSQL database (free tier) works on my Flask app locally, so it doesn’t appear to be caused by using PostgreSQL in the deployed application that’s causing this CSRF token expired error.

I managed to solve it.

So in my app/init.py file

I was using


app.app_context().push()

This was preventing the CSRF token from refreshing, and making it impossible to work with forms after the CSRF token had expired after 1 hour (or 3600 seconds).
This only worked locally, but when deployed, it would not work.

Changing it to this code below, the CSRF token is changed every time I refresh the page.

with app.app_context():

       # Your code runs here

Hope this helps anyone who was confused like I was!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.