“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;
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
add a comment
|
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
add a comment
|
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
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
flask jwt csrf flask-admin flask-jwt-extended
asked Mar 28 at 21:28
juljul
16.4k54 gold badges167 silver badges280 bronze badges
16.4k54 gold badges167 silver badges280 bronze badges
add a comment
|
add a comment
|
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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