Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def _discover_jwks_uri(auth_domain: str) -> str:
jwks_uri, cache_keys=True, headers={"User-Agent": "keep-api"}
)
else:
jwks_uri = None
jwks_client = None


Expand All @@ -68,7 +69,13 @@ def __init__(self, scopes: list[str] = []) -> None:
self.auth_domain = os.environ.get("AUTH0_DOMAIN")
if not self.auth_domain:
raise Exception("Missing AUTH0_DOMAIN environment variable")
self.jwks_uri = _discover_jwks_uri(self.auth_domain)
# Discovered once, at import. This used to call _discover_jwks_uri
# again here, which put one HTTP request with a 10 second timeout on
# every construction and then threw the answer away: token verification
# below reads the module level jwks_client, not this attribute. Route
# dependencies build a verifier each, so an Auth0 deployment paid for
# about 190 of those before it served a request.
self.jwks_uri = jwks_uri
# Note: cache_keys is set to True to avoid fetching the jwks keys on every request
# but it currently caches only per-route. After moving this auth verifier to be a singleton, we can cache it globally
self.issuer = f"https://{self.auth_domain}/"
Expand Down
69 changes: 69 additions & 0 deletions tests/test_auth0_authverifier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""Auth0 verifier construction must not reach the network.

OIDC discovery happens once, when the module is imported. Building a verifier
reuses that answer, and route dependencies build a lot of verifiers.
"""

import importlib
import sys
from unittest.mock import MagicMock, patch

import pytest

MODULE = "ee.identitymanager.identity_managers.auth0.auth0_authverifier"
DOMAIN = "example.auth0.com"


@pytest.fixture
def auth0_module(monkeypatch):
"""Import the verifier module fresh, with discovery answered by a stub.

The module reads AUTH0_DOMAIN and runs discovery at import time, so a stale
copy in sys.modules would answer for whatever the previous test set.
"""
monkeypatch.setenv("AUTH0_DOMAIN", DOMAIN)
monkeypatch.setenv("AUTH0_AUDIENCE", "keep-api")
sys.modules.pop(MODULE, None)

response = MagicMock()
response.json.return_value = {
"jwks_uri": f"https://{DOMAIN}/.well-known/jwks.json"
}
response.raise_for_status = MagicMock()

requested = []

def fake_get(url, **kwargs):
requested.append(url)
return response

with patch("requests.get", side_effect=fake_get):
module = importlib.import_module(MODULE)
yield module, requested

sys.modules.pop(MODULE, None)


def test_import_discovers_the_jwks_uri_once(auth0_module):
module, requested = auth0_module

assert requested == [f"https://{DOMAIN}/.well-known/openid-configuration"]
assert module.jwks_uri == f"https://{DOMAIN}/.well-known/jwks.json"


def test_construction_does_not_repeat_discovery(auth0_module):
module, requested = auth0_module
requested.clear()

for _ in range(3):
module.Auth0AuthVerifier()

assert requested == []


def test_construction_carries_the_discovered_jwks_uri(auth0_module):
module, _ = auth0_module

verifier = module.Auth0AuthVerifier()

assert verifier.jwks_uri == f"https://{DOMAIN}/.well-known/jwks.json"
Loading