Skip to content

Commit

Permalink
Add JWT_SECRET_KEY and JWT_PRIVATE_KEY
Browse files Browse the repository at this point in the history
  • Loading branch information
vimalloc committed May 8, 2017
1 parent 6741215 commit ae82230
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 18 deletions.
10 changes: 7 additions & 3 deletions docs/options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,13 @@ General Options:
takes a ``datetime.timedelta``, and defaults to 30 days
``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'``.
``JWT_PUBLIC_KEY`` The public key needed for RSA and ECDSA based signing algorithms.
Has to be provided if any of ``RS*`` or ``ES*`` algorithms is used.
PEM format expected.
``JWT_SECRET_KEY`` The secret key needed for symmetric based signing algorithms,
such as ``HS*``. If this is not set, we use the
flask ``SECRET_KEY`` value instead.
``JWT_PUBLIC_KEY`` The public key needed for asymmetric based signing algorithms,
such as ``RS*`` or ``ES*``. PEM format expected.
``JWT_PRIVATE_KEY`` The private key needed for asymmetric based signing algorithms,
such as ``RS*`` or ``ES*``. PEM format expected.
================================= =========================================


Expand Down
31 changes: 21 additions & 10 deletions flask_jwt_extended/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def is_asymmetric(self):

@property
def encode_key(self):
return self.secret_key
return self.private_key if self.is_asymmetric else self.secret_key

@property
def decode_key(self):
Expand Down Expand Up @@ -191,20 +191,31 @@ def blacklist_access_tokens(self):

@property
def secret_key(self):
key = current_app.config.get('SECRET_KEY', None)
key = current_app.config['JWT_SECRET_KEY']
if not key:
raise RuntimeError('flask SECRET_KEY must be set')
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))
return key

@property
def public_key(self):
key = None
if self.algorithm in requires_cryptography:
key = current_app.config.get('JWT_PUBLIC_KEY', None)
if not key:
raise RuntimeError('JWT_PUBLIC_KEY must be set to use '
'asymmetric cryptography algorith '
'"{crypto_algorithm}"'.format(crypto_algorithm=self.algorithm))
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))
return key

@property
def private_key(self):
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))
return key

@property
Expand Down
9 changes: 8 additions & 1 deletion flask_jwt_extended/jwt_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,14 @@ def _set_default_configuration_options(app):
# https://github.com/jpadilla/pyjwt/blob/master/jwt/api_jwt.py
app.config.setdefault('JWT_ALGORITHM', 'HS256')

# must be set if using asymmetric cryptography algorithm (RS* or EC*)
# Secret key to sign JWTs with. Only used if a symmetric algorithm is
# used (such as the HS* algorithms). We will use the app secret key
# if this is not set.
app.config.setdefault('JWT_SECRET_KEY', None)

# Keys to sign JWTs with when use when using an asymmetric
# (public/private key) algorithm, such as RS* or EC*
app.config.setdefault('JWT_PRIVATE_KEY', None)
app.config.setdefault('JWT_PUBLIC_KEY', None)

# Options for blacklisting/revoking tokens
Expand Down
13 changes: 10 additions & 3 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,16 @@ def test_default_configs(self):
self.assertEqual(config.blacklist_access_tokens, False)

self.assertEqual(config.secret_key, self.app.secret_key)
self.assertEqual(config.public_key, None)
self.assertEqual(config.encode_key, self.app.secret_key)
self.assertEqual(config.decode_key, self.app.secret_key)
self.assertEqual(config.cookie_max_age, None)

with self.assertRaises(RuntimeError):
config.blacklist_store
with self.assertRaises(RuntimeError):
config.public_key
with self.assertRaises(RuntimeError):
config.private_key

def test_override_configs(self):
sample_store = simplekv.memory.DictStore()
Expand Down Expand Up @@ -176,8 +179,11 @@ def test_invalid_config_options(self):

self.app.config['JWT_ALGORITHM'] = 'RS256'
self.app.config['JWT_PUBLIC_KEY'] = None
self.app.config['JWT_PRIVATE_KEY'] = None
with self.assertRaises(RuntimeError):
config.decode_key
with self.assertRaises(RuntimeError):
config.encode_key

def test_depreciated_options(self):
self.app.config['JWT_CSRF_HEADER_NAME'] = 'Auth'
Expand Down Expand Up @@ -220,12 +226,13 @@ def test_special_config_options(self):
self.assertEqual(config.csrf_protect, False)

def test_asymmetric_encryption_key_handling(self):
self.app.secret_key = 'MOCK_RSA_PRIVATE_KEY'
self.app.config['JWT_PRIVATE_KEY'] = 'MOCK_RSA_PRIVATE_KEY'
self.app.config['JWT_PUBLIC_KEY'] = 'MOCK_RSA_PUBLIC_KEY'
self.app.config['JWT_ALGORITHM'] = 'RS256'

with self.app.test_request_context():
self.assertEqual(config.is_asymmetric, True)
self.assertEqual(config.secret_key, 'MOCK_RSA_PRIVATE_KEY')
self.assertEqual(config.encode_key, 'MOCK_RSA_PRIVATE_KEY')
self.assertEqual(config.decode_key, 'MOCK_RSA_PUBLIC_KEY')
self.assertEqual(config.private_key, 'MOCK_RSA_PRIVATE_KEY')
self.assertEqual(config.public_key, 'MOCK_RSA_PUBLIC_KEY')
2 changes: 1 addition & 1 deletion tests/test_protected_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -846,8 +846,8 @@ class TestEndpointsWithAssymmetricCrypto(unittest.TestCase):

def setUp(self):
self.app = Flask(__name__)
self.app.secret_key = RSA_PRIVATE
self.app.config['JWT_PUBLIC_KEY'] = RSA_PUBLIC
self.app.config['JWT_PRIVATE_KEY'] = RSA_PRIVATE
self.app.config['JWT_ALGORITHM'] = 'RS256'
self.app.config['JWT_ACCESS_TOKEN_EXPIRES'] = timedelta(seconds=1)
self.app.config['JWT_REFRESH_TOKEN_EXPIRES'] = timedelta(seconds=1)
Expand Down

0 comments on commit ae82230

Please sign in to comment.