bitwarden_auth/login/
login_client.rs

1use bitwarden_core::{Client, ClientSettings};
2#[cfg(feature = "wasm")]
3use wasm_bindgen::prelude::*;
4
5/// Client for authenticating Bitwarden users.
6///
7/// Handles unauthenticated operations to obtain access tokens from the Identity API.
8/// After successful authentication, use the returned tokens to create an authenticated core client.
9///
10/// # Lifecycle
11///
12/// 1. Create `LoginClient` via `AuthClient`
13/// 2. Call login method
14/// 3. Use returned tokens with authenticated core client
15///
16/// # Password Login Example
17///
18/// ```rust,no_run
19/// # use bitwarden_auth::{AuthClient, login::login_via_password::PasswordLoginRequest};
20/// # use bitwarden_auth::login::models::{LoginRequest, LoginDeviceRequest, LoginResponse};
21/// # use bitwarden_core::{Client, ClientSettings, DeviceType};
22/// # async fn example(email: String, password: String) -> Result<(), Box<dyn std::error::Error>> {
23/// // Create auth client
24/// let client = Client::new(None);
25/// let auth_client = AuthClient::new(client);
26///
27/// // Configure client settings and create login client
28/// let settings = ClientSettings {
29///     identity_url: "https://identity.bitwarden.com".to_string(),
30///     api_url: "https://api.bitwarden.com".to_string(),
31///     user_agent: "MyApp/1.0".to_string(),
32///     device_type: DeviceType::SDK,
33///     device_identifier: None,
34///     bitwarden_client_version: None,
35///     bitwarden_package_type: None,
36/// };
37/// let login_client = auth_client.login(settings);
38///
39/// // Get user's KDF config
40/// let prelogin = login_client.get_password_prelogin(email.clone()).await?;
41///
42/// // Login with credentials
43/// let response = login_client.login_via_password(PasswordLoginRequest {
44///     login_request: LoginRequest {
45///         client_id: "connector".to_string(),
46///         device: LoginDeviceRequest {
47///             device_type: DeviceType::SDK,
48///             device_identifier: "device-id".to_string(),
49///             device_name: "My Device".to_string(),
50///             device_push_token: None,
51///         },
52///     },
53///     email,
54///     password,
55///     prelogin_response: prelogin,
56/// }).await?;
57///
58/// // Use tokens from response for authenticated requests
59/// match response {
60///     LoginResponse::Authenticated(success) => {
61///         let access_token = success.access_token;
62///         // Use access_token for authenticated requests
63///     }
64/// }
65/// # Ok(())
66/// # }
67/// ```
68#[cfg_attr(feature = "wasm", wasm_bindgen)]
69#[cfg_attr(feature = "uniffi", derive(uniffi::Object))]
70pub struct LoginClient {
71    pub(crate) client: Client,
72}
73
74impl LoginClient {
75    /// Creates a new `LoginClient` with the given client settings.
76    ///
77    /// # Note
78    ///
79    /// This method is `pub(crate)` because `LoginClient` instances should be obtained through
80    /// the AuthClient. Direct instantiation is internal to the crate.
81    pub(crate) fn new(settings: ClientSettings) -> Self {
82        let core_client = Client::new(Some(settings));
83
84        Self {
85            client: core_client,
86        }
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn test_login_client_creation() {
96        let client_settings = ClientSettings::default();
97        let login_client = LoginClient::new(client_settings);
98
99        // Verify the internal client exists (type check)
100        let _client = &login_client.client;
101        // The fact that this compiles and doesn't panic means the client was created successfully
102    }
103}