Flask-Restful POST fails due CSRF protection of Flask-WTF

12,067

Solution 1

You can use the @csrf.exempt decorator, which you need to add directly on the API object, with the decorators argument; this would apply the decorator to all API routes:

csrf_protect = CsrfProtect(app)
api = restful.Api(app, decorators=[csrf_protect.exempt])

You cannot use resource method decorators as they are not the final view functions that the exempt decorator requires to work.

It appears you cannot protect individual resources and exempt others; this is a limitation in the method used by Flask-Wtf's method of recording what views are exempted.

Solution 2

More simple solution (related commit):

csrf.exempt(api_blueprint)

And here is a complete demo:

from flask import Flask, Blueprint
from flask_wtf import CSRFProtect

app = Flask(__name__)
csrf = CSRFprotect(app)

api_blueprint = Blueprint('api', __name__)
csrf.exempt(api_blueprint)

app.register_blueprint(api_blueprint)
Share:
12,067
Houman
Author by

Houman

I'm a thinker and a dreamer. Love pets but don't have any. I'm a passionate tech entrepreneur.

Updated on June 04, 2022

Comments

  • Houman
    Houman almost 2 years

    I am using normal flask web + flask-restful. So I need CSRF protection for web but not for REST.

    The moment I enable CsrfProtect(app) of flask-wtf, all my post unit tests for flask-restful return a 400.

    Is there a way to disable CSRF protection for REST services since they are coming from mobile handsets without session handling anyway, hence CSRF wouldn't make much sense.

    This is how I test it:

    rv = self.client.post('api/v1.0/verify-email', environ_base={'REMOTE_ADDR': '127.0.0.1'}, headers={'Content-Type':'application/json'}, data=json.dumps(data))
    self.check_content_type(rv.headers)
    eq_(rv.status_code, 412)
    
  • Houman
    Houman over 10 years
    Thats an interesting solution. When try to run it it says method_decorators = [csrf.exempt] -> AttributeError: 'module' object has no attribute 'exempt'. I am importing: from flask_wtf import csrf
  • Martijn Pieters
    Martijn Pieters over 10 years
    Not the module, the extension object. I've updated the answer to make this a little more obvious as well as add another method to apply the decorator to all API routes.
  • Houman
    Houman over 10 years
    The second solution is brilliant. It works, thank you so much Martijn.
  • Martijn Pieters
    Martijn Pieters over 10 years
    Indeed, adjusted the answer; method decorators would not work.
  • James Bridgewater
    James Bridgewater about 5 years
    This was perfect. Thanks!