Skip to content
Closed
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
8 changes: 6 additions & 2 deletions docs/options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@ General Options:
in a sequence or a set to check more then one location, such as:
``('headers', 'cookies')``. Defaults to ``['headers']``
``JWT_ACCESS_TOKEN_EXPIRES`` How long an access token should live before it expires. This
takes a ``datetime.timedelta`` or an ``int`` (seconds), and defaults to 15 minutes.
takes any value that can be safely added to a ``datetime.datetime`` object, including
``datetime.timedelta``, `dateutil.relativedelta <https://dateutil.readthedocs.io/en/stable/relativedelta.html>`_,
or an ``int`` (seconds), and defaults to 15 minutes.
Can be set to ``False`` to disable expiration.
``JWT_REFRESH_TOKEN_EXPIRES`` How long a refresh token should live before it expires. This
takes a ``datetime.timedelta`` or ``int`` (seconds), and defaults to 30 days.
takes any value that can be safely added to a ``datetime.datetime`` object, including
``datetime.timedelta``, `dateutil.relativedelta <https://dateutil.readthedocs.io/en/stable/relativedelta.html>`_,
or an ``int`` (seconds), and defaults to 30 days.
Can be set to ``False`` to disable expiration.
``JWT_ALGORITHM`` Which algorithm to sign the JWT with. `See here <https://pyjwt.readthedocs.io/en/latest/algorithms.html>`_
for the options. Defaults to ``'HS256'``.
Expand Down
186 changes: 107 additions & 79 deletions flask_jwt_extended/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,18 @@
try:
from jwt.algorithms import requires_cryptography
except ImportError: # pragma: no cover
requires_cryptography = {'RS256', 'RS384', 'RS512', 'ES256', 'ES384',
'ES521', 'ES512', 'PS256', 'PS384', 'PS512'}
requires_cryptography = {
"RS256",
"RS384",
"RS512",
"ES256",
"ES384",
"ES521",
"ES512",
"PS256",
"PS384",
"PS512",
}


class _Config(object):
Expand Down Expand Up @@ -47,124 +57,128 @@ def decode_key(self):

@property
def token_location(self):
locations = current_app.config['JWT_TOKEN_LOCATION']
locations = current_app.config["JWT_TOKEN_LOCATION"]
if isinstance(locations, str):
locations = (locations,)
elif not isinstance(locations, (Sequence, Set)):
raise RuntimeError('JWT_TOKEN_LOCATION must be a sequence or a set')
raise RuntimeError("JWT_TOKEN_LOCATION must be a sequence or a set")
elif not locations:
raise RuntimeError('JWT_TOKEN_LOCATION must contain at least one '
'of "headers", "cookies", "query_string", or "json"')
raise RuntimeError(
"JWT_TOKEN_LOCATION must contain at least one "
'of "headers", "cookies", "query_string", or "json"'
)
for location in locations:
if location not in ('headers', 'cookies', 'query_string', 'json'):
raise RuntimeError('JWT_TOKEN_LOCATION can only contain '
'"headers", "cookies", "query_string", or "json"')
if location not in ("headers", "cookies", "query_string", "json"):
raise RuntimeError(
"JWT_TOKEN_LOCATION can only contain "
'"headers", "cookies", "query_string", or "json"'
)
return locations

@property
def jwt_in_cookies(self):
return 'cookies' in self.token_location
return "cookies" in self.token_location

@property
def jwt_in_headers(self):
return 'headers' in self.token_location
return "headers" in self.token_location

@property
def jwt_in_query_string(self):
return 'query_string' in self.token_location
return "query_string" in self.token_location

@property
def jwt_in_json(self):
return 'json' in self.token_location
return "json" in self.token_location

@property
def header_name(self):
name = current_app.config['JWT_HEADER_NAME']
name = current_app.config["JWT_HEADER_NAME"]
if not name:
raise RuntimeError("JWT_ACCESS_HEADER_NAME cannot be empty")
return name

@property
def header_type(self):
return current_app.config['JWT_HEADER_TYPE']
return current_app.config["JWT_HEADER_TYPE"]

@property
def query_string_name(self):
return current_app.config['JWT_QUERY_STRING_NAME']
return current_app.config["JWT_QUERY_STRING_NAME"]

@property
def access_cookie_name(self):
return current_app.config['JWT_ACCESS_COOKIE_NAME']
return current_app.config["JWT_ACCESS_COOKIE_NAME"]

@property
def refresh_cookie_name(self):
return current_app.config['JWT_REFRESH_COOKIE_NAME']
return current_app.config["JWT_REFRESH_COOKIE_NAME"]

@property
def access_cookie_path(self):
return current_app.config['JWT_ACCESS_COOKIE_PATH']
return current_app.config["JWT_ACCESS_COOKIE_PATH"]

