10

I get problem for disable csrf using flask-wtf for a restapi. The problem is similar like here: Flask-Restful POST fails due CSRF protection of Flask-WTF, but I use flask original instead of flask-restful.

I use the @csrf.exemptdecorator, and I did exactly like the documentation, but still can not disable the csrf. Here is my code, do you know what is the problem?

myApp.py

from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField
from flask_wtf.csrf import CSRFProtect

app = Flask(__name__)    
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
app.config['SECRET_KEY'] = "secret"

db = SQLAlchemy(app)

csrf = CSRFProtect(app) # initialize the csrf protect

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String())

class myForm(FlaskForm):
    username = StringField("user name")

@app.route("/check", methods=['POST'])    
@csrf.exempt # why this code doesn't work???!!! :(
def check():
    form = myForm(request.form)

    if form.validate():
        user = User(username=form.username.data)
        db.session.add(user)
        db.session.commit()
        return jsonify(message="user saved!"), 200
    else:
        return jsonify(message=form.errors), 404

if __name__ == '__main__':
    app.run(debug=True)

My Postman always return:

{
    "message": {
        "csrf_token": [
            "The CSRF token is missing."
        ]
    }
}
xirururu
  • 5,028
  • 9
  • 35
  • 64

3 Answers3

15

FlaskForm.validate() seems to be the one returning that error, i.e. try

form = myForm(request.form, csrf_enabled=False)

or

class myForm(FlaskForm):
    class Meta:
        csrf = False

     username = StringField("user name")

since csrf_enabled seems to be deprecated.

From the documentation

Any view using FlaskForm to process the request is already getting CSRF protection.

J.J. Hakala
  • 6,136
  • 6
  • 27
  • 61
  • Thanks very much for this answer! Do you mean the `csrf_enabled` in `myForm()` is deprecated? It currently works wunderful. Another question is if I use `class Meta: crsf = False`, then I will disable all the csrf protection, actually, I only want disable a part of them for the restapi... Is there any way to use the use the `@csrf.exempt`? – xirururu Feb 16 '19 at 16:05
  • 2
    There was a deprecation warning about `csrf_enabled` when I executed the flask application. Use of `class Meta..` in `myForm` should be limited to instances of class `myForm`. I think decorators provided by an instance of `CSRFProtect` are meant for views that do not call `FlaskForm.validate()`, so probably no. – J.J. Hakala Feb 16 '19 at 16:14
11

You can pass meta={'csrf': False} as parameter in your constructor

form = myForm(request.form, meta={'csrf': False})
0

You can also pass the route[s] you would like to exclude to csrf as a string:

csrf = CSRFProtect(app)
csrf.exempt('app.blueprints.views.my_view_fn')
nikk wong
  • 8,059
  • 6
  • 51
  • 68