Skip to content

Commit 9250430

Browse files
authored
Merge pull request #149 from matthewstory/master
[#148] add unset_access_cookies and unset_refresh_cookies functions
2 parents 2eb6998 + 31a4518 commit 9250430

File tree

3 files changed

+76
-19
lines changed

3 files changed

+76
-19
lines changed

flask_jwt_extended/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
from .utils import (
66
create_refresh_token, create_access_token, get_jwt_identity,
77
get_jwt_claims, set_access_cookies, set_refresh_cookies,
8-
unset_jwt_cookies, get_raw_jwt, get_current_user, current_user,
9-
get_jti, decode_token, get_csrf_token
8+
unset_jwt_cookies, unset_access_cookies, unset_refresh_cookies,
9+
get_raw_jwt, get_current_user, current_user, get_jti, decode_token,
10+
get_csrf_token
1011
)
1112

1213
__version__ = '3.8.1'

flask_jwt_extended/utils.py

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -281,18 +281,23 @@ def unset_jwt_cookies(response):
281281
282282
:param response: The Flask response object to delete the JWT cookies in.
283283
"""
284+
unset_access_cookies(response)
285+
unset_refresh_cookies(response)
286+
287+
288+
def unset_access_cookies(response):
289+
"""
290+
takes a flask response object, and configures it to unset (delete) the
291+
access token from the response cookies. if `jwt_csrf_in_cookies`
292+
(see :ref:`configuration options`) is `true`, this will also remove the
293+
access csrf double submit value from the response cookies as well.
294+
295+
:param response: the flask response object to delete the jwt cookies in.
296+
"""
284297
if not config.jwt_in_cookies:
285298
raise RuntimeWarning("unset_refresh_cookies() called without "
286299
"'JWT_TOKEN_LOCATION' configured to use cookies")
287300

288-
response.set_cookie(config.refresh_cookie_name,
289-
value='',
290-
expires=0,
291-
secure=config.cookie_secure,
292-
httponly=True,
293-
domain=config.cookie_domain,
294-
path=config.refresh_cookie_path,
295-
samesite=config.cookie_samesite)
296301
response.set_cookie(config.access_cookie_name,
297302
value='',
298303
expires=0,
@@ -303,19 +308,44 @@ def unset_jwt_cookies(response):
303308
samesite=config.cookie_samesite)
304309

305310
if config.csrf_protect and config.csrf_in_cookies:
306-
response.set_cookie(config.refresh_csrf_cookie_name,
311+
response.set_cookie(config.access_csrf_cookie_name,
307312
value='',
308313
expires=0,
309314
secure=config.cookie_secure,
310315
httponly=False,
311316
domain=config.cookie_domain,
312-
path=config.refresh_csrf_cookie_path,
317+
path=config.access_csrf_cookie_path,
313318
samesite=config.cookie_samesite)
314-
response.set_cookie(config.access_csrf_cookie_name,
319+
320+
321+
def unset_refresh_cookies(response):
322+
"""
323+
takes a flask response object, and configures it to unset (delete) the
324+
refresh token from the response cookies. if `jwt_csrf_in_cookies`
325+
(see :ref:`configuration options`) is `true`, this will also remove the
326+
refresh csrf double submit value from the response cookies as well.
327+
328+
:param response: the flask response object to delete the jwt cookies in.
329+
"""
330+
if not config.jwt_in_cookies:
331+
raise RuntimeWarning("unset_refresh_cookies() called without "
332+
"'JWT_TOKEN_LOCATION' configured to use cookies")
333+
334+
response.set_cookie(config.refresh_cookie_name,
335+
value='',
336+
expires=0,
337+
secure=config.cookie_secure,
338+
httponly=True,
339+
domain=config.cookie_domain,
340+
path=config.refresh_cookie_path,
341+
samesite=config.cookie_samesite)
342+
343+
if config.csrf_protect and config.csrf_in_cookies:
344+
response.set_cookie(config.refresh_csrf_cookie_name,
315345
value='',
316346
expires=0,
317347
secure=config.cookie_secure,
318348
httponly=False,
319349
domain=config.cookie_domain,
320-
path=config.access_csrf_cookie_path,
350+
path=config.refresh_csrf_cookie_path,
321351
samesite=config.cookie_samesite)

tests/test_cookies.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from flask_jwt_extended import (
55
jwt_required, JWTManager, jwt_refresh_token_required, create_access_token,
66
create_refresh_token, set_access_cookies, set_refresh_cookies,
7-
unset_jwt_cookies, jwt_optional
7+
unset_jwt_cookies, unset_access_cookies, unset_refresh_cookies, jwt_optional
88
)
99

1010
def _get_cookie_from_response(response, cookie_name):
@@ -46,6 +46,18 @@ def delete_tokens():
4646
unset_jwt_cookies(resp)
4747
return resp
4848

49+
@app.route('/delete_access_tokens', methods=['GET'])
50+
def delete_access_tokens():
51+
resp = jsonify(access_revoked=True)
52+
unset_access_cookies(resp)
53+
return resp
54+
55+
@app.route('/delete_refresh_tokens', methods=['GET'])
56+
def delete_refresh_tokens():
57+
resp = jsonify(refresh_revoked=True)
58+
unset_refresh_cookies(resp)
59+
return resp
60+
4961
@app.route('/protected', methods=['GET'])
5062
@jwt_required
5163
def protected():
@@ -75,12 +87,12 @@ def optional_post_protected():
7587

7688

7789
@pytest.mark.parametrize("options", [
78-
('/refresh_token', 'refresh_token_cookie', '/refresh_protected'),
79-
('/access_token', 'access_token_cookie', '/protected')
90+
('/refresh_token', 'refresh_token_cookie', '/refresh_protected', '/delete_refresh_tokens'),
91+
('/access_token', 'access_token_cookie', '/protected', '/delete_access_tokens')
8092
])
8193
def test_jwt_refresh_required_with_cookies(app, options):
8294
test_client = app.test_client()
83-
auth_url, cookie_name, protected_url = options
95+
auth_url, cookie_name, protected_url, delete_url = options
8496

8597
# Test without cookies
8698
response = test_client.get(protected_url)
@@ -94,7 +106,17 @@ def test_jwt_refresh_required_with_cookies(app, options):
94106
assert response.get_json() == {'foo': 'bar'}
95107

96108
# Test after issuing a 'logout' to delete the cookies
97-
test_client.get('/delete_tokens')
109+
test_client.get(delete_url)
110+
response = test_client.get(protected_url)
111+
assert response.status_code == 401
112+
assert response.get_json() == {'msg': 'Missing cookie "{}"'.format(cookie_name)}
113+
114+
# log back in once more to test that clearing all tokens works
115+
test_client.get(auth_url)
116+
response = test_client.get(protected_url)
117+
assert response.status_code == 200
118+
119+
test_client.get("/delete_tokens")
98120
response = test_client.get(protected_url)
99121
assert response.status_code == 401
100122
assert response.get_json() == {'msg': 'Missing cookie "{}"'.format(cookie_name)}
@@ -217,6 +239,10 @@ def test_setting_cookies_wihout_cookies_enabled(app):
217239
assert response.status_code == 500
218240
response = test_client.get('/delete_tokens')
219241
assert response.status_code == 500
242+
response = test_client.get('/delete_access_tokens')
243+
assert response.status_code == 500
244+
response = test_client.get('/delete_refresh_tokens')
245+
assert response.status_code == 500
220246

221247

222248
def test_default_cookie_options(app):

0 commit comments

Comments
 (0)