Skip to content

Commit 54ab9e5

Browse files
committed
Add support for aud and iss claims, addresses jazzband#38
1 parent 89cdeaa commit 54ab9e5

File tree

5 files changed

+54
-3
lines changed

5 files changed

+54
-3
lines changed

README.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ Some of Simple JWT's behavior can be customized through settings variables in
151151
'ALGORITHM': 'HS256',
152152
'SIGNING_KEY': settings.SECRET_KEY,
153153
'VERIFYING_KEY': None,
154+
'AUDIENCE': None,
155+
'ISSUER': None,
154156
155157
'AUTH_HEADER_TYPES': ('Bearer',),
156158
'USER_ID_FIELD': 'id',
@@ -229,6 +231,16 @@ VERIFYING_KEY
229231
by the ``ALGORITHM`` setting, the ``VERIFYING_KEY`` setting must be set to a
230232
string which contains an RSA public key.
231233

234+
AUDIENCE
235+
The audience claim to be included in generated tokens and/or validated in
236+
decoded tokens. When set to ``None``, this field is excluded from tokens and
237+
is not validated.
238+
239+
ISSUER
240+
The issuer claim to be included in generated tokens and/or validated in
241+
decoded tokens. When set to ``None``, this field is excluded from tokens and
242+
is not validated.
243+
232244
AUTH_HEADER_TYPES
233245
The authorization header type(s) that will be accepted for views that require
234246
authentication. For example, a value of ``'Bearer'`` means that views

rest_framework_simplejwt/backends.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616

1717

1818
class TokenBackend:
19-
def __init__(self, algorithm, signing_key=None, verifying_key=None):
19+
def __init__(self, algorithm, signing_key=None, verifying_key=None, audience=None, issuer=None):
2020
if algorithm not in ALLOWED_ALGORITHMS:
2121
raise TokenBackendError(format_lazy(_("Unrecognized algorithm type '{}'"), algorithm))
2222

2323
self.algorithm = algorithm
2424
self.signing_key = signing_key
25+
self.audience = audience
26+
self.issuer = issuer
2527
if algorithm.startswith('HS'):
2628
self.verifying_key = signing_key
2729
else:
@@ -31,6 +33,11 @@ def encode(self, payload):
3133
"""
3234
Returns an encoded token for the given payload dictionary.
3335
"""
36+
if self.audience:
37+
payload['aud'] = self.audience
38+
if self.issuer:
39+
payload['iss'] = self.issuer
40+
3441
token = jwt.encode(payload, self.signing_key, algorithm=self.algorithm)
3542
return token.decode('utf-8')
3643

@@ -43,6 +50,7 @@ def decode(self, token, verify=True):
4350
signature check fails, or if its 'exp' claim indicates it has expired.
4451
"""
4552
try:
46-
return jwt.decode(token, self.verifying_key, algorithms=[self.algorithm], verify=verify)
53+
return jwt.decode(token, self.verifying_key, algorithms=[self.algorithm], verify=verify,
54+
audience=self.audience, issuer=self.issuer)
4755
except InvalidTokenError:
4856
raise TokenBackendError(_('Token is invalid or expired'))

rest_framework_simplejwt/settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
'ALGORITHM': 'HS256',
1919
'SIGNING_KEY': settings.SECRET_KEY,
2020
'VERIFYING_KEY': None,
21+
'AUDIENCE': None,
22+
'ISSUER': None,
2123

2224
'AUTH_HEADER_TYPES': ('Bearer',),
2325
'USER_ID_FIELD': 'id',

rest_framework_simplejwt/state.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55

66
User = get_user_model()
77
token_backend = TokenBackend(api_settings.ALGORITHM, api_settings.SIGNING_KEY,
8-
api_settings.VERIFYING_KEY)
8+
api_settings.VERIFYING_KEY, api_settings.AUDIENCE, api_settings.ISSUER)

tests/test_backends.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,16 @@
5151
-----END PUBLIC KEY-----
5252
'''
5353

54+
AUDIENCE = 'openid-client-id'
55+
56+
ISSUER = 'https://www.myoidcprovider.com'
57+
5458

5559
class TestTokenBackend(TestCase):
5660
def setUp(self):
5761
self.hmac_token_backend = TokenBackend('HS256', SECRET)
5862
self.rsa_token_backend = TokenBackend('RS256', PRIVATE_KEY, PUBLIC_KEY)
63+
self.aud_iss_token_backend = TokenBackend('RS256', PRIVATE_KEY, PUBLIC_KEY, AUDIENCE, ISSUER)
5964
self.payload = {'foo': 'bar'}
6065

6166
def test_init(self):
@@ -95,6 +100,20 @@ def test_encode_rsa(self):
95100
),
96101
)
97102

103+
def test_encode_aud_iss(self):
104+
# Should return a JSON web token for the given payload
105+
payload = {'exp': make_utc(datetime(year=2000, month=1, day=1))}
106+
107+
rsa_token = self.aud_iss_token_backend.encode(payload)
108+
109+
# Token could be one of two depending on header dict ordering
110+
self.assertIn(
111+
rsa_token,
112+
(
113+
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJleHAiOjk0NjY4NDgwMCwiYXVkIjoib3BlbmlkLWNsaWVudC1pZCIsImlzcyI6Imh0dHBzOi8vd3d3Lm15b2lkY3Byb3ZpZGVyLmNvbSJ9.kSz7KyUZgpKaeQHYSQlhsE-UFLG2zhBiJ2MFCIvhstA4lSIKj3U1fdP1OhEDg7X66EquRRIZrby6M7RncqCdsjRwKrEIaL74KgC4s5PDXa_HC6dtpi2GhXqaLz8YxfCPaNGZ_9q9rs4Z4O6WpwBLNmMQrTxNno9p0uT93Z2yKj5hGih8a9C_CSf_rKtsHW9AJShWGoKpR6qQFKVNP1GAwQOQ6IeEvZenq_LSEywnrfiWp4Y5UF7xi42wWx7_YPQtM9_Bp5sB-DbrKg_8t0zSc-OHeVDgH0TKqygGEea09W0QkmJcROkaEbxt2LxJg9OuSdXgudVytV8ewpgNtWNE4g'
114+
),
115+
)
116+
98117
def test_decode_hmac_with_no_expiry(self):
99118
no_exp_token = jwt.encode(self.payload, SECRET, algorithm='HS256')
100119

@@ -208,3 +227,13 @@ def test_decode_rsa_success(self):
208227
token = jwt.encode(self.payload, PRIVATE_KEY, algorithm='RS256').decode('utf-8')
209228

210229
self.assertEqual(self.rsa_token_backend.decode(token), self.payload)
230+
231+
def test_decode_aud_iss_success(self):
232+
self.payload['exp'] = aware_utcnow() + timedelta(days=1)
233+
self.payload['foo'] = 'baz'
234+
self.payload['aud'] = AUDIENCE
235+
self.payload['iss'] = ISSUER
236+
237+
token = jwt.encode(self.payload, PRIVATE_KEY, algorithm='RS256').decode('utf-8')
238+
239+
self.assertEqual(self.aud_iss_token_backend.decode(token), self.payload)

0 commit comments

Comments
 (0)