bitwarden_core/auth/
renew.rs1use chrono::Utc;
2
3use super::login::LoginError;
4#[cfg(feature = "secrets")]
5use crate::{
6 auth::api::request::AccessTokenRequest,
7 client::ServiceAccountLoginMethod,
8 key_management::SymmetricKeyId,
9 secrets_manager::state::{self, ClientState},
10};
11use crate::{
12 auth::api::{request::ApiTokenRequest, response::IdentityTokenResponse},
13 client::{internal::InternalClient, LoginMethod, UserLoginMethod},
14 NotAuthenticatedError,
15};
16
17pub(crate) async fn renew_token(client: &InternalClient) -> Result<(), LoginError> {
18 const TOKEN_RENEW_MARGIN_SECONDS: i64 = 5 * 60;
19
20 let tokens = client
21 .tokens
22 .read()
23 .expect("RwLock is not poisoned")
24 .clone();
25 let login_method = client
26 .login_method
27 .read()
28 .expect("RwLock is not poisoned")
29 .clone();
30
31 if let (Some(expires), Some(login_method)) = (tokens.expires_on, login_method) {
32 if Utc::now().timestamp() < expires - TOKEN_RENEW_MARGIN_SECONDS {
33 return Ok(());
34 }
35
36 let config = client
37 .__api_configurations
38 .read()
39 .expect("RwLock is not poisoned")
40 .clone();
41
42 let res = match login_method.as_ref() {
43 LoginMethod::User(u) => match u {
44 UserLoginMethod::Username { client_id, .. } => {
45 let refresh = tokens.refresh_token.ok_or(NotAuthenticatedError)?;
46
47 crate::auth::api::request::RenewTokenRequest::new(refresh, client_id.to_owned())
48 .send(&config)
49 .await?
50 }
51 UserLoginMethod::ApiKey {
52 client_id,
53 client_secret,
54 ..
55 } => {
56 ApiTokenRequest::new(client_id, client_secret)
57 .send(&config)
58 .await?
59 }
60 },
61 #[cfg(feature = "secrets")]
62 LoginMethod::ServiceAccount(s) => match s {
63 ServiceAccountLoginMethod::AccessToken {
64 access_token,
65 state_file,
66 ..
67 } => {
68 let result = AccessTokenRequest::new(
69 access_token.access_token_id,
70 &access_token.client_secret,
71 )
72 .send(&config)
73 .await?;
74
75 if let (IdentityTokenResponse::Payload(r), Some(state_file)) =
76 (&result, state_file)
77 {
78 let key_store = client.get_key_store();
79 let ctx = key_store.context();
80 #[allow(deprecated)]
81 if let Ok(enc_key) = ctx.dangerous_get_symmetric_key(SymmetricKeyId::User) {
82 let state =
83 ClientState::new(r.access_token.clone(), enc_key.to_base64());
84 _ = state::set(state_file, access_token, state);
85 }
86 }
87
88 result
89 }
90 },
91 };
92
93 match res {
94 IdentityTokenResponse::Refreshed(r) => {
95 client.set_tokens(r.access_token, r.refresh_token, r.expires_in);
96 return Ok(());
97 }
98 IdentityTokenResponse::Authenticated(r) => {
99 client.set_tokens(r.access_token, r.refresh_token, r.expires_in);
100 return Ok(());
101 }
102 IdentityTokenResponse::Payload(r) => {
103 client.set_tokens(r.access_token, r.refresh_token, r.expires_in);
104 return Ok(());
105 }
106 _ => {
107 return Err(LoginError::InvalidResponse);
109 }
110 }
111 }
112
113 Err(NotAuthenticatedError)?
114}