Skip to content

Commit b3adde8

Browse files
author
Landon Gilbert-Bland
committed
Add and document iss and aud configuration options
1 parent 3329871 commit b3adde8

File tree

5 files changed

+82
-5
lines changed

5 files changed

+82
-5
lines changed

docs/options.rst

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,28 @@ General Options:
110110

111111
.. py:data:: JWT_DECODE_AUDIENCE
112112
113-
The expected audience (``aud``) or list of audiences you expect in a JWT when
114-
decoding it.
113+
The string or list of audiences (``aud``) expected in a JWT when decoding it.
114+
115+
Default: ``None``
116+
117+
118+
.. py:data:: JWT_ENCODE_AUDIENCE
119+
120+
The string or list of audiences (``aud``) for created JWTs.
121+
122+
Default: ``None``
123+
124+
125+
.. py:data:: JWT_DECODE_ISSUER
126+
127+
The issuer (``iss``) you expect in a JWT when decoding it.
128+
129+
Default: ``None``
130+
131+
132+
.. py:data:: JWT_ENCODE_ISSUER
133+
134+
The issuer (``iss``) for created JWTs.
115135

116136
Default: ``None``
117137

flask_jwt_extended/config.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,13 @@ def json_encoder(self):
272272
return current_app.json_encoder
273273

274274
@property
275-
def audience(self):
275+
def decode_audience(self):
276276
return current_app.config["JWT_DECODE_AUDIENCE"]
277277

278+
@property
279+
def encode_audience(self):
280+
return current_app.config["JWT_ENCODE_AUDIENCE"]
281+
278282
@property
279283
def encode_issuer(self):
280284
return current_app.config["JWT_ENCODE_ISSUER"]

flask_jwt_extended/jwt_manager.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from jwt import InvalidAudienceError
77
from jwt import InvalidIssuerError
88
from jwt import InvalidTokenError
9+
from jwt import MissingRequiredClaimError
910

1011
from flask_jwt_extended.config import config
1112
from flask_jwt_extended.default_callbacks import default_additional_claims_callback
@@ -113,6 +114,10 @@ def handle_expired_error(e):
113114
def handle_fresh_token_required(e):
114115
return self._needs_fresh_token_callback(e.jwt_header, e.jwt_data)
115116

117+
@app.errorhandler(MissingRequiredClaimError)
118+
def handle_missing_required_claim_error(e):
119+
return self._invalid_token_callback(str(e))
120+
116121
@app.errorhandler(InvalidAudienceError)
117122
def handle_invalid_audience_error(e):
118123
return self._invalid_token_callback(str(e))
@@ -176,6 +181,7 @@ def _set_default_configuration_options(app):
176181
app.config.setdefault("JWT_DECODE_AUDIENCE", None)
177182
app.config.setdefault("JWT_DECODE_ISSUER", None)
178183
app.config.setdefault("JWT_DECODE_LEEWAY", 0)
184+
app.config.setdefault("JWT_ENCODE_AUDIENCE", None)
179185
app.config.setdefault("JWT_ENCODE_ISSUER", None)
180186
app.config.setdefault("JWT_ERROR_MESSAGE_KEY", "msg")
181187
app.config.setdefault("JWT_HEADER_NAME", "Authorization")
@@ -481,6 +487,7 @@ def _encode_jwt_from_config(
481487

482488
return _encode_jwt(
483489
algorithm=config.algorithm,
490+
audience=config.encode_audience,
484491
claim_overrides=claim_overrides,
485492
csrf=config.csrf_protect,
486493
expires_delta=expires_delta,
@@ -507,14 +514,14 @@ def _decode_jwt_from_config(
507514

508515
kwargs = {
509516
"algorithms": config.decode_algorithms,
510-
"audience": config.audience,
517+
"audience": config.decode_audience,
511518
"csrf_value": csrf_value,
512519
"encoded_token": encoded_token,
513520
"identity_claim_key": config.identity_claim_key,
514521
"issuer": config.decode_issuer,
515522
"leeway": config.leeway,
516523
"secret": secret,
517-
"verify_aud": config.audience is not None,
524+
"verify_aud": config.decode_audience is not None,
518525
}
519526

520527
try:

flask_jwt_extended/tokens.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
def _encode_jwt(
1414
algorithm,
15+
audience,
1516
claim_overrides,
1617
csrf,
1718
expires_delta,
@@ -41,6 +42,9 @@ def _encode_jwt(
4142
if csrf:
4243
token_data["csrf"] = str(uuid.uuid4())
4344

45+
if audience:
46+
token_data["aud"] = audience
47+
4448
if issuer:
4549
token_data["iss"] = issuer
4650

tests/test_decode_tokens.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from jwt import InvalidAudienceError
1212
from jwt import InvalidIssuerError
1313
from jwt import InvalidSignatureError
14+
from jwt import MissingRequiredClaimError
1415

1516
from flask_jwt_extended import create_access_token
1617
from flask_jwt_extended import create_refresh_token
@@ -78,6 +79,47 @@ def test_bad_token_type(app, default_access_token):
7879
decode_token(bad_type_token)
7980

8081

82+
def test_encode_decode_audience(app):
83+
# Default, no audience
84+
with app.test_request_context():
85+
encoded_token = create_access_token("username")
86+
decoded_token = decode_token(encoded_token)
87+
with pytest.raises(KeyError):
88+
decoded_token["aud"]
89+
90+
# Encode and decode audience configured
91+
app.config["JWT_ENCODE_AUDIENCE"] = "foo"
92+
app.config["JWT_DECODE_AUDIENCE"] = "foo"
93+
with app.test_request_context():
94+
encoded_token = create_access_token("username")
95+
decoded_token = decode_token(encoded_token)
96+
assert decoded_token["aud"] == "foo"
97+
98+
# Encode and decode mismatch
99+
app.config["JWT_ENCODE_AUDIENCE"] = "foo"
100+
app.config["JWT_DECODE_AUDIENCE"] = "bar"
101+
with app.test_request_context():
102+
encoded_token = create_access_token("username")
103+
with pytest.raises(InvalidAudienceError):
104+
decode_token(encoded_token)
105+
106+
# No encode defined
107+
app.config["JWT_ENCODE_AUDIENCE"] = None
108+
app.config["JWT_DECODE_AUDIENCE"] = "foo"
109+
with app.test_request_context():
110+
encoded_token = create_access_token("username")
111+
with pytest.raises(MissingRequiredClaimError):
112+
decode_token(encoded_token)
113+
114+
# No decode defined
115+
app.config["JWT_ENCODE_AUDIENCE"] = "foo"
116+
app.config["JWT_DECODE_AUDIENCE"] = None
117+
with app.test_request_context():
118+
encoded_token = create_access_token("username")
119+
decoded_token = decode_token(encoded_token)
120+
assert decoded_token["aud"] == "foo"
121+
122+
81123
@pytest.mark.parametrize("delta_func", [timedelta, relativedelta])
82124
def test_expired_token(app, delta_func):
83125
with app.test_request_context():

0 commit comments

Comments
 (0)