Skip to content

Commit

Permalink
Iss #35 Added a config option to control setting session or persisten…
Browse files Browse the repository at this point in the history
…t cookies.

The options getters seem to be merging app config and default config as
transparently as possible so I added a helper method in utils.py,
_get_cookie_max_age, to translate the true/false value into something
meaningful for flask's set_cookie max_age parameter.

Tests have been run on Python 2.7 only! This has also been installed on
a flask app and tested manually.
  • Loading branch information
Craig Wright committed Apr 5, 2017
1 parent 8f57733 commit 09ac2df
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 2 deletions.
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

0 comments on commit 09ac2df

Please sign in to comment.