1

I'm using flask-jwt-extended to protect a rest api using JWT cookies.

I have found that when

app.config['JWT_COOKIE_CSRF_PROTECT'] = True

POST requests to protected endpoints don't work (while GET's do).

Here is my setup.

#app.py
app = flask.Flask(__name__)

# Configure application to store JWTs in cookies
app.config['JWT_TOKEN_LOCATION'] = ['cookies']

# Only allow JWT cookies to be sent over https. In production, this
# should likely be True
app.config['JWT_COOKIE_SECURE'] = False

app.config['JWT_ACCESS_COOKIE_PATH'] = '/api/'
app.config['JWT_REFRESH_COOKIE_PATH'] = '/api/refresh'

app.config['JWT_COOKIE_CSRF_PROTECT'] = True
app.config['JWT_SESSION_COOKIE'] = False


app.config["DEBUG"] = True
app.config["JWT_SECRET_KEY"] = "123456" 

jwt = JWTManager(app)


@app.route("/api/test_protected", methods=["GET", "POST"])
@jwt_required
def test_protected():
    print("test protected ok", get_jwt_identity())
    return jsonify(success=True)

a get request works

Request URL: http://test.localhsl.com:8080/api/test_protected
Request Method: GET
Status Code: 200 OK
Remote Address: 127.0.0.1:8080
Referrer Policy: no-referrer-when-downgrade
connection: keep-alive
content-length: 22
content-type: application/json
date: Tue, 04 Aug 2020 15:48:30 GMT
server: Werkzeug/1.0.1 Python/3.7.7
X-Powered-By: Express
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Cookie: access_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1OTY1NTYwNjEsIm5iZiI6MTU5NjU1NjA2MSwianRpIjoiZmJiZTM4YmYtZTMzYy00OGViLWJiZGItNmVjOThiZGMwNDVlIiwiZXhwIjoxNTk2NTU2OTYxLCJpZGVudGl0eSI6ImJyb21AcHJvdG9ubWFpbC5jb20iLCJmcmVzaCI6ZmFsc2UsInR5cGUiOiJhY2Nlc3MiLCJjc3JmIjoiMDY1YTdkNzEtYzlhZS00ZTY5LWJlMDYtYTRiYzZiNDlhODUyIn0.mfgjgXjHKibjO-HPtbdcWkXsFW5XavlxarJ0Bx64GWk; csrf_access_token=065a7d71-c9ae-4e69-be06-a4bc6b49a852; csrf_refresh_token=4669a26e-b39e-46ce-a7a3-4ac9a8d295cb
Host: test.localhsl.com:8080
Referer: http://test.localhsl.com:8080/projects
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36

but a post request fails

Request URL: http://test.localhsl.com:8080/api/test_protected
Request Method: POST
Status Code: 401 UNAUTHORIZED
Remote Address: 127.0.0.1:8080
Referrer Policy: no-referrer-when-downgrade
connection: keep-alive
content-length: 34
content-type: application/json
date: Tue, 04 Aug 2020 15:49:48 GMT
server: Werkzeug/1.0.1 Python/3.7.7
X-Powered-By: Express
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Content-Length: 0
Cookie: access_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1OTY1NTYxODEsIm5iZiI6MTU5NjU1NjE4MSwianRpIjoiMmUzMTVhMzItY2JmOS00MzJmLWI2MGUtYTYxMjU5Yzc2YTBkIiwiZXhwIjoxNTk2NTU3MDgxLCJpZGVudGl0eSI6ImJyb21AcHJvdG9ubWFpbC5jb20iLCJmcmVzaCI6ZmFsc2UsInR5cGUiOiJhY2Nlc3MiLCJjc3JmIjoiNTMwZmQ4OGItYTYxMS00NDI2LTk3NzQtM2Q0MWNhZWRhZmQzIn0.8EqCsPSEIVsE876dBz26cHhXz-v2d2vfwyPMNo2lsng; csrf_access_token=530fd88b-a611-4426-9774-3d41caedafd3; csrf_refresh_token=9b1e5ab7-bc62-4a5d-976c-1a14a82b7cb3
Host: test.localhsl.com:8080
Origin: http://test.localhsl.com:8080
Referer: http://test.localhsl.com:8080/projects
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36

However, if I set

app.config['JWT_COOKIE_CSRF_PROTECT'] = False

both POST and GET to the protected endpoint work.

Any idea why this might be?

anonthot
  • 11
  • 1

1 Answers1

0

You need to manually send the double submit token in with your post requests in order to protect your app from csrf attacks while using cookies. See the documentation for details: https://flask-jwt-extended.readthedocs.io/en/stable/tokens_in_cookies/

vimalloc
  • 3,869
  • 4
  • 32
  • 45