diff --git a/src/workos/user_management/_resource.py b/src/workos/user_management/_resource.py index e84d43a2..8c383d77 100644 --- a/src/workos/user_management/_resource.py +++ b/src/workos/user_management/_resource.py @@ -2098,6 +2098,23 @@ def delete_user_authorized_application( # @oagen-ignore-start + def get_jwks_url(self, client_id: Optional[str] = None) -> str: + """Get the JWKS URL used to verify access tokens. + + Use this when integrating with a JWT library that fetches and caches + the JWKS itself (e.g. ``PyJWKClient``). For the JWKS document, call + :meth:`get_jwks` instead. + + Args: + client_id: The WorkOS client ID. Defaults to the client's + configured client_id. + + Returns: + The JWKS URL. + """ + resolved_client_id = client_id or self._client._require_client_id() + return f"{self._client.base_url}sso/jwks/{resolved_client_id}" + def load_sealed_session( self, *, @@ -4266,6 +4283,23 @@ async def delete_user_authorized_application( # @oagen-ignore-start + def get_jwks_url(self, client_id: Optional[str] = None) -> str: + """Get the JWKS URL used to verify access tokens. + + Use this when integrating with a JWT library that fetches and caches + the JWKS itself (e.g. ``PyJWKClient``). For the JWKS document, call + :meth:`get_jwks` instead. + + Args: + client_id: The WorkOS client ID. Defaults to the client's + configured client_id. + + Returns: + The JWKS URL. + """ + resolved_client_id = client_id or self._client._require_client_id() + return f"{self._client.base_url}sso/jwks/{resolved_client_id}" + def load_sealed_session( self, *, diff --git a/tests/test_inline_helpers.py b/tests/test_inline_helpers.py index 53c44603..c2aceead 100644 --- a/tests/test_inline_helpers.py +++ b/tests/test_inline_helpers.py @@ -271,3 +271,35 @@ async def test_sends_code_verifier(self, async_workos, httpx_mock): request = httpx_mock.get_request() body = json.loads(request.content) assert body["code_verifier"] == "test_verifier_abc" + + +class TestGetJwksUrl: + def test_uses_configured_client_id(self, workos): + url = workos.user_management.get_jwks_url() + assert url == "https://api.workos.com/sso/jwks/client_test" + + def test_explicit_client_id_overrides_default(self, workos): + url = workos.user_management.get_jwks_url("client_other") + assert url == "https://api.workos.com/sso/jwks/client_other" + + def test_raises_when_no_client_id_configured(self): + from workos import WorkOSClient + from workos._errors import ConfigurationError + + client = WorkOSClient(api_key="sk_test_abc") + try: + with pytest.raises(ConfigurationError): + client.user_management.get_jwks_url() + finally: + client.close() + + +@pytest.mark.asyncio +class TestAsyncGetJwksUrl: + async def test_uses_configured_client_id(self, async_workos): + url = async_workos.user_management.get_jwks_url() + assert url == "https://api.workos.com/sso/jwks/client_test" + + async def test_explicit_client_id_overrides_default(self, async_workos): + url = async_workos.user_management.get_jwks_url("client_other") + assert url == "https://api.workos.com/sso/jwks/client_other"