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);