“Missing CSRF token in headers” with JWT authentication in Flask-AdminWhat is a CSRF token ? What is its importance and how does it work?WARNING: Can't verify CSRF token authenticity railsWhy is it common to put CSRF prevention tokens in cookies?Sending JWT token in the headers with PostmanJWT (JSON Web Token) automatic prolongation of expirationJWT authentication for ASP.NET Web APIflask error CSRF token is missingUsing double submitted CSRF tokens (header + cookie) in HTML forms?Flask CSRF session token is missing

Do any Star Trek characters play rock band instruments?

Is there an integrated terminal option in file managers such as Nautilus in Ubuntu?

Can I say: “The train departs at 16 past every hour“?

Is it possible to save a (science) PhD in 10 months?

How can you castle legally in Chess960 when the castling rook is on the king's destination square?

Log user out after change of IP address?

What is self hosted version control system?

The output -1 becomes a slash in the loop

Does the House Resolution about the Impeachment Inquiry change anything?

How to deal with a 6 year old who was "caught" cheating?

How did composers "test" their music?

A Caesar cipher in Python3

Body swap, then building it back to health

How does an all-female medieval country maintain itself?

How to check if python package is latest version programmatically?

Is F[x] isomorphic to Z for any field F?

How likely are you to be injured by falling shot from a game shoot?

Is it worth delving deep outside my field to revise a paper?

Calculate the sum of a finite sequence

Do dead weight 'components' exist?

Double feature: Bibliophile edition

MOS 8502, just a 6510B?

What potential problems are there with dumping dex in bard build?

Does there exist a surjective group homomorphism from G to H such that G doesn't contain a subgroup isomorphic to H?



“Missing CSRF token in headers” with JWT authentication in Flask-Admin


What is a CSRF token ? What is its importance and how does it work?WARNING: Can't verify CSRF token authenticity railsWhy is it common to put CSRF prevention tokens in cookies?Sending JWT token in the headers with PostmanJWT (JSON Web Token) automatic prolongation of expirationJWT authentication for ASP.NET Web APIflask error CSRF token is missingUsing double submitted CSRF tokens (header + cookie) in HTML forms?Flask CSRF session token is missing






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty
margin-bottom:0;









1

















I am writing a Flask backend to serve a RESTful API with authentication through JWT.



I am using Flask-Admin for the admin and, in order to use a single authentication method, I would like to use JWT authentication with it too.



I added a simple login form to Flask-Admin that set the JWT tokens in the cookies.



The JWT tokens are found and properly decoded in the request in the create_form method of my sqla.ModelView, but when posting the form (by clicking on the save button of my create form, I get a 401 error: "Missing CSRF token in headers.



Anybody can help ?



Login route



@bp_api.route('/api/user/login', methods=('POST',))
def login():

data = request.json

web = request.args.get('web', 0, type=int)


user = User.query.filter(User.username==data['username']).first()

if not user:
return jsonify('msg': 'User doesn't exist'.format(data['username'])), 400

if not user.confirmed_on:
return jsonify('msg': f'user.email not confirmed'), 400

if check_password_hash(user.password, data['password']):
access_token = create_access_token(identity = data['username'], fresh=True)
refresh_token = create_refresh_token(identity = data['username'])
if web:
resp = jsonify('username': f'user.username')
set_access_cookies(resp, access_token)
set_refresh_cookies(resp, refresh_token)
else:
resp = jsonify('msg':f'Logged as user.username',
'access_token': access_token, 'refresh_token': refresh_token
)
return resp, 200

else:
return jsonify('msg': 'Invalid password.'), 401


Flask-Admin view



from flask_admin.base import BaseView
from flask_admin.contrib import sqla

from flask_jwt_extended import (
get_current_user,
get_jwt_identity,
jwt_required,
verify_jwt_in_request,
verify_jwt_refresh_token_in_request,
create_access_token,
set_access_cookies,
unset_jwt_cookies,
)
from flask_jwt_extended.exceptions import NoAuthorizationError
from jwt import ExpiredSignatureError



class PhaunosBaseView(BaseView):

def render(self, template, **kwargs):
try:
verify_jwt_in_request()
self._template_args['current_user'] = get_current_user()
current_app.logger.info("Access token ok for user ".format(get_current_user()))
resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))

