Skip to content

Commit

Permalink
Add a timeout for PyJWKClient requests
Browse files Browse the repository at this point in the history
By default, the timeout for urlopen is socket._GLOBAL_DEFAULT_TIMEOUT
which is None (meaning that the request never times out):

https://docs.python.org/3/library/socket.html#socket.getdefaulttimeout

This change sets the timeout to 30 but also adds a timeout variable
users can set.
  • Loading branch information
daviddavis committed Apr 8, 2023
1 parent f4071a6 commit 1eefb97
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 2 deletions.
6 changes: 4 additions & 2 deletions jwt/jwks_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ def __init__(
cache_jwk_set: bool = True,
lifespan: int = 300,
headers: Optional[Dict[str, Any]] = None,
timeout: int = 30,
):
if headers is None:
headers = {}
self.uri = uri
self.jwk_set_cache: Optional[JWKSetCache] = None
self.headers = headers
self.timeout = timeout

if cache_jwk_set:
# Init jwt set cache with default or given lifespan.
Expand All @@ -46,9 +48,9 @@ def fetch_data(self) -> Any:
jwk_set: Any = None
try:
r = urllib.request.Request(url=self.uri, headers=self.headers)
with urllib.request.urlopen(r) as response:
with urllib.request.urlopen(r, timeout=self.timeout) as response:
jwk_set = json.load(response)
except URLError as e:
except (URLError, TimeoutError) as e:
raise PyJWKClientError(f'Fail to fetch data from the url, err: "{e}"')
else:
return jwk_set
Expand Down
17 changes: 17 additions & 0 deletions tests/test_jwks_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ def mocked_first_call_wrong_kid_second_call_correct_kid(
yield urlopen_mock


@contextlib.contextmanager
def mocked_timeout():
with mock.patch("urllib.request.urlopen") as urlopen_mock:
urlopen_mock.side_effect = TimeoutError("timed out")
yield urlopen_mock


@crypto_required
class TestPyJWKClient:
def test_fetch_data_forwards_headers_to_correct_url(self):
Expand Down Expand Up @@ -309,3 +316,13 @@ def test_get_jwt_set_invalid_lifespan(self):
with pytest.raises(PyJWKClientError):
jwks_client = PyJWKClient(url, lifespan=-1)
assert jwks_client is None

def test_get_jwt_set_timeout(self):
url = "https://dev-87evx9ru.auth0.com/.well-known/jwks.json"
jwks_client = PyJWKClient(url, timeout=5)

with pytest.raises(PyJWKClientError) as exc:
with mocked_timeout():
jwks_client.get_jwk_set()

assert 'Fail to fetch data from the url, err: "timed out"' in str(exc.value)

0 comments on commit 1eefb97

Please sign in to comment.