Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ The available options are:
``JWT_REFRESH_COOKIE_PATH`` What ``path`` should be set for the refresh cookie. Defaults to ``None``, which
will cause this access cookie to be sent in with every request. Should be modified
for only the paths that need the refresh cookie
``JWT_SESSION_COOKIE`` Whether to set session (deleted when the browser is closed) or persistent cookies.
Defaults to ``True`` (sets session cookies).
``JWT_COOKIE_CSRF_PROTECT`` Enable/disable CSRF protection. Only used when sending the JWT in via cookies
``JWT_CSRF_METHODS`` The request types that will use CSRF protection. Defaults to
```['POST', 'PUT', 'PATCH', 'DELETE']```
Expand Down
5 changes: 5 additions & 0 deletions flask_jwt_extended/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
REFRESH_COOKIE_NAME = 'refresh_token_cookie'
ACCESS_COOKIE_PATH = None
REFRESH_COOKIE_PATH = None
SESSION_COOKIE = True # True to use session cookies, False to use persistent

# Options for using double submit for verifying CSRF tokens
COOKIE_CSRF_PROTECT = True
Expand Down Expand Up @@ -76,6 +77,10 @@ def get_refresh_cookie_path():
return current_app.config.get('JWT_REFRESH_COOKIE_PATH', REFRESH_COOKIE_PATH)


def get_session_cookie():
return current_app.config.get('JWT_SESSION_COOKIE', SESSION_COOKIE)


def get_cookie_csrf_protect():
return current_app.config.get('JWT_COOKIE_CSRF_PROTECT', COOKIE_CSRF_PROTECT)

Expand Down
14 changes: 13 additions & 1 deletion flask_jwt_extended/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
get_algorithm, get_blacklist_enabled, get_blacklist_checks, get_jwt_header_type, \
get_access_cookie_name, get_cookie_secure, get_access_cookie_path, \
get_cookie_csrf_protect, get_access_csrf_cookie_name, \
get_refresh_cookie_name, get_refresh_cookie_path, \
get_refresh_cookie_name, get_refresh_cookie_path, get_session_cookie, \
get_refresh_csrf_cookie_name, get_token_location, \
get_csrf_header_name, get_jwt_header_name, get_csrf_request_methods
from flask_jwt_extended.exceptions import JWTEncodeError, JWTDecodeError, \
Expand Down Expand Up @@ -49,6 +49,14 @@ def get_raw_jwt():
return getattr(ctx_stack.top, 'jwt', {})


def _get_cookie_max_age():
"""
Checks config value for using session or persistent cookies and returns the
appropriate value for flask set_cookies.
"""
return None if get_session_cookie() else 2147483647 # 2^31


def _create_csrf_token():
return str(uuid.uuid4())

Expand Down Expand Up @@ -395,6 +403,7 @@ def set_access_cookies(response, encoded_access_token):
# Set the access JWT in the cookie
response.set_cookie(get_access_cookie_name(),
value=encoded_access_token,
max_age=_get_cookie_max_age(),
secure=get_cookie_secure(),
httponly=True,
path=get_access_cookie_path())
Expand All @@ -403,6 +412,7 @@ def set_access_cookies(response, encoded_access_token):
if get_cookie_csrf_protect():
response.set_cookie(get_access_csrf_cookie_name(),
value=_get_csrf_token(encoded_access_token),
max_age=_get_cookie_max_age(),
secure=get_cookie_secure(),
httponly=False,
path='/')
Expand All @@ -420,6 +430,7 @@ def set_refresh_cookies(response, encoded_refresh_token):
# Set the refresh JWT in the cookie
response.set_cookie(get_refresh_cookie_name(),
value=encoded_refresh_token,
max_age=_get_cookie_max_age(),
secure=get_cookie_secure(),
httponly=True,
path=get_refresh_cookie_path())
Expand All @@ -428,6 +439,7 @@ def set_refresh_cookies(response, encoded_refresh_token):
if get_cookie_csrf_protect():
response.set_cookie(get_refresh_csrf_cookie_name(),
value=_get_csrf_token(encoded_refresh_token),
max_age=_get_cookie_max_age(),
secure=get_cookie_secure(),
httponly=False,
path='/')
Expand Down
5 changes: 4 additions & 1 deletion tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
get_token_location, get_cookie_secure, get_access_cookie_name, \
get_refresh_cookie_name, get_access_cookie_path, get_refresh_cookie_path, \
get_cookie_csrf_protect, get_access_csrf_cookie_name, \
get_refresh_csrf_cookie_name, get_csrf_header_name
get_refresh_csrf_cookie_name, get_csrf_header_name, get_session_cookie
from flask_jwt_extended import JWTManager


Expand All @@ -34,6 +34,7 @@ def test_default_configs(self):
self.assertEqual(get_refresh_cookie_name(), 'refresh_token_cookie')
self.assertEqual(get_access_cookie_path(), None)
self.assertEqual(get_refresh_cookie_path(), None)
self.assertEqual(get_session_cookie(), True)
self.assertEqual(get_cookie_csrf_protect(), True)
self.assertEqual(get_access_csrf_cookie_name(), 'csrf_access_token')
self.assertEqual(get_refresh_csrf_cookie_name(), 'csrf_refresh_token')
Expand All @@ -56,6 +57,7 @@ def test_override_configs(self):
self.app.config['JWT_REFRESH_COOKIE_NAME'] = 'banana2'
self.app.config['JWT_ACCESS_COOKIE_PATH'] = '/banana/'
self.app.config['JWT_REFRESH_COOKIE_PATH'] = '/banana2/'
self.app.config['JWT_SESSION_COOKIE'] = False
self.app.config['JWT_COOKIE_CSRF_PROTECT'] = False
self.app.config['JWT_ACCESS_CSRF_COOKIE_NAME'] = 'banana1a'
self.app.config['JWT_REFRESH_CSRF_COOKIE_NAME'] = 'banana2a'
Expand All @@ -78,6 +80,7 @@ def test_override_configs(self):
self.assertEqual(get_refresh_cookie_name(), 'banana2')
self.assertEqual(get_access_cookie_path(), '/banana/')
self.assertEqual(get_refresh_cookie_path(), '/banana2/')
self.assertEqual(get_session_cookie(), False)
self.assertEqual(get_cookie_csrf_protect(), False)
self.assertEqual(get_access_csrf_cookie_name(), 'banana1a')
self.assertEqual(get_refresh_csrf_cookie_name(), 'banana2a')
Expand Down