bitwarden_auth/send_access/
access_token_response.rs

1use std::fmt::Debug;
2
3use crate::send_access::api::{SendAccessTokenApiErrorResponse, SendAccessTokenApiSuccessResponse};
4
5/// A send access token which can be used to access a send.
6#[derive(serde::Serialize, serde::Deserialize, Clone)]
7#[serde(rename_all = "camelCase", deny_unknown_fields)]
8#[cfg_attr(
9    feature = "wasm",
10    derive(tsify::Tsify),
11    tsify(into_wasm_abi, from_wasm_abi)
12)]
13#[derive(Debug)]
14pub struct SendAccessTokenResponse {
15    /// The actual token string.
16    pub token: String,
17    /// The timestamp in milliseconds when the token expires.
18    pub expires_at: i64,
19}
20
21impl From<SendAccessTokenApiSuccessResponse> for SendAccessTokenResponse {
22    fn from(response: SendAccessTokenApiSuccessResponse) -> Self {
23        // We want to convert the expires_in from seconds to a millisecond timestamp to have a
24        // concrete time the token will expire as it is easier to build logic around a
25        // concrete time rather than a duration.
26        let expires_at =
27            chrono::Utc::now().timestamp_millis() + (response.expires_in * 1000) as i64;
28
29        SendAccessTokenResponse {
30            token: response.access_token,
31            expires_at,
32        }
33    }
34}
35
36// We're using the full variant of the bitwarden-error macro because we want to keep the contents of
37// SendAccessTokenApiErrorResponse
38#[bitwarden_error::bitwarden_error(full)]
39#[derive(Debug, thiserror::Error)]
40#[serde(tag = "kind", content = "data", rename_all = "lowercase")]
41/// Represents errors that can occur when requesting a send access token.
42/// It includes expected and unexpected API errors.
43pub enum SendAccessTokenError {
44    #[error("Unexpected Error response: {0:?}")]
45    /// Represents an unexpected error that occurred during the request.
46    /// This would typically be a transport-level error, such as network issues or serialization
47    /// problems.
48    Unexpected(UnexpectedIdentityError),
49
50    #[error("Expected error response")]
51    /// Represents an expected error response from the API.
52    Expected(SendAccessTokenApiErrorResponse),
53}
54
55// This is just a utility function so that the ? operator works correctly without manual mapping
56impl From<reqwest::Error> for SendAccessTokenError {
57    fn from(value: reqwest::Error) -> Self {
58        Self::Unexpected(UnexpectedIdentityError(format!("{value:?}")))
59    }
60}
61
62/// Any unexpected error that occurs when making requests to identity. This could be
63/// local/transport/decoding failure from the HTTP client (DNS/TLS/connect/read timeout,
64/// connection reset, or JSON decode failure on a success response) or non-2xx response with an
65/// unexpected body or status. Used when decoding the server's error payload into
66/// `SendAccessTokenApiErrorResponse` fails, or for 5xx responses where no structured error is
67/// available.
68#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
69#[serde(transparent)]
70#[cfg_attr(
71    feature = "wasm",
72    derive(tsify::Tsify),
73    tsify(into_wasm_abi, from_wasm_abi)
74)]
75pub struct UnexpectedIdentityError(pub String);