@property
def refresh_cookie_path(self):
return current_app.config['JWT_REFRESH_COOKIE_PATH']
return current_app.config["JWT_REFRESH_COOKIE_PATH"]

@property
def cookie_secure(self):
return current_app.config['JWT_COOKIE_SECURE']
return current_app.config["JWT_COOKIE_SECURE"]

@property
def cookie_domain(self):
return current_app.config['JWT_COOKIE_DOMAIN']
return current_app.config["JWT_COOKIE_DOMAIN"]

@property
def session_cookie(self):
return current_app.config['JWT_SESSION_COOKIE']
return current_app.config["JWT_SESSION_COOKIE"]

@property
def cookie_samesite(self):
return current_app.config['JWT_COOKIE_SAMESITE']
return current_app.config["JWT_COOKIE_SAMESITE"]

@property
def json_key(self):
return current_app.config['JWT_JSON_KEY']
return current_app.config["JWT_JSON_KEY"]

@property
def refresh_json_key(self):
return current_app.config['JWT_REFRESH_JSON_KEY']
return current_app.config["JWT_REFRESH_JSON_KEY"]

@property
def csrf_protect(self):
return self.jwt_in_cookies and current_app.config['JWT_COOKIE_CSRF_PROTECT']
return self.jwt_in_cookies and current_app.config["JWT_COOKIE_CSRF_PROTECT"]

@property
def csrf_request_methods(self):
return current_app.config['JWT_CSRF_METHODS']
return current_app.config["JWT_CSRF_METHODS"]

@property
def csrf_in_cookies(self):
return current_app.config['JWT_CSRF_IN_COOKIES']
return current_app.config["JWT_CSRF_IN_COOKIES"]

@property
def access_csrf_cookie_name(self):
return current_app.config['JWT_ACCESS_CSRF_COOKIE_NAME']
return current_app.config["JWT_ACCESS_CSRF_COOKIE_NAME"]

@property
def refresh_csrf_cookie_name(self):
return current_app.config['JWT_REFRESH_CSRF_COOKIE_NAME']
return current_app.config["JWT_REFRESH_CSRF_COOKIE_NAME"]

@property
def access_csrf_cookie_path(self):
return current_app.config['JWT_ACCESS_CSRF_COOKIE_PATH']
return current_app.config["JWT_ACCESS_CSRF_COOKIE_PATH"]

@property
def refresh_csrf_cookie_path(self):
return current_app.config['JWT_REFRESH_CSRF_COOKIE_PATH']
return current_app.config["JWT_REFRESH_CSRF_COOKIE_PATH"]

