Skip to main content

light_openid/
token_refresher.rs

1use crate::client::OpenIDClient;
2use crate::errors::{OpenIdError, Res};
3use crate::primitives::OpenIDTokenResponse;
4use crate::utils::time_utils::time;
5use std::time::Duration;
6
7/// A structure that holds a token and helps with its automatic renewal
8#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
9pub struct TokenRefresher {
10    pub token: OpenIDTokenResponse,
11    expires_at: u64,
12}
13
14impl TokenRefresher {
15    /// Initialize a new token refresher, estimating that the token was issued now
16    pub fn from_token(token: OpenIDTokenResponse) -> Option<Self> {
17        Some(Self {
18            expires_at: time() + token.expires_in?,
19            token,
20        })
21    }
22
23    /// Check out whether this refresh token should be updated or not. Return true if token reached
24    /// 75% of its lifetime
25    pub fn should_refresh(&self) -> bool {
26        self.should_refresh_if_expire_before(Duration::from_secs(
27            self.token.expires_in.unwrap_or(15 * 60) / 4,
28        ))
29    }
30
31    /// Check out whether this refresh token should be updated or not, depending of its upcoming
32    /// expiration.
33    ///
34    /// If no refresh token was returned by IdP, return false
35    pub fn should_refresh_if_expire_before(&self, duration: Duration) -> bool {
36        if self.token.refresh_token.is_none() {
37            return false;
38        }
39
40        self.expires_at - duration.as_secs() < time()
41    }
42
43    /// Check out whether this refresh token is expired not
44    pub fn is_expired(&self) -> bool {
45        self.expires_at <= time()
46    }
47
48    /// Attempt to refresh this token.
49    pub async fn refresh(&mut self, client: &OpenIDClient) -> Res<()> {
50        let Some(refresh_token) = &self.token.refresh_token else {
51            return Err(OpenIdError::MissingRefreshToken);
52        };
53
54        let (token, _) = client
55            .request_token_from_refresh_token(refresh_token)
56            .await?;
57
58        // Update token information
59        self.token.access_token = token.access_token;
60        self.token.token_type = token.token_type;
61
62        self.expires_at = time() + token.expires_in.unwrap_or(3600);
63        self.token.expires_in = token.expires_in;
64
65        if let Some(new) = token.refresh_token {
66            self.token.refresh_token = Some(new);
67        }
68
69        if let Some(new) = token.id_token {
70            self.token.id_token = Some(new);
71        }
72
73        Ok(())
74    }
75}