except ExpiredSignatureError:
# if the access token has expired, create new non-fresh token
current_app.logger.info("Access token has expired.")
try:
verify_jwt_refresh_token_in_request()
self._template_args['current_user'] = get_current_user()
access_token = create_access_token(identity=get_jwt_identity(), fresh=False)
resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))
set_access_cookies(resp, access_token)
except ExpiredSignatureError:
# if the refresh token has expired, user must login again
current_app.logger.info("Refresh token has expired")
resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))
unset_jwt_cookies(resp)
except NoAuthorizationError:
current_app.logger.info("No authorization token.")
resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))
return resp


class PhaunosModelView(PhaunosBaseView, sqla.ModelView):
pass


class ProjectAdminView(PhaunosModelView):

def create_form(self, obj=None):
current_app.logger.info("In create_form")
form = super(ProjectAdminView, self).create_form(obj)
current_app.logger.info(request.headers)
verify_jwt_in_request()
return form

def on_model_change(self, form, model, is_created):
current_app.logger.info("In on_model_change")
current_app.logger.info(id(request))
current_app.logger.info(request.headers)
verify_jwt_in_request()
# then set get_current_user() to some model attribute



log



[2019-03-28 18:20:27,311] INFO in views: In create_form
[2019-03-28 18:20:27,312] INFO in views: 140045316455232
[2019-03-28 18:20:27,312] INFO in views: Host: 127.0.0.1:5000
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1:5000/admin/admin_project/
Connection: keep-alive
Cookie: session_id=0c89eb809ae01aa65aa58bbc45faf79b31af32db; access_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiMWU0ZTA3YzItMjJjOC00NTFhLWJkNjAtYjllNzZmNWYzMTYyIiwiZXhwIjoxNTUzNzk3Mzc2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsImZyZXNoIjp0cnVlLCJ0eXBlIjoiYWNjZXNzIiwiY3NyZiI6IjkwZTY5ZjM1LWQwNDctNDM0NC1hOWVlLTg2NDM4OWFiNzM4OCJ9.0p1CBGxpUzLgIR369I1yP-FTRel4-fhAIeL084YV_O0; csrf_access_token=90e69f35-d047-4344-a9ee-864389ab7388; refresh_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiODI0MGJkODItYjg0NC00MjI5LWFiN2MtZTRhN2IwYzgxYzYzIiwiZXhwIjoxNTUzNzk3NTU2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsInR5cGUiOiJyZWZyZXNoIiwiY3NyZiI6Ijg1M2FiYzk0LWU2YjctNGZkZi05YzRhLTczNDMxZWE4NGRlOCJ9.CcHzlWsT9kBURZ1FaeCjG8du7FGXLD-fm5-HF0sBdJ8; csrf_refresh_token=853abc94-e6b7-4fdf-9c4a-73431ea84de8
Upgrade-Insecure-Requests: 1


[2019-03-28 18:20:27,316] INFO in views: Access token ok for user dummy_user42
172.23.0.1 - - [28/Mar/2019 18:20:27] "GET /admin/admin_project/new/?url=%2Fadmin%2Fadmin_project%2F HTTP/1.1" 200 -
[2019-03-28 18:21:11,496] INFO in views: In create_form
[2019-03-28 18:21:11,496] INFO in views: 140045316455232
[2019-03-28 18:21:11,496] INFO in views: Host: 127.0.0.1:5000
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1:5000/admin/admin_project/new/?url=%2Fadmin%2Fadmin_project%2F
Content-Type: multipart/form-data; boundary=---------------------------209115246111667105161673380
Content-Length: 857
Connection: keep-alive
Cookie: session_id=0c89eb809ae01aa65aa58bbc45faf79b31af32db; access_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiMWU0ZTA3YzItMjJjOC00NTFhLWJkNjAtYjllNzZmNWYzMTYyIiwiZXhwIjoxNTUzNzk3Mzc2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsImZyZXNoIjp0cnVlLCJ0eXBlIjoiYWNjZXNzIiwiY3NyZiI6IjkwZTY5ZjM1LWQwNDctNDM0NC1hOWVlLTg2NDM4OWFiNzM4OCJ9.0p1CBGxpUzLgIR369I1yP-FTRel4-fhAIeL084YV_O0; csrf_access_token=90e69f35-d047-4344-a9ee-864389ab7388; refresh_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiODI0MGJkODItYjg0NC00MjI5LWFiN2MtZTRhN2IwYzgxYzYzIiwiZXhwIjoxNTUzNzk3NTU2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsInR5cGUiOiJyZWZyZXNoIiwiY3NyZiI6Ijg1M2FiYzk0LWU2YjctNGZkZi05YzRhLTczNDMxZWE4NGRlOCJ9.CcHzlWsT9kBURZ1FaeCjG8du7FGXLD-fm5-HF0sBdJ8; csrf_refresh_token=853abc94-e6b7-4fdf-9c4a-73431ea84de8
Upgrade-Insecure-Requests: 1


