bitwarden_auth/login/models/
login_success_response.rs

1use std::fmt::Debug;
2
3use bitwarden_core::{key_management::MasterPasswordError, require};
4use bitwarden_policies::MasterPasswordPolicyResponse;
5
6use crate::login::{api::response::LoginSuccessApiResponse, models::UserDecryptionOptionsResponse};
7
8/// SDK response model for a successful login.
9/// This is the model that will be exposed to consuming applications.
10#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
11#[serde(rename_all = "camelCase")]
12#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
13#[cfg_attr(
14    feature = "wasm",
15    derive(tsify::Tsify),
16    tsify(into_wasm_abi, from_wasm_abi)
17)]
18pub struct LoginSuccessResponse {
19    /// The access token string.
20    pub access_token: String,
21
22    /// The duration in seconds until the token expires.
23    pub expires_in: u64,
24
25    /// The timestamp in milliseconds when the token expires.
26    /// We calculate this for more convenient token expiration handling.
27    pub expires_at: i64,
28
29    /// The scope of the access token.
30    /// OAuth 2.0 RFC reference: <https://datatracker.ietf.org/doc/html/rfc6749#section-3.3>
31    pub scope: String,
32
33    /// The type of the token.
34    /// This will be "Bearer" for send access tokens.
35    /// OAuth 2.0 RFC reference: <https://datatracker.ietf.org/doc/html/rfc6749#section-7.1>
36    pub token_type: String,
37
38    /// The optional refresh token string.
39    /// This token can be used to obtain new access tokens when the current one expires.
40    pub refresh_token: Option<String>,
41
42    /// The user key wrapped user private key.
43    /// Note: previously known as "private_key".
44    pub user_key_wrapped_user_private_key: Option<String>,
45
46    /// Two-factor authentication token for future requests.
47    pub two_factor_token: Option<String>,
48
49    /// Indicates whether an admin has reset the user's master password,
50    /// requiring them to set a new password upon next login.
51    pub force_password_reset: Option<bool>,
52
53    /// Indicates whether the user uses Key Connector and if the client should have a locally
54    /// configured Key Connector URL in their environment.
55    /// Note: This is currently only applicable for client_credential grant type logins and
56    /// is only expected to be relevant for the CLI
57    pub api_use_key_connector: Option<bool>,
58
59    /// The user's decryption options for unlocking their vault.
60    pub user_decryption_options: UserDecryptionOptionsResponse,
61
62    /// If the user is subject to an organization master password policy,
63    /// this field contains the requirements of that policy.
64    pub master_password_policy: Option<MasterPasswordPolicyResponse>,
65    // TODO: PM-30222 we can expose this once we have a trait to convert PrivateKeysResponseModel
66    // to WrappedAccountCryptographicState
67    // The user's account cryptographic keys (wrapped with the user key).
68    // pub wrapped_account_crypto_state: Option<WrappedAccountCryptographicState>,
69}
70
71impl TryFrom<LoginSuccessApiResponse> for LoginSuccessResponse {
72    type Error = MasterPasswordError;
73    fn try_from(response: LoginSuccessApiResponse) -> Result<Self, Self::Error> {
74        // We want to convert the expires_in from seconds to a millisecond timestamp to have a
75        // concrete time the token will expire. This makes it easier to build logic around a
76        // concrete time rather than a duration. We keep expires_in as well for backward
77        // compatibility and convenience.
78        let expires_at =
79            chrono::Utc::now().timestamp_millis() + (response.expires_in * 1000) as i64;
80
81        Ok(LoginSuccessResponse {
82            access_token: response.access_token,
83            expires_in: response.expires_in,
84            expires_at,
85            scope: response.scope,
86            token_type: response.token_type,
87            refresh_token: response.refresh_token,
88            user_key_wrapped_user_private_key: response.private_key,
89            two_factor_token: response.two_factor_token,
90            force_password_reset: response.force_password_reset,
91            api_use_key_connector: response.api_use_key_connector,
92            // User decryption options are required on successful login responses
93            user_decryption_options: require!(response.user_decryption_options).try_into()?,
94            master_password_policy: response.master_password_policy.map(|policy| policy.into()),
95            // TODO: PM-30222 - we can expose this once we have a trait to convert
96            // PrivateKeysResponseModel to WrappedAccountCryptographicState
97            // wrapped_account_crypto_state: response.account_keys.map(|keys| keys.into()),
98        })
99    }
100}