use crate::client::OpenIDClient;
use crate::errors::{OpenIdError, Res};
use crate::primitives::OpenIDTokenResponse;
use crate::utils::time_utils::time;
use std::time::Duration;
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct TokenRefresher {
pub token: OpenIDTokenResponse,
expires_at: u64,
}
impl TokenRefresher {
pub fn from_token(token: OpenIDTokenResponse) -> Option<Self> {
Some(Self {
expires_at: time() + token.expires_in?,
token,
})
}
pub fn should_refresh(&self) -> bool {
self.should_refresh_if_expire_before(Duration::from_secs(
self.token.expires_in.unwrap_or(15 * 60) / 4,
))
}
pub fn should_refresh_if_expire_before(&self, duration: Duration) -> bool {
if self.token.refresh_token.is_none() {
return false;
}
self.expires_at - duration.as_secs() < time()
}
pub fn is_expired(&self) -> bool {
self.expires_at <= time()
}
pub async fn refresh(&mut self, client: &OpenIDClient) -> Res<()> {
let Some(refresh_token) = &self.token.refresh_token else {
return Err(OpenIdError::MissingRefreshToken);
};
let (token, _) = client
.request_token_from_refresh_token(refresh_token)
.await?;
self.token.access_token = token.access_token;
self.token.token_type = token.token_type;
self.expires_at = time() + token.expires_in.unwrap_or(3600);
self.token.expires_in = token.expires_in;
if let Some(new) = token.refresh_token {
self.token.refresh_token = Some(new);
}
if let Some(new) = token.id_token {
self.token.id_token = Some(new);
}
Ok(())
}
}