172.23.0.1 - - [28/Mar/2019 18:21:11] "POST /admin/admin_project/new/?url=%2Fadmin%2Fadmin_project%2F HTTP/1.1" 401 -









share|improve this question
































    1

















    I am writing a Flask backend to serve a RESTful API with authentication through JWT.



    I am using Flask-Admin for the admin and, in order to use a single authentication method, I would like to use JWT authentication with it too.



    I added a simple login form to Flask-Admin that set the JWT tokens in the cookies.



    The JWT tokens are found and properly decoded in the request in the create_form method of my sqla.ModelView, but when posting the form (by clicking on the save button of my create form, I get a 401 error: "Missing CSRF token in headers.



    Anybody can help ?



    Login route



    @bp_api.route('/api/user/login', methods=('POST',))
    def login():

    data = request.json

    web = request.args.get('web', 0, type=int)


    user = User.query.filter(User.username==data['username']).first()

    if not user:
    return jsonify('msg': 'User doesn't exist'.format(data['username'])), 400

    if not user.confirmed_on:
    return jsonify('msg': f'user.email not confirmed'), 400

    if check_password_hash(user.password, data['password']):
    access_token = create_access_token(identity = data['username'], fresh=True)
    refresh_token = create_refresh_token(identity = data['username'])
    if web:
    resp = jsonify('username': f'user.username')
    set_access_cookies(resp, access_token)
    set_refresh_cookies(resp, refresh_token)
    else:
    resp = jsonify('msg':f'Logged as user.username',
    'access_token': access_token, 'refresh_token': refresh_token
    )
    return resp, 200

    else:
    return jsonify('msg': 'Invalid password.'), 401


    Flask-Admin view



    from flask_admin.base import BaseView
    from flask_admin.contrib import sqla

    from flask_jwt_extended import (
    get_current_user,
    get_jwt_identity,
    jwt_required,
    verify_jwt_in_request,
    verify_jwt_refresh_token_in_request,
    create_access_token,
    set_access_cookies,
    unset_jwt_cookies,
    )
    from flask_jwt_extended.exceptions import NoAuthorizationError
    from jwt import ExpiredSignatureError



    class PhaunosBaseView(BaseView):

    def render(self, template, **kwargs):
    try:
    verify_jwt_in_request()
    self._template_args['current_user'] = get_current_user()
    current_app.logger.info("Access token ok for user ".format(get_current_user()))
    resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))

    except ExpiredSignatureError:
    # if the access token has expired, create new non-fresh token
    current_app.logger.info("Access token has expired.")
    try:
    verify_jwt_refresh_token_in_request()
    self._template_args['current_user'] = get_current_user()
    access_token = create_access_token(identity=get_jwt_identity(), fresh=False)
    resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))
    set_access_cookies(resp, access_token)
    except ExpiredSignatureError:
    # if the refresh token has expired, user must login again
    current_app.logger.info("Refresh token has expired")
    resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))
    unset_jwt_cookies(resp)
    except NoAuthorizationError:
    current_app.logger.info("No authorization token.")
    resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))
    return resp


    class PhaunosModelView(PhaunosBaseView, sqla.ModelView):
    pass


    class ProjectAdminView(PhaunosModelView):

    def create_form(self, obj=None):
    current_app.logger.info("In create_form")
    form = super(ProjectAdminView, self).create_form(obj)
    current_app.logger.info(request.headers)
    verify_jwt_in_request()
    return form

    def on_model_change(self, form, model, is_created):
    current_app.logger.info("In on_model_change")
    current_app.logger.info(id(request))
    current_app.logger.info(request.headers)
    verify_jwt_in_request()
    # then set get_current_user() to some model attribute



    log



    [2019-03-28 18:20:27,311] INFO in views: In create_form
    [2019-03-28 18:20:27,312] INFO in views: 140045316455232
    [2019-03-28 18:20:27,312] INFO in views: Host: 127.0.0.1:5000
    User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: en-US,en;q=0.5
    Accept-Encoding: gzip, deflate
    Referer: http://127.0.0.1:5000/admin/admin_project/
    Connection: keep-alive
    Cookie: session_id=0c89eb809ae01aa65aa58bbc45faf79b31af32db; access_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiMWU0ZTA3YzItMjJjOC00NTFhLWJkNjAtYjllNzZmNWYzMTYyIiwiZXhwIjoxNTUzNzk3Mzc2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsImZyZXNoIjp0cnVlLCJ0eXBlIjoiYWNjZXNzIiwiY3NyZiI6IjkwZTY5ZjM1LWQwNDctNDM0NC1hOWVlLTg2NDM4OWFiNzM4OCJ9.0p1CBGxpUzLgIR369I1yP-FTRel4-fhAIeL084YV_O0; csrf_access_token=90e69f35-d047-4344-a9ee-864389ab7388; refresh_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiODI0MGJkODItYjg0NC00MjI5LWFiN2MtZTRhN2IwYzgxYzYzIiwiZXhwIjoxNTUzNzk3NTU2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsInR5cGUiOiJyZWZyZXNoIiwiY3NyZiI6Ijg1M2FiYzk0LWU2YjctNGZkZi05YzRhLTczNDMxZWE4NGRlOCJ9.CcHzlWsT9kBURZ1FaeCjG8du7FGXLD-fm5-HF0sBdJ8; csrf_refresh_token=853abc94-e6b7-4fdf-9c4a-73431ea84de8
    Upgrade-Insecure-Requests: 1


    [2019-03-28 18:20:27,316] INFO in views: Access token ok for user dummy_user42
    172.23.0.1 - - [28/Mar/2019 18:20:27] "GET /admin/admin_project/new/?url=%2Fadmin%2Fadmin_project%2F HTTP/1.1" 200 -
    [2019-03-28 18:21:11,496] INFO in views: In create_form
    [2019-03-28 18:21:11,496] INFO in views: 140045316455232
    [2019-03-28 18:21:11,496] INFO in views: Host: 127.0.0.1:5000
    User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: en-US,en;q=0.5
    Accept-Encoding: gzip, deflate
    Referer: http://127.0.0.1:5000/admin/admin_project/new/?url=%2Fadmin%2Fadmin_project%2F
    Content-Type: multipart/form-data; boundary=---------------------------209115246111667105161673380
    Content-Length: 857
    Connection: keep-alive
    Cookie: session_id=0c89eb809ae01aa65aa58bbc45faf79b31af32db; access_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiMWU0ZTA3YzItMjJjOC00NTFhLWJkNjAtYjllNzZmNWYzMTYyIiwiZXhwIjoxNTUzNzk3Mzc2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsImZyZXNoIjp0cnVlLCJ0eXBlIjoiYWNjZXNzIiwiY3NyZiI6IjkwZTY5ZjM1LWQwNDctNDM0NC1hOWVlLTg2NDM4OWFiNzM4OCJ9.0p1CBGxpUzLgIR369I1yP-FTRel4-fhAIeL084YV_O0; csrf_access_token=90e69f35-d047-4344-a9ee-864389ab7388; refresh_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiODI0MGJkODItYjg0NC00MjI5LWFiN2MtZTRhN2IwYzgxYzYzIiwiZXhwIjoxNTUzNzk3NTU2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsInR5cGUiOiJyZWZyZXNoIiwiY3NyZiI6Ijg1M2FiYzk0LWU2YjctNGZkZi05YzRhLTczNDMxZWE4NGRlOCJ9.CcHzlWsT9kBURZ1FaeCjG8du7FGXLD-fm5-HF0sBdJ8; csrf_refresh_token=853abc94-e6b7-4fdf-9c4a-73431ea84de8
    Upgrade-Insecure-Requests: 1


    172.23.0.1 - - [28/Mar/2019 18:21:11] "POST /admin/admin_project/new/?url=%2Fadmin%2Fadmin_project%2F HTTP/1.1" 401 -









    share|improve this question




























      1












      1








      1








      I am writing a Flask backend to serve a RESTful API with authentication through JWT.



      I am using Flask-Admin for the admin and, in order to use a single authentication method, I would like to use JWT authentication with it too.



      I added a simple login form to Flask-Admin that set the JWT tokens in the cookies.



      The JWT tokens are found and properly decoded in the request in the create_form method of my sqla.ModelView, but when posting the form (by clicking on the save button of my create form, I get a 401 error: "Missing CSRF token in headers.



      Anybody can help ?



      Login route



      @bp_api.route('/api/user/login', methods=('POST',))
      def login():

      data = request.json

      web = request.args.get('web', 0, type=int)


      user = User.query.filter(User.username==data['username']).first()

      if not user:
      return jsonify('msg': 'User doesn't exist'.format(data['username'])), 400

      if not user.confirmed_on:
      return jsonify('msg': f'user.email not confirmed'), 400

      if check_password_hash(user.password, data['password']):
      access_token = create_access_token(identity = data['username'], fresh=True)
      refresh_token = create_refresh_token(identity = data['username'])
      if web:
      resp = jsonify('username': f'user.username')
      set_access_cookies(resp, access_token)
      set_refresh_cookies(resp, refresh_token)
      else:
      resp = jsonify('msg':f'Logged as user.username',
      'access_token': access_token, 'refresh_token': refresh_token
      )
      return resp, 200

      else:
      return jsonify('msg': 'Invalid password.'), 401


      Flask-Admin view



      from flask_admin.base import BaseView
      from flask_admin.contrib import sqla

      from flask_jwt_extended import (
      get_current_user,
      get_jwt_identity,
      jwt_required,
      verify_jwt_in_request,
      verify_jwt_refresh_token_in_request,
      create_access_token,
      set_access_cookies,
      unset_jwt_cookies,
      )
      from flask_jwt_extended.exceptions import NoAuthorizationError
      from jwt import ExpiredSignatureError



      class PhaunosBaseView(BaseView):

      def render(self, template, **kwargs):
      try:
      verify_jwt_in_request()
      self._template_args['current_user'] = get_current_user()
      current_app.logger.info("Access token ok for user ".format(get_current_user()))
      resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))

      except ExpiredSignatureError:
      # if the access token has expired, create new non-fresh token
      current_app.logger.info("Access token has expired.")
      try:
      verify_jwt_refresh_token_in_request()
      self._template_args['current_user'] = get_current_user()
      access_token = create_access_token(identity=get_jwt_identity(), fresh=False)
      resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))
      set_access_cookies(resp, access_token)
      except ExpiredSignatureError:
      # if the refresh token has expired, user must login again
      current_app.logger.info("Refresh token has expired")
      resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))
      unset_jwt_cookies(resp)
      except NoAuthorizationError:
      current_app.logger.info("No authorization token.")
      resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))
      return resp


      class PhaunosModelView(PhaunosBaseView, sqla.ModelView):
      pass


      class ProjectAdminView(PhaunosModelView):

      def create_form(self, obj=None):
      current_app.logger.info("In create_form")
      form = super(ProjectAdminView, self).create_form(obj)
      current_app.logger.info(request.headers)
      verify_jwt_in_request()
      return form

      def on_model_change(self, form, model, is_created):
      current_app.logger.info("In on_model_change")
      current_app.logger.info(id(request))
      current_app.logger.info(request.headers)
      verify_jwt_in_request()
      # then set get_current_user() to some model attribute



      log



      [2019-03-28 18:20:27,311] INFO in views: In create_form
      [2019-03-28 18:20:27,312] INFO in views: 140045316455232
      [2019-03-28 18:20:27,312] INFO in views: Host: 127.0.0.1:5000
      User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
      Accept-Language: en-US,en;q=0.5
      Accept-Encoding: gzip, deflate
      Referer: http://127.0.0.1:5000/admin/admin_project/
      Connection: keep-alive
      Cookie: session_id=0c89eb809ae01aa65aa58bbc45faf79b31af32db; access_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiMWU0ZTA3YzItMjJjOC00NTFhLWJkNjAtYjllNzZmNWYzMTYyIiwiZXhwIjoxNTUzNzk3Mzc2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsImZyZXNoIjp0cnVlLCJ0eXBlIjoiYWNjZXNzIiwiY3NyZiI6IjkwZTY5ZjM1LWQwNDctNDM0NC1hOWVlLTg2NDM4OWFiNzM4OCJ9.0p1CBGxpUzLgIR369I1yP-FTRel4-fhAIeL084YV_O0; csrf_access_token=90e69f35-d047-4344-a9ee-864389ab7388; refresh_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiODI0MGJkODItYjg0NC00MjI5LWFiN2MtZTRhN2IwYzgxYzYzIiwiZXhwIjoxNTUzNzk3NTU2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsInR5cGUiOiJyZWZyZXNoIiwiY3NyZiI6Ijg1M2FiYzk0LWU2YjctNGZkZi05YzRhLTczNDMxZWE4NGRlOCJ9.CcHzlWsT9kBURZ1FaeCjG8du7FGXLD-fm5-HF0sBdJ8; csrf_refresh_token=853abc94-e6b7-4fdf-9c4a-73431ea84de8
      Upgrade-Insecure-Requests: 1


      [2019-03-28 18:20:27,316] INFO in views: Access token ok for user dummy_user42
      172.23.0.1 - - [28/Mar/2019 18:20:27] "GET /admin/admin_project/new/?url=%2Fadmin%2Fadmin_project%2F HTTP/1.1" 200 -
      [2019-03-28 18:21:11,496] INFO in views: In create_form
      [2019-03-28 18:21:11,496] INFO in views: 140045316455232
      [2019-03-28 18:21:11,496] INFO in views: Host: 127.0.0.1:5000
      User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
      Accept-Language: en-US,en;q=0.5
      Accept-Encoding: gzip, deflate
      Referer: http://127.0.0.1:5000/admin/admin_project/new/?url=%2Fadmin%2Fadmin_project%2F
      Content-Type: multipart/form-data; boundary=---------------------------209115246111667105161673380
      Content-Length: 857
      Connection: keep-alive
      Cookie: session_id=0c89eb809ae01aa65aa58bbc45faf79b31af32db; access_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiMWU0ZTA3YzItMjJjOC00NTFhLWJkNjAtYjllNzZmNWYzMTYyIiwiZXhwIjoxNTUzNzk3Mzc2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsImZyZXNoIjp0cnVlLCJ0eXBlIjoiYWNjZXNzIiwiY3NyZiI6IjkwZTY5ZjM1LWQwNDctNDM0NC1hOWVlLTg2NDM4OWFiNzM4OCJ9.0p1CBGxpUzLgIR369I1yP-FTRel4-fhAIeL084YV_O0; csrf_access_token=90e69f35-d047-4344-a9ee-864389ab7388; refresh_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiODI0MGJkODItYjg0NC00MjI5LWFiN2MtZTRhN2IwYzgxYzYzIiwiZXhwIjoxNTUzNzk3NTU2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsInR5cGUiOiJyZWZyZXNoIiwiY3NyZiI6Ijg1M2FiYzk0LWU2YjctNGZkZi05YzRhLTczNDMxZWE4NGRlOCJ9.CcHzlWsT9kBURZ1FaeCjG8du7FGXLD-fm5-HF0sBdJ8; csrf_refresh_token=853abc94-e6b7-4fdf-9c4a-73431ea84de8
      Upgrade-Insecure-Requests: 1


      172.23.0.1 - - [28/Mar/2019 18:21:11] "POST /admin/admin_project/new/?url=%2Fadmin%2Fadmin_project%2F HTTP/1.1" 401 -









      share|improve this question















      I am writing a Flask backend to serve a RESTful API with authentication through JWT.



      I am using Flask-Admin for the admin and, in order to use a single authentication method, I would like to use JWT authentication with it too.



      I added a simple login form to Flask-Admin that set the JWT tokens in the cookies.



      The JWT tokens are found and properly decoded in the request in the create_form method of my sqla.ModelView, but when posting the form (by clicking on the save button of my create form, I get a 401 error: "Missing CSRF token in headers.



      Anybody can help ?



      Login route



      @bp_api.route('/api/user/login', methods=('POST',))
      def login():

      data = request.json

      web = request.args.get('web', 0, type=int)


      user = User.query.filter(User.username==data['username']).first()

      if not user:
      return jsonify('msg': 'User doesn't exist'.format(data['username'])), 400

      if not user.confirmed_on:
      return jsonify('msg': f'user.email not confirmed'), 400

      if check_password_hash(user.password, data['password']):
      access_token = create_access_token(identity = data['username'], fresh=True)
      refresh_token = create_refresh_token(identity = data['username'])
      if web:
      resp = jsonify('username': f'user.username')
      set_access_cookies(resp, access_token)
      set_refresh_cookies(resp, refresh_token)
      else:
      resp = jsonify('msg':f'Logged as user.username',
      'access_token': access_token, 'refresh_token': refresh_token
      )
      return resp, 200

      else:
      return jsonify('msg': 'Invalid password.'), 401


      Flask-Admin view



      from flask_admin.base import BaseView
      from flask_admin.contrib import sqla

      from flask_jwt_extended import (
      get_current_user,
      get_jwt_identity,
      jwt_required,
      verify_jwt_in_request,
      verify_jwt_refresh_token_in_request,
      create_access_token,
      set_access_cookies,
      unset_jwt_cookies,
      )
      from flask_jwt_extended.exceptions import NoAuthorizationError
      from jwt import ExpiredSignatureError



      class PhaunosBaseView(BaseView):

      def render(self, template, **kwargs):
      try:
      verify_jwt_in_request()
      self._template_args['current_user'] = get_current_user()
      current_app.logger.info("Access token ok for user ".format(get_current_user()))
      resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))

      except ExpiredSignatureError:
      # if the access token has expired, create new non-fresh token
      current_app.logger.info("Access token has expired.")
      try:
      verify_jwt_refresh_token_in_request()
      self._template_args['current_user'] = get_current_user()
      access_token = create_access_token(identity=get_jwt_identity(), fresh=False)
      resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))
      set_access_cookies(resp, access_token)
      except ExpiredSignatureError:
      # if the refresh token has expired, user must login again
      current_app.logger.info("Refresh token has expired")
      resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))
      unset_jwt_cookies(resp)
      except NoAuthorizationError:
      current_app.logger.info("No authorization token.")
      resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))
      return resp


      class PhaunosModelView(PhaunosBaseView, sqla.ModelView):
      pass


      class ProjectAdminView(PhaunosModelView):

      def create_form(self, obj=None):
      current_app.logger.info("In create_form")
      form = super(ProjectAdminView, self).create_form(obj)
      current_app.logger.info(request.headers)
      verify_jwt_in_request()
      return form

      def on_model_change(self, form, model, is_created):
      current_app.logger.info("In on_model_change")
      current_app.logger.info(id(request))
      current_app.logger.info(request.headers)
      verify_jwt_in_request()
      # then set get_current_user() to some model attribute



      log



      [2019-03-28 18:20:27,311] INFO in views: In create_form
      [2019-03-28 18:20:27,312] INFO in views: 140045316455232
      [2019-03-28 18:20:27,312] INFO in views: Host: 127.0.0.1:5000
      User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
      Accept-Language: en-US,en;q=0.5
      Accept-Encoding: gzip, deflate
      Referer: http://127.0.0.1:5000/admin/admin_project/
      Connection: keep-alive
      Cookie: session_id=0c89eb809ae01aa65aa58bbc45faf79b31af32db; access_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiMWU0ZTA3YzItMjJjOC00NTFhLWJkNjAtYjllNzZmNWYzMTYyIiwiZXhwIjoxNTUzNzk3Mzc2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsImZyZXNoIjp0cnVlLCJ0eXBlIjoiYWNjZXNzIiwiY3NyZiI6IjkwZTY5ZjM1LWQwNDctNDM0NC1hOWVlLTg2NDM4OWFiNzM4OCJ9.0p1CBGxpUzLgIR369I1yP-FTRel4-fhAIeL084YV_O0; csrf_access_token=90e69f35-d047-4344-a9ee-864389ab7388; refresh_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiODI0MGJkODItYjg0NC00MjI5LWFiN2MtZTRhN2IwYzgxYzYzIiwiZXhwIjoxNTUzNzk3NTU2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsInR5cGUiOiJyZWZyZXNoIiwiY3NyZiI6Ijg1M2FiYzk0LWU2YjctNGZkZi05YzRhLTczNDMxZWE4NGRlOCJ9.CcHzlWsT9kBURZ1FaeCjG8du7FGXLD-fm5-HF0sBdJ8; csrf_refresh_token=853abc94-e6b7-4fdf-9c4a-73431ea84de8
      Upgrade-Insecure-Requests: 1


      [2019-03-28 18:20:27,316] INFO in views: Access token ok for user dummy_user42
      172.23.0.1 - - [28/Mar/2019 18:20:27] "GET /admin/admin_project/new/?url=%2Fadmin%2Fadmin_project%2F HTTP/1.1" 200 -
      [2019-03-28 18:21:11,496] INFO in views: In create_form
      [2019-03-28 18:21:11,496] INFO in views: 140045316455232
      [2019-03-28 18:21:11,496] INFO in views: Host: 127.0.0.1:5000
      User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
      Accept-Language: en-US,en;q=0.5
      Accept-Encoding: gzip, deflate
      Referer: http://127.0.0.1:5000/admin/admin_project/new/?url=%2Fadmin%2Fadmin_project%2F
      Content-Type: multipart/form-data; boundary=---------------------------209115246111667105161673380
      Content-Length: 857
      Connection: keep-alive
      Cookie: session_id=0c89eb809ae01aa65aa58bbc45faf79b31af32db; access_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiMWU0ZTA3YzItMjJjOC00NTFhLWJkNjAtYjllNzZmNWYzMTYyIiwiZXhwIjoxNTUzNzk3Mzc2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsImZyZXNoIjp0cnVlLCJ0eXBlIjoiYWNjZXNzIiwiY3NyZiI6IjkwZTY5ZjM1LWQwNDctNDM0NC1hOWVlLTg2NDM4OWFiNzM4OCJ9.0p1CBGxpUzLgIR369I1yP-FTRel4-fhAIeL084YV_O0; csrf_access_token=90e69f35-d047-4344-a9ee-864389ab7388; refresh_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiODI0MGJkODItYjg0NC00MjI5LWFiN2MtZTRhN2IwYzgxYzYzIiwiZXhwIjoxNTUzNzk3NTU2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsInR5cGUiOiJyZWZyZXNoIiwiY3NyZiI6Ijg1M2FiYzk0LWU2YjctNGZkZi05YzRhLTczNDMxZWE4NGRlOCJ9.CcHzlWsT9kBURZ1FaeCjG8du7FGXLD-fm5-HF0sBdJ8; csrf_refresh_token=853abc94-e6b7-4fdf-9c4a-73431ea84de8
      Upgrade-Insecure-Requests: 1


      172.23.0.1 - - [28/Mar/2019 18:21:11] "POST /admin/admin_project/new/?url=%2Fadmin%2Fadmin_project%2F HTTP/1.1" 401 -






      flask jwt csrf flask-admin flask-jwt-extended






      share|improve this question














      share|improve this question











      share|improve this question




      share|improve this question










      asked Mar 28 at 21:28









      juljul

      16.4k54 gold badges167 silver badges280 bronze badges




      16.4k54 gold badges167 silver badges280 bronze badges

























          0






          active

          oldest

          votes













          Your Answer






          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "1"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );














          draft saved

          draft discarded
















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55407115%2fmissing-csrf-token-in-headers-with-jwt-authentication-in-flask-admin%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown


























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55407115%2fmissing-csrf-token-in-headers-with-jwt-authentication-in-flask-admin%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown









          Popular posts from this blog

          Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

          Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

          Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript