From a32f88893e342e17c84a8d0babca95b0ec3afa51 Mon Sep 17 00:00:00 2001 From: "workos-tars[bot]" <269013284+workos-tars[bot]@users.noreply.github.com> Date: Fri, 16 Oct 2026 21:48:16 +0000 Subject: [PATCH] fix: classify Radar email and SMS challenges correctly --- src/workos/_errors.py | 2 ++ tests/test_generated_client.py | 56 ++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/src/workos/_errors.py b/src/workos/_errors.py index 6960f95a..76a4e82a 100644 --- a/src/workos/_errors.py +++ b/src/workos/_errors.py @@ -423,5 +423,7 @@ def __init__(self, message: str = "Request timed out") -> None: "email_password_auth_disabled": EmailPasswordAuthDisabledError, "passkey_progressive_enrollment": PasskeyProgressiveEnrollmentError, "radar_challenge": RadarChallengeError, + "radar_email_challenge": RadarChallengeError, + "radar_sms_challenge": RadarChallengeError, "radar_sign_up_challenge": RadarSignUpChallengeError, } diff --git a/tests/test_generated_client.py b/tests/test_generated_client.py index 09cd20d6..c42234bc 100644 --- a/tests/test_generated_client.py +++ b/tests/test_generated_client.py @@ -263,6 +263,33 @@ def test_raises_simple_auth_flow_errors(self, httpx_mock): assert exc_info.value.pending_authentication_token == "pat_tok" client.close() + @pytest.mark.parametrize( + "error_code", ["radar_email_challenge", "radar_sms_challenge"] + ) + @pytest.mark.parametrize("error_field", ["code", "error"]) + def test_raises_radar_challenge(self, workos, httpx_mock, error_code, error_field): + payload = { + error_field: error_code, + "message": "Radar challenge required", + "pending_authentication_token": "pat_radar", + "radar_challenge_id": "radar_challenge_123", + } + httpx_mock.add_response( + status_code=403, json=payload, headers={"X-Request-ID": "req_radar"} + ) + with pytest.raises(RadarChallengeError) as exc_info: + workos.user_management.authenticate_with_password( + email="user@example.com", password="password" + ) + error = exc_info.value + assert isinstance(error, AuthenticationFlowError) + assert isinstance(error, AuthorizationError) + assert error.pending_authentication_token == "pat_radar" + assert error.response_json == payload + assert getattr(error, error_field) == error_code + assert error.status_code == 403 + assert error.request_id == "req_radar" + def test_auth_flow_errors_are_catchable_as_authorization_error(self, httpx_mock): httpx_mock.add_response( status_code=403, @@ -731,6 +758,35 @@ async def test_raises_sso_required(self, httpx_mock): assert exc_info.value.connection_ids == ["conn_1"] await client.close() + @pytest.mark.parametrize( + "error_code", ["radar_email_challenge", "radar_sms_challenge"] + ) + @pytest.mark.parametrize("error_field", ["code", "error"]) + async def test_raises_radar_challenge( + self, async_workos, httpx_mock, error_code, error_field + ): + payload = { + error_field: error_code, + "message": "Radar challenge required", + "pending_authentication_token": "pat_radar", + "radar_challenge_id": "radar_challenge_123", + } + httpx_mock.add_response( + status_code=403, json=payload, headers={"X-Request-ID": "req_radar"} + ) + with pytest.raises(RadarChallengeError) as exc_info: + await async_workos.user_management.authenticate_with_password( + email="user@example.com", password="password" + ) + error = exc_info.value + assert isinstance(error, AuthenticationFlowError) + assert isinstance(error, AuthorizationError) + assert error.pending_authentication_token == "pat_radar" + assert error.response_json == payload + assert getattr(error, error_field) == error_code + assert error.status_code == 403 + assert error.request_id == "req_radar" + async def test_auth_flow_errors_backward_compat(self, httpx_mock): httpx_mock.add_response( status_code=403,