Skip to content

Commit 413d17d

Browse files
committed
Use False to disable expiration
This is more intuitive than timedelta(0)
1 parent bfb1bc0 commit 413d17d

File tree

7 files changed

+34
-21
lines changed

7 files changed

+34
-21
lines changed

docs/changing_default_behavior.rst

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,15 @@ You could accomplish this like such:
6969
token = create_access_token(username, expires_delta=expires)
7070
return jsonify({'token': token}), 201
7171
72-
You can even disable expiration by setting `expires_delta` to `datetime.timedelta(0)`:
72+
You can even disable expiration by setting `expires_delta` to `False`:
7373

7474
.. code-block:: python
7575
7676
@app.route('/create-api-token', methods=['POST'])
7777
@jwt_required
7878
def create_api_token():
7979
username = get_jwt_identity()
80-
expires = datetime.timedelta()
81-
token = create_access_token(username, expires_delta=expires)
80+
token = create_access_token(username, expires_delta=False)
8281
return jsonify({'token': token}), 201
8382
8483
Note that in this case, you should enable token revoking (see :ref:`Blacklist and Token Revoking`).

docs/options.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ General Options:
2020
in a list to check more then one location, such as: ``['headers', 'cookies']``.
2121
Defaults to ``'headers'``
2222
``JWT_ACCESS_TOKEN_EXPIRES`` How long an access token should live before it expires. This
23-
takes a ``datetime.timedelta``, and defaults to 15 minutes
23+
takes a ``datetime.timedelta``, and defaults to 15 minutes.
24+
Can be set to ``False`` to disable expiration.
2425
``JWT_REFRESH_TOKEN_EXPIRES`` How long a refresh token should live before it expires. This
2526
takes a ``datetime.timedelta``, and defaults to 30 days.
26-
Can be set to ``datetime.timedelta(0)`` to disable expiration.
27+
Can be set to ``False`` to disable expiration.
2728
``JWT_ALGORITHM`` Which algorithm to sign the JWT with. `See here <https://pyjwt.readthedocs.io/en/latest/algorithms.html>`_
2829
for the options. Defaults to ``'HS256'``.
2930
``JWT_SECRET_KEY`` The secret key needed for symmetric based signing algorithms,

flask_jwt_extended/config.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,15 +151,15 @@ def refresh_csrf_header_name(self):
151151
@property
152152
def access_expires(self):
153153
delta = current_app.config['JWT_ACCESS_TOKEN_EXPIRES']
154-
if not isinstance(delta, datetime.timedelta):
155-
raise RuntimeError('JWT_ACCESS_TOKEN_EXPIRES must be a datetime.timedelta')
154+
if not isinstance(delta, datetime.timedelta) and delta is not False:
155+
raise RuntimeError('JWT_ACCESS_TOKEN_EXPIRES must be a datetime.timedelta or False')
156156
return delta
157157

158158
@property
159159
def refresh_expires(self):
160160
delta = current_app.config['JWT_REFRESH_TOKEN_EXPIRES']
161-
if not isinstance(delta, datetime.timedelta):
162-
raise RuntimeError('JWT_REFRESH_TOKEN_EXPIRES must be a datetime.timedelta')
161+
if not isinstance(delta, datetime.timedelta) and delta is not False:
162+
raise RuntimeError('JWT_REFRESH_TOKEN_EXPIRES must be a datetime.timedelta or False')
163163
return delta
164164

165165
@property

