diff --git a/.changelog-pending/2026-07-06T15-36-53-a2c464df57c9c25ad289cf11417e5df4ada5c726.md b/.changelog-pending/2026-07-06T15-36-53-a2c464df57c9c25ad289cf11417e5df4ada5c726.md new file mode 100644 index 00000000..de177d90 --- /dev/null +++ b/.changelog-pending/2026-07-06T15-36-53-a2c464df57c9c25ad289cf11417e5df4ada5c726.md @@ -0,0 +1,13 @@ +* [#687](https://github.com/workos/workos-python/pull/687) fix(generated): regenerate from spec + + **Features** + * **[user_management](https://workos.com/docs/reference/authkit/user)**: + * Added model `UserRoleAssignmentSource` + * Added `source` to `UserRoleAssignment` + * Added enum `UserRoleAssignmentSourceType` + * Added parameter `UserManagementAuthentication.authorize.max_age` + * Added endpoint `GET /user_management/cors_origins` + * Added endpoint `GET /user_management/redirect_uris` + + **Fixes** + * Restore mistakenly removed CreateMagicAuth logic from previous release diff --git a/.last-synced-sha b/.last-synced-sha index 639e2e87..509956d7 100644 --- a/.last-synced-sha +++ b/.last-synced-sha @@ -1 +1 @@ -4b4e0618779460dbebc1cf5e0f02197c21796d1f +23faa38318d596e581656934ed72c4a18476d742 diff --git a/.oagen-manifest.json b/.oagen-manifest.json index 453021d7..1e476b16 100644 --- a/.oagen-manifest.json +++ b/.oagen-manifest.json @@ -1,7 +1,6 @@ { "version": 2, "language": "python", - "generatedAt": "2026-07-02T17:29:55.736Z", "files": [ "src/workos/_client.py", "src/workos/admin_portal/__init__.py", diff --git a/src/workos/user_management/_resource.py b/src/workos/user_management/_resource.py index ed2ea8d6..6cd1386f 100644 --- a/src/workos/user_management/_resource.py +++ b/src/workos/user_management/_resource.py @@ -176,6 +176,8 @@ def authenticate_with_password( ip_address: Optional[str] = None, device_id: Optional[str] = None, user_agent: Optional[str] = None, + signals_id: Optional[str] = None, + radar_auth_attempt_id: Optional[str] = None, request_options: Optional[RequestOptions] = None, ) -> AuthenticateResponse: """Authenticate with password.""" @@ -196,6 +198,10 @@ def authenticate_with_password( body["device_id"] = device_id if user_agent is not None: body["user_agent"] = user_agent + if signals_id is not None: + body["signals_id"] = signals_id + if radar_auth_attempt_id is not None: + body["radar_auth_attempt_id"] = radar_auth_attempt_id return self._client.request( method="POST", @@ -214,6 +220,7 @@ def authenticate_with_code( ip_address: Optional[str] = None, device_id: Optional[str] = None, user_agent: Optional[str] = None, + signals_id: Optional[str] = None, request_options: Optional[RequestOptions] = None, ) -> AuthenticateResponse: """Authenticate with code.""" @@ -235,6 +242,8 @@ def authenticate_with_code( body["device_id"] = device_id if user_agent is not None: body["user_agent"] = user_agent + if signals_id is not None: + body["signals_id"] = signals_id return self._client.request( method="POST", @@ -289,6 +298,7 @@ def authenticate_with_magic_auth( ip_address: Optional[str] = None, device_id: Optional[str] = None, user_agent: Optional[str] = None, + radar_auth_attempt_id: Optional[str] = None, request_options: Optional[RequestOptions] = None, ) -> AuthenticateResponse: """Authenticate with magic auth.""" @@ -309,6 +319,8 @@ def authenticate_with_magic_auth( body["device_id"] = device_id if user_agent is not None: body["user_agent"] = user_agent + if radar_auth_attempt_id is not None: + body["radar_auth_attempt_id"] = radar_auth_attempt_id return self._client.request( method="POST", @@ -456,6 +468,82 @@ def authenticate_with_device_code( request_options=request_options, ) + def authenticate_with_radar_email_challenge( + self, + *, + code: str, + radar_challenge_id: str, + pending_authentication_token: str, + ip_address: Optional[str] = None, + device_id: Optional[str] = None, + user_agent: Optional[str] = None, + request_options: Optional[RequestOptions] = None, + ) -> AuthenticateResponse: + """Authenticate with radar email challenge.""" + body: Dict[str, Any] = { + "grant_type": "urn:workos:oauth:grant-type:radar-email-challenge:code", + "code": code, + "radar_challenge_id": radar_challenge_id, + "pending_authentication_token": pending_authentication_token, + } + if self._client.client_id is not None: + body["client_id"] = self._client.client_id + if self._client._api_key is not None: + body["client_secret"] = self._client._api_key + if ip_address is not None: + body["ip_address"] = ip_address + if device_id is not None: + body["device_id"] = device_id + if user_agent is not None: + body["user_agent"] = user_agent + + return self._client.request( + method="POST", + path=("user_management", "authenticate"), + body=body, + model=AuthenticateResponse, + request_options=request_options, + ) + + def authenticate_with_radar_sms_challenge( + self, + *, + code: str, + verification_id: str, + phone_number: str, + pending_authentication_token: str, + ip_address: Optional[str] = None, + device_id: Optional[str] = None, + user_agent: Optional[str] = None, + request_options: Optional[RequestOptions] = None, + ) -> AuthenticateResponse: + """Authenticate with radar sms challenge.""" + body: Dict[str, Any] = { + "grant_type": "urn:workos:oauth:grant-type:radar-sms-challenge:code", + "code": code, + "verification_id": verification_id, + "phone_number": phone_number, + "pending_authentication_token": pending_authentication_token, + } + if self._client.client_id is not None: + body["client_id"] = self._client.client_id + if self._client._api_key is not None: + body["client_secret"] = self._client._api_key + if ip_address is not None: + body["ip_address"] = ip_address + if device_id is not None: + body["device_id"] = device_id + if user_agent is not None: + body["user_agent"] = user_agent + + return self._client.request( + method="POST", + path=("user_management", "authenticate"), + body=body, + model=AuthenticateResponse, + request_options=request_options, + ) + def get_authorization_url( self, *, @@ -2379,6 +2467,8 @@ async def authenticate_with_password( ip_address: Optional[str] = None, device_id: Optional[str] = None, user_agent: Optional[str] = None, + signals_id: Optional[str] = None, + radar_auth_attempt_id: Optional[str] = None, request_options: Optional[RequestOptions] = None, ) -> AuthenticateResponse: """Authenticate with password.""" @@ -2399,6 +2489,10 @@ async def authenticate_with_password( body["device_id"] = device_id if user_agent is not None: body["user_agent"] = user_agent + if signals_id is not None: + body["signals_id"] = signals_id + if radar_auth_attempt_id is not None: + body["radar_auth_attempt_id"] = radar_auth_attempt_id return await self._client.request( method="POST", @@ -2417,6 +2511,7 @@ async def authenticate_with_code( ip_address: Optional[str] = None, device_id: Optional[str] = None, user_agent: Optional[str] = None, + signals_id: Optional[str] = None, request_options: Optional[RequestOptions] = None, ) -> AuthenticateResponse: """Authenticate with code.""" @@ -2438,6 +2533,8 @@ async def authenticate_with_code( body["device_id"] = device_id if user_agent is not None: body["user_agent"] = user_agent + if signals_id is not None: + body["signals_id"] = signals_id return await self._client.request( method="POST", @@ -2492,6 +2589,7 @@ async def authenticate_with_magic_auth( ip_address: Optional[str] = None, device_id: Optional[str] = None, user_agent: Optional[str] = None, + radar_auth_attempt_id: Optional[str] = None, request_options: Optional[RequestOptions] = None, ) -> AuthenticateResponse: """Authenticate with magic auth.""" @@ -2512,6 +2610,8 @@ async def authenticate_with_magic_auth( body["device_id"] = device_id if user_agent is not None: body["user_agent"] = user_agent + if radar_auth_attempt_id is not None: + body["radar_auth_attempt_id"] = radar_auth_attempt_id return await self._client.request( method="POST", @@ -2659,6 +2759,82 @@ async def authenticate_with_device_code( request_options=request_options, ) + async def authenticate_with_radar_email_challenge( + self, + *, + code: str, + radar_challenge_id: str, + pending_authentication_token: str, + ip_address: Optional[str] = None, + device_id: Optional[str] = None, + user_agent: Optional[str] = None, + request_options: Optional[RequestOptions] = None, + ) -> AuthenticateResponse: + """Authenticate with radar email challenge.""" + body: Dict[str, Any] = { + "grant_type": "urn:workos:oauth:grant-type:radar-email-challenge:code", + "code": code, + "radar_challenge_id": radar_challenge_id, + "pending_authentication_token": pending_authentication_token, + } + if self._client.client_id is not None: + body["client_id"] = self._client.client_id + if self._client._api_key is not None: + body["client_secret"] = self._client._api_key + if ip_address is not None: + body["ip_address"] = ip_address + if device_id is not None: + body["device_id"] = device_id + if user_agent is not None: + body["user_agent"] = user_agent + + return await self._client.request( + method="POST", + path=("user_management", "authenticate"), + body=body, + model=AuthenticateResponse, + request_options=request_options, + ) + + async def authenticate_with_radar_sms_challenge( + self, + *, + code: str, + verification_id: str, + phone_number: str, + pending_authentication_token: str, + ip_address: Optional[str] = None, + device_id: Optional[str] = None, + user_agent: Optional[str] = None, + request_options: Optional[RequestOptions] = None, + ) -> AuthenticateResponse: + """Authenticate with radar sms challenge.""" + body: Dict[str, Any] = { + "grant_type": "urn:workos:oauth:grant-type:radar-sms-challenge:code", + "code": code, + "verification_id": verification_id, + "phone_number": phone_number, + "pending_authentication_token": pending_authentication_token, + } + if self._client.client_id is not None: + body["client_id"] = self._client.client_id + if self._client._api_key is not None: + body["client_secret"] = self._client._api_key + if ip_address is not None: + body["ip_address"] = ip_address + if device_id is not None: + body["device_id"] = device_id + if user_agent is not None: + body["user_agent"] = user_agent + + return await self._client.request( + method="POST", + path=("user_management", "authenticate"), + body=body, + model=AuthenticateResponse, + request_options=request_options, + ) + def get_authorization_url( self, *, diff --git a/src/workos/user_management/models/magic_auth_send_magic_auth_code_and_return_response.py b/src/workos/user_management/models/magic_auth_send_magic_auth_code_and_return_response.py index d11374d6..23eeba40 100644 --- a/src/workos/user_management/models/magic_auth_send_magic_auth_code_and_return_response.py +++ b/src/workos/user_management/models/magic_auth_send_magic_auth_code_and_return_response.py @@ -3,14 +3,32 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Any, Dict, Optional +from datetime import datetime +from typing import Any, Dict, Literal, Optional from workos._types import _raise_deserialize_error +from workos._types import _format_datetime, _parse_datetime @dataclass(slots=True) class MagicAuthSendMagicAuthCodeAndReturnResponse: """Magic Auth Send Magic Auth Code And Return Response model.""" + object: Literal["magic_auth"] + """Distinguishes the Magic Auth object.""" + id: str + """The unique ID of the Magic Auth code.""" + user_id: str + """The unique ID of the user.""" + email: str + """The email address of the user.""" + expires_at: datetime + """The timestamp when the Magic Auth code expires.""" + created_at: datetime + """An ISO 8601 timestamp.""" + updated_at: datetime + """An ISO 8601 timestamp.""" + code: str + """The code used to verify the Magic Auth code.""" radar_auth_attempt_id: Optional[str] = None """The ID of the Radar authentication attempt created for this request when Radar is enabled. Pass this value to the authenticate endpoint to associate the subsequent authentication with this Radar attempt.""" @@ -21,6 +39,14 @@ def from_dict( """Deserialize from a dictionary.""" try: return cls( + object=data.get("object", "magic_auth"), + id=data["id"], + user_id=data["user_id"], + email=data["email"], + expires_at=_parse_datetime(data["expires_at"]), + created_at=_parse_datetime(data["created_at"]), + updated_at=_parse_datetime(data["updated_at"]), + code=data["code"], radar_auth_attempt_id=data.get("radar_auth_attempt_id"), ) except (KeyError, ValueError) as e: @@ -29,6 +55,14 @@ def from_dict( def to_dict(self) -> Dict[str, Any]: """Serialize to a dictionary.""" result: Dict[str, Any] = {} + result["object"] = self.object + result["id"] = self.id + result["user_id"] = self.user_id + result["email"] = self.email + result["expires_at"] = _format_datetime(self.expires_at) + result["created_at"] = _format_datetime(self.created_at) + result["updated_at"] = _format_datetime(self.updated_at) + result["code"] = self.code if self.radar_auth_attempt_id is not None: result["radar_auth_attempt_id"] = self.radar_auth_attempt_id return result diff --git a/src/workos/user_management/models/user_create_response.py b/src/workos/user_management/models/user_create_response.py index dcf60080..3d9f2c65 100644 --- a/src/workos/user_management/models/user_create_response.py +++ b/src/workos/user_management/models/user_create_response.py @@ -1,8 +1,114 @@ # This file is auto-generated by oagen. Do not edit. -from typing import TypeAlias -from .magic_auth_send_magic_auth_code_and_return_response import ( - MagicAuthSendMagicAuthCodeAndReturnResponse, -) +from __future__ import annotations -UserCreateResponse: TypeAlias = MagicAuthSendMagicAuthCodeAndReturnResponse +from dataclasses import dataclass +from datetime import datetime +from typing import Any, Dict, Literal, Optional +from workos._types import _raise_deserialize_error +from workos._types import _format_datetime, _parse_datetime + + +@dataclass(slots=True) +class UserCreateResponse: + """User Create Response model.""" + + object: Literal["user"] + """Distinguishes the user object.""" + id: str + """The unique ID of the user.""" + first_name: Optional[str] + """The first name of the user.""" + last_name: Optional[str] + """The last name of the user.""" + profile_picture_url: Optional[str] + """A URL reference to an image representing the user.""" + email: str + """The email address of the user.""" + email_verified: bool + """Whether the user's email has been verified.""" + external_id: Optional[str] + """The external ID of the user.""" + last_sign_in_at: Optional[datetime] + """The timestamp when the user last signed in.""" + created_at: datetime + """An ISO 8601 timestamp.""" + updated_at: datetime + """An ISO 8601 timestamp.""" + name: Optional[str] = None + """The user's full name.""" + metadata: Optional[Dict[str, str]] = None + """Object containing metadata key/value pairs associated with the user.""" + locale: Optional[str] = None + """The user's preferred locale.""" + radar_auth_attempt_id: Optional[str] = None + """The ID of the Radar authentication attempt created for this request when Radar is enabled. Pass this value to the authenticate endpoint to associate the subsequent authentication with this Radar attempt.""" + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> "UserCreateResponse": + """Deserialize from a dictionary.""" + try: + return cls( + object=data.get("object", "user"), + id=data["id"], + first_name=data["first_name"], + last_name=data["last_name"], + profile_picture_url=data["profile_picture_url"], + email=data["email"], + email_verified=data["email_verified"], + external_id=data["external_id"], + last_sign_in_at=_parse_datetime(_v_last_sign_in_at) + if (_v_last_sign_in_at := data["last_sign_in_at"]) is not None + else None, + created_at=_parse_datetime(data["created_at"]), + updated_at=_parse_datetime(data["updated_at"]), + name=data.get("name"), + metadata=data.get("metadata"), + locale=data.get("locale"), + radar_auth_attempt_id=data.get("radar_auth_attempt_id"), + ) + except (KeyError, ValueError) as e: + _raise_deserialize_error("UserCreateResponse", e) + + def to_dict(self) -> Dict[str, Any]: + """Serialize to a dictionary.""" + result: Dict[str, Any] = {} + result["object"] = self.object + result["id"] = self.id + if self.first_name is not None: + result["first_name"] = self.first_name + else: + result["first_name"] = None + if self.last_name is not None: + result["last_name"] = self.last_name + else: + result["last_name"] = None + if self.profile_picture_url is not None: + result["profile_picture_url"] = self.profile_picture_url + else: + result["profile_picture_url"] = None + result["email"] = self.email + result["email_verified"] = self.email_verified + if self.external_id is not None: + result["external_id"] = self.external_id + else: + result["external_id"] = None + if self.last_sign_in_at is not None: + result["last_sign_in_at"] = _format_datetime(self.last_sign_in_at) + else: + result["last_sign_in_at"] = None + result["created_at"] = _format_datetime(self.created_at) + result["updated_at"] = _format_datetime(self.updated_at) + if self.name is not None: + result["name"] = self.name + else: + result["name"] = None + if self.metadata is not None: + result["metadata"] = self.metadata + if self.locale is not None: + result["locale"] = self.locale + else: + result["locale"] = None + if self.radar_auth_attempt_id is not None: + result["radar_auth_attempt_id"] = self.radar_auth_attempt_id + return result diff --git a/tests/fixtures/magic_auth_send_magic_auth_code_and_return_response.json b/tests/fixtures/magic_auth_send_magic_auth_code_and_return_response.json index 762e42d0..6310986b 100644 --- a/tests/fixtures/magic_auth_send_magic_auth_code_and_return_response.json +++ b/tests/fixtures/magic_auth_send_magic_auth_code_and_return_response.json @@ -1,3 +1,11 @@ { + "object": "magic_auth", + "id": "magic_auth_01HWZBQZY2M3AMQW166Q22K88F", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "expires_at": "2026-01-15T12:00:00.000Z", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "code": "123456", "radar_auth_attempt_id": "radar_auth_attempt_01HXYZ123456789ABCDEFGHIJ" } diff --git a/tests/fixtures/user_create_response.json b/tests/fixtures/user_create_response.json index 762e42d0..dbb6ece8 100644 --- a/tests/fixtures/user_create_response.json +++ b/tests/fixtures/user_create_response.json @@ -1,3 +1,19 @@ { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "name": "Marcelina Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.000Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", "radar_auth_attempt_id": "radar_auth_attempt_01HXYZ123456789ABCDEFGHIJ" } diff --git a/tests/test_user_management.py b/tests/test_user_management.py index 5e722725..77a19a1b 100644 --- a/tests/test_user_management.py +++ b/tests/test_user_management.py @@ -266,10 +266,8 @@ def test_create_user(self, workos, httpx_mock): email="test_email", password=PasswordPlaintext(password="test_value") ) assert isinstance(result, UserCreateResponse) - assert ( - result.radar_auth_attempt_id - == "radar_auth_attempt_01HXYZ123456789ABCDEFGHIJ" - ) + assert result.object == "user" + assert result.id == "user_01E4ZCR3C56J083X43JQXF3JK5" request = httpx_mock.get_request() assert request.method == "POST" assert request.url.path.endswith("/user_management/users") @@ -565,10 +563,8 @@ def test_create_magic_auth(self, workos, httpx_mock): ) result = workos.user_management.create_magic_auth(email="test_email") assert isinstance(result, MagicAuthSendMagicAuthCodeAndReturnResponse) - assert ( - result.radar_auth_attempt_id - == "radar_auth_attempt_01HXYZ123456789ABCDEFGHIJ" - ) + assert result.object == "magic_auth" + assert result.id == "magic_auth_01HWZBQZY2M3AMQW166Q22K88F" request = httpx_mock.get_request() assert request.method == "POST" assert request.url.path.endswith("/user_management/magic_auth") @@ -815,6 +811,38 @@ def test_authenticate_with_device_code(self, workos, httpx_mock): body = json.loads(request.content) assert body["grant_type"] == "urn:ietf:params:oauth:grant-type:device_code" + def test_authenticate_with_radar_email_challenge(self, workos, httpx_mock): + httpx_mock.add_response(json=load_fixture("authenticate_response.json")) + result = workos.user_management.authenticate_with_radar_email_challenge( + code="test_value", + radar_challenge_id="test_value", + pending_authentication_token="test_value", + ) + assert isinstance(result, AuthenticateResponse) + request = httpx_mock.get_request() + assert request.method == "POST" + body = json.loads(request.content) + assert ( + body["grant_type"] + == "urn:workos:oauth:grant-type:radar-email-challenge:code" + ) + + def test_authenticate_with_radar_sms_challenge(self, workos, httpx_mock): + httpx_mock.add_response(json=load_fixture("authenticate_response.json")) + result = workos.user_management.authenticate_with_radar_sms_challenge( + code="test_value", + verification_id="test_value", + phone_number="test_value", + pending_authentication_token="test_value", + ) + assert isinstance(result, AuthenticateResponse) + request = httpx_mock.get_request() + assert request.method == "POST" + body = json.loads(request.content) + assert ( + body["grant_type"] == "urn:workos:oauth:grant-type:radar-sms-challenge:code" + ) + def test_get_jwks_with_request_options(self, workos, httpx_mock): httpx_mock.add_response(json=load_fixture("jwks_response.json")) workos.user_management.get_jwks( @@ -1101,10 +1129,8 @@ async def test_create_user(self, async_workos, httpx_mock): email="test_email", password=PasswordPlaintext(password="test_value") ) assert isinstance(result, UserCreateResponse) - assert ( - result.radar_auth_attempt_id - == "radar_auth_attempt_01HXYZ123456789ABCDEFGHIJ" - ) + assert result.object == "user" + assert result.id == "user_01E4ZCR3C56J083X43JQXF3JK5" request = httpx_mock.get_request() assert request.method == "POST" assert request.url.path.endswith("/user_management/users") @@ -1392,10 +1418,8 @@ async def test_create_magic_auth(self, async_workos, httpx_mock): email="test_email" ) assert isinstance(result, MagicAuthSendMagicAuthCodeAndReturnResponse) - assert ( - result.radar_auth_attempt_id - == "radar_auth_attempt_01HXYZ123456789ABCDEFGHIJ" - ) + assert result.object == "magic_auth" + assert result.id == "magic_auth_01HWZBQZY2M3AMQW166Q22K88F" request = httpx_mock.get_request() assert request.method == "POST" assert request.url.path.endswith("/user_management/magic_auth") @@ -1664,6 +1688,48 @@ async def test_authenticate_with_device_code(self, async_workos, httpx_mock): body = json.loads(request.content) assert body["grant_type"] == "urn:ietf:params:oauth:grant-type:device_code" + @pytest.mark.asyncio + async def test_authenticate_with_radar_email_challenge( + self, async_workos, httpx_mock + ): + httpx_mock.add_response(json=load_fixture("authenticate_response.json")) + result = ( + await async_workos.user_management.authenticate_with_radar_email_challenge( + code="test_value", + radar_challenge_id="test_value", + pending_authentication_token="test_value", + ) + ) + assert isinstance(result, AuthenticateResponse) + request = httpx_mock.get_request() + assert request.method == "POST" + body = json.loads(request.content) + assert ( + body["grant_type"] + == "urn:workos:oauth:grant-type:radar-email-challenge:code" + ) + + @pytest.mark.asyncio + async def test_authenticate_with_radar_sms_challenge( + self, async_workos, httpx_mock + ): + httpx_mock.add_response(json=load_fixture("authenticate_response.json")) + result = ( + await async_workos.user_management.authenticate_with_radar_sms_challenge( + code="test_value", + verification_id="test_value", + phone_number="test_value", + pending_authentication_token="test_value", + ) + ) + assert isinstance(result, AuthenticateResponse) + request = httpx_mock.get_request() + assert request.method == "POST" + body = json.loads(request.content) + assert ( + body["grant_type"] == "urn:workos:oauth:grant-type:radar-sms-challenge:code" + ) + @pytest.mark.asyncio async def test_get_jwks_with_request_options(self, async_workos, httpx_mock): httpx_mock.add_response(json=load_fixture("jwks_response.json")) diff --git a/tests/test_user_management_models_round_trip.py b/tests/test_user_management_models_round_trip.py index c24eedf7..8025ea15 100644 --- a/tests/test_user_management_models_round_trip.py +++ b/tests/test_user_management_models_round_trip.py @@ -1101,14 +1101,40 @@ def test_magic_auth_send_magic_auth_code_and_return_response_round_trip(self): assert restored.to_dict() == serialized def test_magic_auth_send_magic_auth_code_and_return_response_minimal_payload(self): - data = {} + data = { + "object": "magic_auth", + "id": "magic_auth_01HWZBQZY2M3AMQW166Q22K88F", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "expires_at": "2026-01-15T12:00:00.000Z", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "code": "123456", + } instance = MagicAuthSendMagicAuthCodeAndReturnResponse.from_dict(data) - assert instance.to_dict() is not None + serialized = instance.to_dict() + assert serialized["object"] == data["object"] + assert serialized["id"] == data["id"] + assert serialized["user_id"] == data["user_id"] + assert serialized["email"] == data["email"] + assert serialized["expires_at"] == data["expires_at"] + assert serialized["created_at"] == data["created_at"] + assert serialized["updated_at"] == data["updated_at"] + assert serialized["code"] == data["code"] def test_magic_auth_send_magic_auth_code_and_return_response_omits_absent_optional_non_nullable_fields( self, ): - data = {} + data = { + "object": "magic_auth", + "id": "magic_auth_01HWZBQZY2M3AMQW166Q22K88F", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "expires_at": "2026-01-15T12:00:00.000Z", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "code": "123456", + } instance = MagicAuthSendMagicAuthCodeAndReturnResponse.from_dict(data) serialized = instance.to_dict() assert "radar_auth_attempt_id" not in serialized @@ -1122,16 +1148,82 @@ def test_user_create_response_round_trip(self): assert restored.to_dict() == serialized def test_user_create_response_minimal_payload(self): - data = {} + data = { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": None, + "last_name": None, + "profile_picture_url": None, + "email": "marcelina.davis@example.com", + "email_verified": True, + "external_id": None, + "last_sign_in_at": None, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + } instance = UserCreateResponse.from_dict(data) - assert instance.to_dict() is not None + serialized = instance.to_dict() + assert serialized["object"] == data["object"] + assert serialized["id"] == data["id"] + assert serialized["first_name"] == data["first_name"] + assert serialized["last_name"] == data["last_name"] + assert serialized["profile_picture_url"] == data["profile_picture_url"] + assert serialized["email"] == data["email"] + assert serialized["email_verified"] == data["email_verified"] + assert serialized["external_id"] == data["external_id"] + assert serialized["last_sign_in_at"] == data["last_sign_in_at"] + assert serialized["created_at"] == data["created_at"] + assert serialized["updated_at"] == data["updated_at"] def test_user_create_response_omits_absent_optional_non_nullable_fields(self): - data = {} + data = { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "name": "Marcelina Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": True, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "last_sign_in_at": "2025-06-25T19:07:33.000Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + } instance = UserCreateResponse.from_dict(data) serialized = instance.to_dict() + assert "metadata" not in serialized assert "radar_auth_attempt_id" not in serialized + def test_user_create_response_preserves_nullable_fields(self): + data = { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": None, + "last_name": None, + "name": None, + "profile_picture_url": None, + "email": "marcelina.davis@example.com", + "email_verified": True, + "external_id": None, + "metadata": {"timezone": "America/New_York"}, + "last_sign_in_at": None, + "locale": None, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "radar_auth_attempt_id": "radar_auth_attempt_01HXYZ123456789ABCDEFGHIJ", + } + instance = UserCreateResponse.from_dict(data) + serialized = instance.to_dict() + assert serialized["first_name"] is None + assert serialized["last_name"] is None + assert serialized["name"] is None + assert serialized["profile_picture_url"] is None + assert serialized["external_id"] is None + assert serialized["last_sign_in_at"] is None + assert serialized["locale"] is None + def test_email_change_confirmation_round_trip(self): data = load_fixture("email_change_confirmation.json") instance = EmailChangeConfirmation.from_dict(data)