Skip to content
Merged
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
34 changes: 34 additions & 0 deletions src/workos/user_management/_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
*,
Expand Down Expand Up @@ -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,
*,
Expand Down
32 changes: 32 additions & 0 deletions tests/test_inline_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Comment on lines +298 to +305
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Missing ConfigurationError test for async path

The sync TestGetJwksUrl has test_raises_when_no_client_id_configured but TestAsyncGetJwksUrl does not. Since both implementations are identical, parity is worth adding to confirm the error path works through async_workos as well.

Loading