flask_jwt_extended/tokens.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@ def _encode_jwt(additional_token_data, expires_delta, secret, algorithm):
1919
'nbf': now,
2020
'jti': uid,
2121
}
22-
# If expires_delta is timedelta(0), the JWT should never expire
22+
# If expires_delta is False, the JWT should never expire
2323
# and the 'exp' claim is not set.
2424
if expires_delta:
25-
# A timedelta object is considered to be true if and only if
26-
# it isn't equal to timedelta(0)
2725
token_data['exp'] = now + expires_delta
2826
token_data.update(additional_token_data)
2927
encoded_token = jwt.encode(token_data, secret, algorithm).decode('utf-8')
@@ -40,8 +38,8 @@ def encode_access_token(identity, secret, algorithm, expires_delta, fresh,
4038
:param secret: Secret key to encode the JWT with
4139
:param algorithm: Which algorithm to encode this JWT with
4240
:param expires_delta: How far in the future this token should expire
43-
(set to timedelta(0) to disable expiration)
44-
:type expires_delta: datetime.timedelta
41+
(set to False to disable expiration)
42+
:type expires_delta: datetime.timedelta or False
4543
:param fresh: If this should be a 'fresh' token or not
4644
:param user_claims: Custom claims to include in this token. This data must
4745
be json serializable
@@ -75,8 +73,8 @@ def encode_refresh_token(identity, secret, algorithm, expires_delta, csrf,
7573
:param secret: Secret key to encode the JWT with
7674
:param algorithm: Which algorithm to use for the toek
7775
:param expires_delta: How far in the future this token should expire
78-
(set to timedelta(0) to disable expiration)
79-
:type expires_delta: datetime.timedelta
76+
(set to False to disable expiration)
77+
:type expires_delta: datetime.timedelta or False
8078
:param csrf: Whether to include a csrf double submit claim in this token
8179
(boolean)
8280
:param identity_claim_key: Which key should be used to store the identity

flask_jwt_extended/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def create_access_token(identity, fresh=False, expires_delta=None):
100100
:func:`~flask_jwt_extended.fresh_jwt_required` endpoints.
101101
Defaults to `False`.
102102
:param expires_delta: A `datetime.timedelta` for how long this token should
103-
last before it expires. Set to timedelta(0) to disable
103+
last before it expires. Set to False to disable
104104
expiration. If this is None, it will use the
105105
'JWT_ACCESS_TOKEN_EXPIRES` config value
106106
(see :ref:`Configuration Options`)
@@ -121,7 +121,7 @@ def create_refresh_token(identity, expires_delta=None):
121121
to define a callback function that will be used to pull a
122122
json serializable identity out of the object.
123123
:param expires_delta: A `datetime.timedelta` for how long this token should
124-
last before it expires. Set to timedelta(0) to disable
124+
last before it expires. Set to False to disable
125125
expiration. If this is None, it will use the
126126
'JWT_REFRESH_TOKEN_EXPIRES` config value
127127
(see :ref:`Configuration Options`)

tests/test_config.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,14 @@ def test_override_configs(app):
129129
assert config.user_claims_key == 'bar'
130130

131131

132+
def test_tokens_never_expire(app):
133+
app.config['JWT_ACCESS_TOKEN_EXPIRES'] = False
134+
app.config['JWT_REFRESH_TOKEN_EXPIRES'] = False
135+
with app.test_request_context():
136+
assert config.access_expires is False
137+
assert config.refresh_expires is False
138+
139+
132140
# noinspection PyStatementEffect
133141
def test_symmetric_secret_key(app):
134142
with app.test_request_context():
@@ -208,6 +216,14 @@ def test_invalid_config_options(app):
208216
with pytest.raises(RuntimeError):
209217
config.refresh_expires
210218

219+
app.config['JWT_ACCESS_TOKEN_EXPIRES'] = True
220+
with pytest.raises(RuntimeError):
221+
config.access_expires
222+
223+
app.config['JWT_REFRESH_TOKEN_EXPIRES'] = True
224+
with pytest.raises(RuntimeError):
225+
config.refresh_expires
226+
211227
app.config['JWT_BLACKLIST_TOKEN_CHECKS'] = 'banana'
212228
with pytest.raises(RuntimeError):
213229
config.blacklist_checks

tests/test_decode_tokens.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,8 @@ def test_expired_token(app):
8686

8787
def test_never_expire_token(app):
8888
with app.test_request_context():
89-
delta = timedelta(0)
90-
access_token = create_access_token('username', expires_delta=delta)
91-
refresh_token = create_refresh_token('username', expires_delta=delta)
89+
access_token = create_access_token('username', expires_delta=False)
90+
refresh_token = create_refresh_token('username', expires_delta=False)
9291
for token in (access_token, refresh_token):
9392
decoded = decode_token(token)
9493
assert 'exp' not in decoded

0 commit comments

Comments
 (0)