diff --git a/.changelog-pending/2026-07-02T17-30-16-71b13e04b6092eeef8253b4bfbcda055ceb2f35a.md b/.changelog-pending/2026-07-02T17-30-16-71b13e04b6092eeef8253b4bfbcda055ceb2f35a.md new file mode 100644 index 00000000..9cbec7da --- /dev/null +++ b/.changelog-pending/2026-07-02T17-30-16-71b13e04b6092eeef8253b4bfbcda055ceb2f35a.md @@ -0,0 +1,30 @@ +* [#123](https://github.com/workos/workos-rust/pull/123) feat(generated): regenerate from spec (2 changes) + + **Features** + * **[user_management](https://workos.com/docs/reference/authkit/user)**: + * Added model `SendRadarSmsChallenge` + * Added model `SendRadarSmsChallengeResponse` + * Added model `UrnWorkosOAuthGrantTypeRadarEmailChallengeCodeSessionAuthenticateRequest` + * Added model `UrnWorkosOAuthGrantTypeRadarSmsChallengeCodeSessionAuthenticateRequest` + * Added model `MagicAuthSendMagicAuthCodeAndReturnResponse` + * Added model `UserCreateResponse` + * Added `ip_address` to `CreateMagicCodeAndReturn` + * Added `user_agent` to `CreateMagicCodeAndReturn` + * Added `radar_auth_attempt_id` to `CreateMagicCodeAndReturn` + * Added `signals_id` to `CreateMagicCodeAndReturn` + * Added `ip_address` to `CreateUser` + * Added `user_agent` to `CreateUser` + * Added `signals_id` to `CreateUser` + * Added `signals_id` to `AuthorizationCodeSessionAuthenticateRequest` + * Added `signals_id` to `PasswordSessionAuthenticateRequest` + * Added `radar_auth_attempt_id` to `PasswordSessionAuthenticateRequest` + * Added `radar_auth_attempt_id` to `UrnWorkosOAuthGrantTypeMagicAuthCodeSessionAuthenticateRequest` + * Added endpoint `POST /user_management/radar_challenges` + * **[radar](https://workos.com/docs/reference/radar)**: + * Added `signals_id` to `RadarStandaloneAssessRequest` + + **Fixes** + * **[user_management](https://workos.com/docs/reference/authkit/user)**: + * Changed request body for `UserManagementAuthentication.authenticate` + * Changed response of `UserManagementUsers.create` from `User` to `UserCreateResponse` + * Changed response of `UserManagementMagicAuth.sendMagicAuthCodeAndReturn` from `MagicAuth` to `MagicAuthSendMagicAuthCodeAndReturnResponse` diff --git a/.oagen-manifest.json b/.oagen-manifest.json index edd4e374..015811eb 100644 --- a/.oagen-manifest.json +++ b/.oagen-manifest.json @@ -1,7 +1,7 @@ { "version": 2, "language": "rust", - "generatedAt": "2026-07-02T14:58:53.128Z", + "generatedAt": "2026-07-02T17:29:47.884Z", "files": [ "src/enums/audit_log_configuration_log_stream_state.rs", "src/enums/audit_log_configuration_log_stream_type.rs", @@ -463,6 +463,7 @@ "src/models/magic_auth_code_session_authenticate_request.rs", "src/models/magic_auth_created.rs", "src/models/magic_auth_created_data.rs", + "src/models/magic_auth_send_magic_auth_code_and_return_response.rs", "src/models/mfa_totp_session_authenticate_request.rs", "src/models/mod.rs", "src/models/new_connect_application_secret.rs", @@ -537,7 +538,9 @@ "src/models/pipes_connected_account_reauthorization_needed.rs", "src/models/portal_link_response.rs", "src/models/profile.rs", + "src/models/radar_email_challenge_code_session_authenticate_request.rs", "src/models/radar_list_entry_already_present_response.rs", + "src/models/radar_sms_challenge_code_session_authenticate_request.rs", "src/models/radar_standalone_assess_request.rs", "src/models/radar_standalone_delete_radar_list_entry_request.rs", "src/models/radar_standalone_response.rs", @@ -562,6 +565,8 @@ "src/models/role_updated.rs", "src/models/role_updated_data.rs", "src/models/send_email_change.rs", + "src/models/send_radar_sms_challenge.rs", + "src/models/send_radar_sms_challenge_response.rs", "src/models/send_verification_email_response.rs", "src/models/session_created.rs", "src/models/session_created_data.rs", @@ -609,6 +614,7 @@ "src/models/user_authentication_factor_list_list_metadata.rs", "src/models/user_consent_option.rs", "src/models/user_consent_option_choice.rs", + "src/models/user_create_response.rs", "src/models/user_created.rs", "src/models/user_deleted.rs", "src/models/user_identities_get_item.rs", @@ -1025,6 +1031,7 @@ "tests/fixtures/magic_auth_code_session_authenticate_request.json", "tests/fixtures/magic_auth_created.json", "tests/fixtures/magic_auth_created_data.json", + "tests/fixtures/magic_auth_send_magic_auth_code_and_return_response.json", "tests/fixtures/mfa_totp_session_authenticate_request.json", "tests/fixtures/new_connect_application_secret.json", "tests/fixtures/object_list_response.json", @@ -1098,7 +1105,9 @@ "tests/fixtures/pipes_connected_account_reauthorization_needed.json", "tests/fixtures/portal_link_response.json", "tests/fixtures/profile.json", + "tests/fixtures/radar_email_challenge_code_session_authenticate_request.json", "tests/fixtures/radar_list_entry_already_present_response.json", + "tests/fixtures/radar_sms_challenge_code_session_authenticate_request.json", "tests/fixtures/radar_standalone_assess_request.json", "tests/fixtures/radar_standalone_delete_radar_list_entry_request.json", "tests/fixtures/radar_standalone_response.json", @@ -1123,6 +1132,8 @@ "tests/fixtures/role_updated.json", "tests/fixtures/role_updated_data.json", "tests/fixtures/send_email_change.json", + "tests/fixtures/send_radar_sms_challenge.json", + "tests/fixtures/send_radar_sms_challenge_response.json", "tests/fixtures/send_verification_email_response.json", "tests/fixtures/session_created.json", "tests/fixtures/session_created_data.json", @@ -1170,6 +1181,7 @@ "tests/fixtures/user_authentication_factor_list_list_metadata.json", "tests/fixtures/user_consent_option.json", "tests/fixtures/user_consent_option_choice.json", + "tests/fixtures/user_create_response.json", "tests/fixtures/user_created.json", "tests/fixtures/user_deleted.json", "tests/fixtures/user_identities_get_item.json", diff --git a/src/models/authorization_code_session_authenticate_request.rs b/src/models/authorization_code_session_authenticate_request.rs index 270dc1bb..e3de1f49 100644 --- a/src/models/authorization_code_session_authenticate_request.rs +++ b/src/models/authorization_code_session_authenticate_request.rs @@ -30,4 +30,7 @@ pub struct AuthorizationCodeSessionAuthenticateRequest { /// The user agent string from the user's browser. #[serde(skip_serializing_if = "Option::is_none", default)] pub user_agent: Option, + /// An optional Radar signals ID to correlate client-side signals with this authentication attempt. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub signals_id: Option, } diff --git a/src/models/create_magic_code_and_return.rs b/src/models/create_magic_code_and_return.rs index c19ed9f6..aa0f5925 100644 --- a/src/models/create_magic_code_and_return.rs +++ b/src/models/create_magic_code_and_return.rs @@ -12,4 +12,16 @@ pub struct CreateMagicCodeAndReturn { /// The invitation token to associate with this magic code. #[serde(skip_serializing_if = "Option::is_none", default)] pub invitation_token: Option, + /// The IP address of the user's request. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub ip_address: Option, + /// The user agent string from the user's request. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub user_agent: Option, + /// The ID of an existing Radar authentication attempt to associate with this request. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub radar_auth_attempt_id: Option, + /// An optional Radar signals ID to correlate client-side signals with this request. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub signals_id: Option, } diff --git a/src/models/create_user.rs b/src/models/create_user.rs index ef7bbb1a..3a90e75c 100644 --- a/src/models/create_user.rs +++ b/src/models/create_user.rs @@ -27,6 +27,15 @@ pub struct CreateUser { /// The external ID of the user. #[serde(skip_serializing_if = "Option::is_none", default)] pub external_id: Option, + /// The IP address of the user's request. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub ip_address: Option, + /// The user agent string from the user's request. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub user_agent: Option, + /// An optional Radar signals ID to correlate client-side signals with this request. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub signals_id: Option, /// The password to set for the user. Mutually exclusive with `password_hash` and `password_hash_type`. #[serde(skip_serializing_if = "Option::is_none", default)] pub password: Option, diff --git a/src/models/magic_auth_code_session_authenticate_request.rs b/src/models/magic_auth_code_session_authenticate_request.rs index 4d4954c0..a07d861d 100644 --- a/src/models/magic_auth_code_session_authenticate_request.rs +++ b/src/models/magic_auth_code_session_authenticate_request.rs @@ -28,4 +28,7 @@ pub struct MagicAuthCodeSessionAuthenticateRequest { /// The user agent string from the user's browser. #[serde(skip_serializing_if = "Option::is_none", default)] pub user_agent: Option, + /// The ID of an existing Radar authentication attempt to associate with this authentication. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub radar_auth_attempt_id: Option, } diff --git a/src/models/magic_auth_send_magic_auth_code_and_return_response.rs b/src/models/magic_auth_send_magic_auth_code_and_return_response.rs new file mode 100644 index 00000000..1253a093 --- /dev/null +++ b/src/models/magic_auth_send_magic_auth_code_and_return_response.rs @@ -0,0 +1,13 @@ +// This file is auto-generated by oagen. Do not edit. + +#[allow(unused_imports)] +use super::*; +#[allow(unused_imports)] +use crate::enums::*; +use serde::{Deserialize, Serialize}; +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MagicAuthSendMagicAuthCodeAndReturnResponse { + /// 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. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub radar_auth_attempt_id: Option, +} diff --git a/src/models/mod.rs b/src/models/mod.rs index e973acde..f7e49f1c 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -325,6 +325,7 @@ mod magic_auth; mod magic_auth_code_session_authenticate_request; mod magic_auth_created; mod magic_auth_created_data; +mod magic_auth_send_magic_auth_code_and_return_response; mod mfa_totp_session_authenticate_request; mod new_connect_application_secret; mod object_list_response; @@ -398,7 +399,9 @@ mod pipes_connected_account_disconnected; mod pipes_connected_account_reauthorization_needed; mod portal_link_response; mod profile; +mod radar_email_challenge_code_session_authenticate_request; mod radar_list_entry_already_present_response; +mod radar_sms_challenge_code_session_authenticate_request; mod radar_standalone_assess_request; mod radar_standalone_delete_radar_list_entry_request; mod radar_standalone_response; @@ -423,6 +426,8 @@ mod role_list; mod role_updated; mod role_updated_data; mod send_email_change; +mod send_radar_sms_challenge; +mod send_radar_sms_challenge_response; mod send_verification_email_response; mod session_created; mod session_created_data; @@ -470,6 +475,7 @@ mod user_authentication_factor_list; mod user_authentication_factor_list_list_metadata; mod user_consent_option; mod user_consent_option_choice; +mod user_create_response; mod user_created; mod user_deleted; mod user_identities_get_item; @@ -856,6 +862,7 @@ pub use magic_auth::*; pub use magic_auth_code_session_authenticate_request::*; pub use magic_auth_created::*; pub use magic_auth_created_data::*; +pub use magic_auth_send_magic_auth_code_and_return_response::*; pub use mfa_totp_session_authenticate_request::*; pub use new_connect_application_secret::*; pub use object_list_response::*; @@ -929,7 +936,9 @@ pub use pipes_connected_account_disconnected::*; pub use pipes_connected_account_reauthorization_needed::*; pub use portal_link_response::*; pub use profile::*; +pub use radar_email_challenge_code_session_authenticate_request::*; pub use radar_list_entry_already_present_response::*; +pub use radar_sms_challenge_code_session_authenticate_request::*; pub use radar_standalone_assess_request::*; pub use radar_standalone_delete_radar_list_entry_request::*; pub use radar_standalone_response::*; @@ -954,6 +963,8 @@ pub use role_list::*; pub use role_updated::*; pub use role_updated_data::*; pub use send_email_change::*; +pub use send_radar_sms_challenge::*; +pub use send_radar_sms_challenge_response::*; pub use send_verification_email_response::*; pub use session_created::*; pub use session_created_data::*; @@ -1001,6 +1012,7 @@ pub use user_authentication_factor_list::*; pub use user_authentication_factor_list_list_metadata::*; pub use user_consent_option::*; pub use user_consent_option_choice::*; +pub use user_create_response::*; pub use user_created::*; pub use user_deleted::*; pub use user_identities_get_item::*; diff --git a/src/models/password_session_authenticate_request.rs b/src/models/password_session_authenticate_request.rs index 76996c50..85c50354 100644 --- a/src/models/password_session_authenticate_request.rs +++ b/src/models/password_session_authenticate_request.rs @@ -28,4 +28,10 @@ pub struct PasswordSessionAuthenticateRequest { /// The user agent string from the user's browser. #[serde(skip_serializing_if = "Option::is_none", default)] pub user_agent: Option, + /// An optional Radar signals ID to correlate client-side signals with this authentication attempt. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub signals_id: Option, + /// The ID of an existing Radar authentication attempt to associate with this authentication. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub radar_auth_attempt_id: Option, } diff --git a/src/models/radar_email_challenge_code_session_authenticate_request.rs b/src/models/radar_email_challenge_code_session_authenticate_request.rs new file mode 100644 index 00000000..cee151c8 --- /dev/null +++ b/src/models/radar_email_challenge_code_session_authenticate_request.rs @@ -0,0 +1,30 @@ +// This file is auto-generated by oagen. Do not edit. + +#[allow(unused_imports)] +use super::*; +#[allow(unused_imports)] +use crate::enums::*; +use serde::{Deserialize, Serialize}; +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct RadarEmailChallengeCodeSessionAuthenticateRequest { + /// The client ID of the application. + pub client_id: String, + /// The client secret of the application. + pub client_secret: crate::SecretString, + pub grant_type: String, + /// The one-time code from the Radar email challenge. + pub code: String, + /// The ID of the Radar email challenge being verified. + pub radar_challenge_id: String, + /// The pending authentication token from a previous authentication attempt. + pub pending_authentication_token: crate::SecretString, + /// The IP address of the user's request. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub ip_address: Option, + /// A unique identifier for the device. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub device_id: Option, + /// The user agent string from the user's browser. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub user_agent: Option, +} diff --git a/src/models/radar_sms_challenge_code_session_authenticate_request.rs b/src/models/radar_sms_challenge_code_session_authenticate_request.rs new file mode 100644 index 00000000..31ba0bc6 --- /dev/null +++ b/src/models/radar_sms_challenge_code_session_authenticate_request.rs @@ -0,0 +1,32 @@ +// This file is auto-generated by oagen. Do not edit. + +#[allow(unused_imports)] +use super::*; +#[allow(unused_imports)] +use crate::enums::*; +use serde::{Deserialize, Serialize}; +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct RadarSmsChallengeCodeSessionAuthenticateRequest { + /// The client ID of the application. + pub client_id: String, + /// The client secret of the application. + pub client_secret: crate::SecretString, + pub grant_type: String, + /// The one-time code from the Radar SMS challenge. + pub code: String, + /// The ID of the Radar SMS verification being confirmed. + pub verification_id: String, + /// The phone number the Radar SMS challenge was sent to. + pub phone_number: String, + /// The pending authentication token from a previous authentication attempt. + pub pending_authentication_token: crate::SecretString, + /// The IP address of the user's request. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub ip_address: Option, + /// A unique identifier for the device. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub device_id: Option, + /// The user agent string from the user's browser. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub user_agent: Option, +} diff --git a/src/models/radar_standalone_assess_request.rs b/src/models/radar_standalone_assess_request.rs index 5e056e80..de9498d0 100644 --- a/src/models/radar_standalone_assess_request.rs +++ b/src/models/radar_standalone_assess_request.rs @@ -17,4 +17,7 @@ pub struct RadarStandaloneAssessRequest { pub auth_method: RadarStandaloneAssessRequestAuthMethod, /// The action being performed. pub action: RadarStandaloneAssessRequestAction, + /// An optional Radar signals ID for the request. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub signals_id: Option, } diff --git a/src/models/send_radar_sms_challenge.rs b/src/models/send_radar_sms_challenge.rs new file mode 100644 index 00000000..dd5e1070 --- /dev/null +++ b/src/models/send_radar_sms_challenge.rs @@ -0,0 +1,22 @@ +// This file is auto-generated by oagen. Do not edit. + +#[allow(unused_imports)] +use super::*; +#[allow(unused_imports)] +use crate::enums::*; +use serde::{Deserialize, Serialize}; +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SendRadarSmsChallenge { + /// The ID of the user to send the SMS challenge to. + pub user_id: String, + /// The pending authentication token from a previous authentication attempt that triggered the Radar challenge. + pub pending_authentication_token: crate::SecretString, + /// The phone number to send the SMS verification code to. + pub phone_number: String, + /// The IP address of the user's request. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub ip_address: Option, + /// The user agent string from the user's request. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub user_agent: Option, +} diff --git a/src/models/send_radar_sms_challenge_response.rs b/src/models/send_radar_sms_challenge_response.rs new file mode 100644 index 00000000..0de0854a --- /dev/null +++ b/src/models/send_radar_sms_challenge_response.rs @@ -0,0 +1,14 @@ +// This file is auto-generated by oagen. Do not edit. + +#[allow(unused_imports)] +use super::*; +#[allow(unused_imports)] +use crate::enums::*; +use serde::{Deserialize, Serialize}; +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SendRadarSmsChallengeResponse { + /// The ID of the SMS verification. Pass this to the authenticate endpoint to verify the code. + pub verification_id: String, + /// The phone number the verification code was sent to. + pub phone_number: String, +} diff --git a/src/models/user_create_response.rs b/src/models/user_create_response.rs new file mode 100644 index 00000000..e38ecec0 --- /dev/null +++ b/src/models/user_create_response.rs @@ -0,0 +1,13 @@ +// This file is auto-generated by oagen. Do not edit. + +#[allow(unused_imports)] +use super::*; +#[allow(unused_imports)] +use crate::enums::*; +use serde::{Deserialize, Serialize}; +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct UserCreateResponse { + /// 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. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub radar_auth_attempt_id: Option, +} diff --git a/src/resources/user_management.rs b/src/resources/user_management.rs index 8a49ecaa..21892b5d 100644 --- a/src/resources/user_management.rs +++ b/src/resources/user_management.rs @@ -48,6 +48,15 @@ pub struct CreateUserParamsBody { /// The external ID of the user. #[serde(skip_serializing_if = "Option::is_none")] pub external_id: Option, + /// The IP address of the user's request. + #[serde(skip_serializing_if = "Option::is_none")] + pub ip_address: Option, + /// The user agent string from the user's request. + #[serde(skip_serializing_if = "Option::is_none")] + pub user_agent: Option, + /// An optional Radar signals ID to correlate client-side signals with this request. + #[serde(skip_serializing_if = "Option::is_none")] + pub signals_id: Option, #[serde(flatten)] #[serde(skip_serializing_if = "Option::is_none")] pub password: Option, @@ -64,6 +73,9 @@ impl CreateUserParamsBody { email_verified: Default::default(), metadata: Default::default(), external_id: Default::default(), + ip_address: Default::default(), + user_agent: Default::default(), + signals_id: Default::default(), password: Default::default(), } } @@ -467,6 +479,23 @@ impl CreateDeviceParams { } } +#[derive(Debug, Clone, Serialize)] +pub struct CreateRadarChallengeParams { + /// Request body sent with this call. + /// + /// Required. + #[serde(skip)] + pub body: SendRadarSmsChallenge, +} + +impl CreateRadarChallengeParams { + /// Construct a new `CreateRadarChallengeParams` with the required fields set. + #[allow(deprecated)] + pub fn new(body: SendRadarSmsChallenge) -> Self { + Self { body } + } +} + #[derive(Debug, Clone, Serialize)] pub struct GetLogoutUrlParams { /// The ID of the session. This can be extracted from the `sid` claim of the access token. @@ -1387,6 +1416,29 @@ impl<'a> UserManagementApi<'a> { .await } + /// Send a Radar SMS challenge + /// + /// Sends a one-time verification code over SMS to a user as part of a Radar challenge. Use the returned `verification_id` to authenticate the user with the `urn:workos:oauth:grant-type:radar-sms-challenge:code` grant type. + pub async fn create_radar_challenge( + &self, + params: CreateRadarChallengeParams, + ) -> Result { + self.create_radar_challenge_with_options(params, None).await + } + + /// Variant of [`Self::create_radar_challenge`] that accepts per-request [`crate::RequestOptions`]. + pub async fn create_radar_challenge_with_options( + &self, + params: CreateRadarChallengeParams, + options: Option<&crate::RequestOptions>, + ) -> Result { + let path = "/user_management/radar_challenges".to_string(); + let method = http::Method::POST; + self.client + .request_with_body_opts(method, &path, ¶ms, Some(¶ms.body), options) + .await + } + /// Logout /// /// Logout a user from the current [session](https://workos.com/docs/reference/authkit/session). @@ -1626,7 +1678,7 @@ impl<'a> UserManagementApi<'a> { /// Create a user /// /// Create a new user in the current environment. - pub async fn create_user(&self, params: CreateUserParams) -> Result { + pub async fn create_user(&self, params: CreateUserParams) -> Result { self.create_user_with_options(params, None).await } @@ -1635,7 +1687,7 @@ impl<'a> UserManagementApi<'a> { &self, params: CreateUserParams, options: Option<&crate::RequestOptions>, - ) -> Result { + ) -> Result { let path = "/user_management/users".to_string(); let method = http::Method::POST; self.client @@ -2132,7 +2184,7 @@ impl<'a> UserManagementApi<'a> { pub async fn create_magic_auth( &self, params: CreateMagicAuthParams, - ) -> Result { + ) -> Result { self.create_magic_auth_with_options(params, None).await } @@ -2141,7 +2193,7 @@ impl<'a> UserManagementApi<'a> { &self, params: CreateMagicAuthParams, options: Option<&crate::RequestOptions>, - ) -> Result { + ) -> Result { let path = "/user_management/magic_auth".to_string(); let method = http::Method::POST; self.client 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 new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/tests/fixtures/magic_auth_send_magic_auth_code_and_return_response.json @@ -0,0 +1 @@ +{} diff --git a/tests/fixtures/radar_email_challenge_code_session_authenticate_request.json b/tests/fixtures/radar_email_challenge_code_session_authenticate_request.json new file mode 100644 index 00000000..6f2be154 --- /dev/null +++ b/tests/fixtures/radar_email_challenge_code_session_authenticate_request.json @@ -0,0 +1,8 @@ +{ + "client_id": "client_01HXYZ123456789ABCDEFGHIJ", + "client_secret": "sk_test_....", + "grant_type": "urn:workos:oauth:grant-type:radar-email-challenge:code", + "code": "123456", + "radar_challenge_id": "radar_challenge_01HXYZ123456789ABCDEFGHIJ", + "pending_authentication_token": "cTDQJTTkTkkVYxbn..." +} diff --git a/tests/fixtures/radar_sms_challenge_code_session_authenticate_request.json b/tests/fixtures/radar_sms_challenge_code_session_authenticate_request.json new file mode 100644 index 00000000..af5eaa55 --- /dev/null +++ b/tests/fixtures/radar_sms_challenge_code_session_authenticate_request.json @@ -0,0 +1,9 @@ +{ + "client_id": "client_01HXYZ123456789ABCDEFGHIJ", + "client_secret": "sk_test_....", + "grant_type": "urn:workos:oauth:grant-type:radar-sms-challenge:code", + "code": "123456", + "verification_id": "vrf_01HXYZ123456789ABCDEFGHIJ", + "phone_number": "+15555550123", + "pending_authentication_token": "cTDQJTTkTkkVYxbn..." +} diff --git a/tests/fixtures/send_radar_sms_challenge.json b/tests/fixtures/send_radar_sms_challenge.json new file mode 100644 index 00000000..de128d3f --- /dev/null +++ b/tests/fixtures/send_radar_sms_challenge.json @@ -0,0 +1,5 @@ +{ + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "pending_authentication_token": "cTDQJTTkTkkVYxbn...", + "phone_number": "+15555550123" +} diff --git a/tests/fixtures/send_radar_sms_challenge_response.json b/tests/fixtures/send_radar_sms_challenge_response.json new file mode 100644 index 00000000..933637b9 --- /dev/null +++ b/tests/fixtures/send_radar_sms_challenge_response.json @@ -0,0 +1,4 @@ +{ + "verification_id": "vrf_01HXYZ123456789ABCDEFGHIJ", + "phone_number": "+15555550123" +} diff --git a/tests/fixtures/user_create_response.json b/tests/fixtures/user_create_response.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/tests/fixtures/user_create_response.json @@ -0,0 +1 @@ +{} diff --git a/tests/user_management_test.rs b/tests/user_management_test.rs index 1a3fc21c..8f4b0539 100644 --- a/tests/user_management_test.rs +++ b/tests/user_management_test.rs @@ -1856,6 +1856,188 @@ async fn user_management_create_device_unprocessable() { assert_eq!(api.status, 422); } +#[tokio::test] +async fn user_management_create_radar_challenge_round_trip() { + let server = MockServer::start().await; + Mock::given(method("POST")) + .and(path_matcher("/user_management/radar_challenges")) + .respond_with(ResponseTemplate::new(200).set_body_string(include_str!( + "fixtures/send_radar_sms_challenge_response.json" + ))) + .expect(1) + .mount(&server) + .await; + let client = common::test_client(&server).await; + let _ = client + .user_management() + .create_radar_challenge(workos::user_management::CreateRadarChallengeParams::new( + serde_json::from_str(include_str!("fixtures/send_radar_sms_challenge.json")) + .expect("parse fixture for SendRadarSmsChallenge"), + )) + .await; +} + +#[tokio::test] +async fn user_management_create_radar_challenge_unauthorized() { + let server = MockServer::start().await; + let template = ResponseTemplate::new(401).set_body_string("{\"message\":\"Unauthorized\"}"); + Mock::given(method("POST")) + .and(path_matcher("/user_management/radar_challenges")) + .respond_with(template) + .expect(1) + .mount(&server) + .await; + let client = common::test_client(&server).await; + let err = client + .user_management() + .create_radar_challenge(workos::user_management::CreateRadarChallengeParams::new( + serde_json::from_str(include_str!("fixtures/send_radar_sms_challenge.json")) + .expect("parse fixture for SendRadarSmsChallenge"), + )) + .await + .expect_err("expected error"); + let api = match &err { + Error::Api(api) => api.as_ref(), + other => panic!("expected Error::Api, got {other:?}"), + }; + assert_eq!(api.status, 401); +} + +#[tokio::test] +async fn user_management_create_radar_challenge_not_found() { + let server = MockServer::start().await; + let template = ResponseTemplate::new(404).set_body_string("{\"message\":\"Not found\"}"); + Mock::given(method("POST")) + .and(path_matcher("/user_management/radar_challenges")) + .respond_with(template) + .expect(1) + .mount(&server) + .await; + let client = common::test_client(&server).await; + let err = client + .user_management() + .create_radar_challenge(workos::user_management::CreateRadarChallengeParams::new( + serde_json::from_str(include_str!("fixtures/send_radar_sms_challenge.json")) + .expect("parse fixture for SendRadarSmsChallenge"), + )) + .await + .expect_err("expected error"); + let api = match &err { + Error::Api(api) => api.as_ref(), + other => panic!("expected Error::Api, got {other:?}"), + }; + assert_eq!(api.status, 404); +} + +#[tokio::test] +async fn user_management_create_radar_challenge_rate_limited() { + let server = MockServer::start().await; + let template = ResponseTemplate::new(429) + .insert_header("retry-after", "1") + .set_body_string("{\"message\":\"Slow down\"}"); + Mock::given(method("POST")) + .and(path_matcher("/user_management/radar_challenges")) + .respond_with(template) + .expect(1) + .mount(&server) + .await; + let client = common::test_client(&server).await; + let err = client + .user_management() + .create_radar_challenge(workos::user_management::CreateRadarChallengeParams::new( + serde_json::from_str(include_str!("fixtures/send_radar_sms_challenge.json")) + .expect("parse fixture for SendRadarSmsChallenge"), + )) + .await + .expect_err("expected error"); + let api = match &err { + Error::Api(api) => api.as_ref(), + other => panic!("expected Error::Api, got {other:?}"), + }; + assert_eq!(api.status, 429); + assert_eq!(api.retry_after, Some(std::time::Duration::from_secs(1))); +} + +#[tokio::test] +async fn user_management_create_radar_challenge_server_error() { + let server = MockServer::start().await; + let template = ResponseTemplate::new(500).set_body_string("{\"message\":\"Internal error\"}"); + Mock::given(method("POST")) + .and(path_matcher("/user_management/radar_challenges")) + .respond_with(template) + .expect(1) + .mount(&server) + .await; + let client = common::test_client(&server).await; + let err = client + .user_management() + .create_radar_challenge(workos::user_management::CreateRadarChallengeParams::new( + serde_json::from_str(include_str!("fixtures/send_radar_sms_challenge.json")) + .expect("parse fixture for SendRadarSmsChallenge"), + )) + .await + .expect_err("expected error"); + let api = match &err { + Error::Api(api) => api.as_ref(), + other => panic!("expected Error::Api, got {other:?}"), + }; + assert_eq!(api.status, 500); +} + +#[tokio::test] +async fn user_management_create_radar_challenge_bad_request() { + let server = MockServer::start().await; + let template = ResponseTemplate::new(400) + .set_body_string("{\"code\":\"validation_error\",\"message\":\"Bad request\"}"); + Mock::given(method("POST")) + .and(path_matcher("/user_management/radar_challenges")) + .respond_with(template) + .expect(1) + .mount(&server) + .await; + let client = common::test_client(&server).await; + let err = client + .user_management() + .create_radar_challenge(workos::user_management::CreateRadarChallengeParams::new( + serde_json::from_str(include_str!("fixtures/send_radar_sms_challenge.json")) + .expect("parse fixture for SendRadarSmsChallenge"), + )) + .await + .expect_err("expected error"); + let api = match &err { + Error::Api(api) => api.as_ref(), + other => panic!("expected Error::Api, got {other:?}"), + }; + assert_eq!(api.status, 400); + assert_eq!(api.code.as_deref(), Some("validation_error")); +} + +#[tokio::test] +async fn user_management_create_radar_challenge_unprocessable() { + let server = MockServer::start().await; + let template = ResponseTemplate::new(422).set_body_string("{\"message\":\"Unprocessable\"}"); + Mock::given(method("POST")) + .and(path_matcher("/user_management/radar_challenges")) + .respond_with(template) + .expect(1) + .mount(&server) + .await; + let client = common::test_client(&server).await; + let err = client + .user_management() + .create_radar_challenge(workos::user_management::CreateRadarChallengeParams::new( + serde_json::from_str(include_str!("fixtures/send_radar_sms_challenge.json")) + .expect("parse fixture for SendRadarSmsChallenge"), + )) + .await + .expect_err("expected error"); + let api = match &err { + Error::Api(api) => api.as_ref(), + other => panic!("expected Error::Api, got {other:?}"), + }; + assert_eq!(api.status, 422); +} + #[tokio::test] async fn user_management_get_logout_url_round_trip() { let server = MockServer::start().await; @@ -3093,9 +3275,7 @@ async fn user_management_create_user_round_trip() { let server = MockServer::start().await; Mock::given(method("POST")) .and(path_matcher("/user_management/users")) - .respond_with( - ResponseTemplate::new(200).set_body_string(include_str!("fixtures/user.json")), - ) + .respond_with(ResponseTemplate::new(200).set_body_string("{}")) .expect(1) .mount(&server) .await; @@ -6288,9 +6468,7 @@ async fn user_management_create_magic_auth_round_trip() { let server = MockServer::start().await; Mock::given(method("POST")) .and(path_matcher("/user_management/magic_auth")) - .respond_with( - ResponseTemplate::new(200).set_body_string(include_str!("fixtures/magic_auth.json")), - ) + .respond_with(ResponseTemplate::new(200).set_body_string("{}")) .expect(1) .mount(&server) .await;