@staticmethod
def _get_depreciated_csrf_header_name():
# This used to be the same option for access and refresh header names.
# This gives users a warning if they are still using the old behavior
old_name = current_app.config.get('JWT_CSRF_HEADER_NAME', None)
old_name = current_app.config.get("JWT_CSRF_HEADER_NAME", None)
if old_name:
msg = (
"JWT_CSRF_HEADER_NAME is depreciated. Use JWT_ACCESS_CSRF_HEADER_NAME "
Expand All @@ -175,132 +189,146 @@ def _get_depreciated_csrf_header_name():

@property
def access_csrf_header_name(self):
return self._get_depreciated_csrf_header_name() or \
current_app.config['JWT_ACCESS_CSRF_HEADER_NAME']
return (
self._get_depreciated_csrf_header_name()
or current_app.config["JWT_ACCESS_CSRF_HEADER_NAME"]
)

@property
def refresh_csrf_header_name(self):
return self._get_depreciated_csrf_header_name() or \
current_app.config['JWT_REFRESH_CSRF_HEADER_NAME']
return (
self._get_depreciated_csrf_header_name()
or current_app.config["JWT_REFRESH_CSRF_HEADER_NAME"]
)

@property
def access_expires(self):
delta = current_app.config['JWT_ACCESS_TOKEN_EXPIRES']
if type(delta) is int:
delta = datetime.timedelta(seconds=delta)
if not isinstance(delta, datetime.timedelta) and delta is not False:
err = 'JWT_ACCESS_TOKEN_EXPIRES must be a ' \
'datetime.timedelta, int or False'
raise RuntimeError(err)
delta = current_app.config["JWT_ACCESS_TOKEN_EXPIRES"]
if delta != False:
try:
delta + datetime.datetime.now()
except TypeError as e:
err = (
"must be able to add JWT_ACCESS_TOKEN_EXPIRES to datetime.datetime"
)
raise RuntimeError(err) from e
return delta

@property
def refresh_expires(self):
delta = current_app.config['JWT_REFRESH_TOKEN_EXPIRES']
if type(delta) is int:
delta = datetime.timedelta(seconds=delta)
if not isinstance(delta, datetime.timedelta) and delta is not False:
err = 'JWT_REFRESH_TOKEN_EXPIRES must be a ' \
'datetime.timedelta, int or False'
raise RuntimeError(err)
delta = current_app.config["JWT_REFRESH_TOKEN_EXPIRES"]
if delta != False:
try:
delta + datetime.datetime.now()
except TypeError as e:
err = (
"must be able to add JWT_REFRESH_TOKEN_EXPIRES to datetime.datetime"
)
raise RuntimeError(err) from e
return delta

@property
def algorithm(self):
return current_app.config['JWT_ALGORITHM']
return current_app.config["JWT_ALGORITHM"]

@property
def blacklist_enabled(self):
return current_app.config['JWT_BLACKLIST_ENABLED']
return current_app.config["JWT_BLACKLIST_ENABLED"]

@property
def blacklist_checks(self):
check_type = current_app.config['JWT_BLACKLIST_TOKEN_CHECKS']
check_type = current_app.config["JWT_BLACKLIST_TOKEN_CHECKS"]
if isinstance(check_type, str):
check_type = (check_type,)
elif not isinstance(check_type, (Sequence, Set)):
raise RuntimeError('JWT_BLACKLIST_TOKEN_CHECKS must be a sequence or a set')
raise RuntimeError("JWT_BLACKLIST_TOKEN_CHECKS must be a sequence or a set")
for item in check_type:
if item not in ('access', 'refresh'):
if item not in ("access", "refresh"):
err = 'JWT_BLACKLIST_TOKEN_CHECKS must be "access" or "refresh"'
raise RuntimeError(err)
return check_type

@property
def blacklist_access_tokens(self):
return 'access' in self.blacklist_checks
return "access" in self.blacklist_checks

@property
def blacklist_refresh_tokens(self):
return 'refresh' in self.blacklist_checks
return "refresh" in self.blacklist_checks

@property
def _secret_key(self):
key = current_app.config['JWT_SECRET_KEY']
key = current_app.config["JWT_SECRET_KEY"]
if not key:
key = current_app.config.get('SECRET_KEY', None)
key = current_app.config.get("SECRET_KEY", None)
if not key:
raise RuntimeError('JWT_SECRET_KEY or flask SECRET_KEY '
'must be set when using symmetric '
'algorithm "{}"'.format(self.algorithm))
raise RuntimeError(
"JWT_SECRET_KEY or flask SECRET_KEY "
"must be set when using symmetric "
'algorithm "{}"'.format(self.algorithm)
)
return key

@property
def _public_key(self):
key = current_app.config['JWT_PUBLIC_KEY']
key = current_app.config["JWT_PUBLIC_KEY"]
if not key:
raise RuntimeError('JWT_PUBLIC_KEY must be set to use '
'asymmetric cryptography algorithm '
'"{}"'.format(self.algorithm))
raise RuntimeError(
"JWT_PUBLIC_KEY must be set to use "
"asymmetric cryptography algorithm "
'"{}"'.format(self.algorithm)
)
return key

@property
def _private_key(self):
key = current_app.config['JWT_PRIVATE_KEY']
key = current_app.config["JWT_PRIVATE_KEY"]
if not key:
raise RuntimeError('JWT_PRIVATE_KEY must be set to use '
'asymmetric cryptography algorithm '
'"{}"'.format(self.algorithm))
raise RuntimeError(
"JWT_PRIVATE_KEY must be set to use "
"asymmetric cryptography algorithm "
'"{}"'.format(self.algorithm)
)
return key

@property
def cookie_max_age(self):
# Returns the appropiate value for max_age for flask set_cookies. If
# session cookie is true, return None, otherwise return a number of
# seconds a long ways in the future
return None if self.session_cookie else 2147483647 # 2^31
return None if self.session_cookie else 2_147_483_647 # 2^31

@property
def identity_claim_key(self):
return current_app.config['JWT_IDENTITY_CLAIM']
return current_app.config["JWT_IDENTITY_CLAIM"]

@property
def user_claims_key(self):
return current_app.config['JWT_USER_CLAIMS']
return current_app.config["JWT_USER_CLAIMS"]

@property
def user_claims_in_refresh_token(self):
return current_app.config['JWT_CLAIMS_IN_REFRESH_TOKEN']
return current_app.config["JWT_CLAIMS_IN_REFRESH_TOKEN"]

@property
def exempt_methods(self):
return {"OPTIONS"}

@property
def error_msg_key(self):
return current_app.config['JWT_ERROR_MESSAGE_KEY']
return current_app.config["JWT_ERROR_MESSAGE_KEY"]

@property
def json_encoder(self):
return current_app.json_encoder

@property
def audience(self):
return current_app.config['JWT_DECODE_AUDIENCE']
return current_app.config["JWT_DECODE_AUDIENCE"]

@property
def leeway(self):
return current_app.config['JWT_DECODE_LEEWAY']
return current_app.config["JWT_DECODE_LEEWAY"]


config = _Config()