use crate::core::{
platform::{Duration, SystemTime},
secrets::SecretString,
};
use http::HeaderValue;
use http::header::InvalidHeaderValue;
#[derive(Debug, Clone)]
pub enum AccessToken {
Dpop(DpopAccessToken),
Bearer(BearerAccessToken),
}
impl AccessToken {
#[must_use]
pub fn token(&self) -> &SecretString {
match self {
AccessToken::Dpop(token) => &token.token,
AccessToken::Bearer(token) => &token.token,
}
}
pub fn expose_header_value(&self) -> Result<HeaderValue, InvalidHeaderValue> {
match self {
AccessToken::Dpop(dpop_access_token) => dpop_access_token.expose_header_value(),
AccessToken::Bearer(bearer_access_token) => bearer_access_token.expose_header_value(),
}
}
#[must_use]
pub fn dpop_jkt(&self) -> Option<&str> {
match self {
AccessToken::Dpop(token) => Some(token.jkt.as_str()),
AccessToken::Bearer(_) => None,
}
}
#[must_use]
pub fn token_type(&self) -> &str {
match self {
AccessToken::Dpop(_) => "DPoP",
AccessToken::Bearer(_) => "Bearer",
}
}
#[must_use]
pub fn effective_expiry(
&self,
default_expires_in: Duration,
expires_margin: Duration,
) -> SystemTime {
match self {
AccessToken::Dpop(dpop_access_token) => {
dpop_access_token.effective_expiry(default_expires_in, expires_margin)
}
AccessToken::Bearer(bearer_access_token) => {
bearer_access_token.effective_expiry(default_expires_in, expires_margin)
}
}
}
#[must_use]
pub fn is_expired(&self, default_expires_in: Duration, expires_margin: Duration) -> bool {
SystemTime::now() >= self.effective_expiry(default_expires_in, expires_margin)
}
}
#[derive(Debug, Clone)]
pub struct DpopAccessToken {
token: SecretString,
jkt: String,
received_at: SystemTime,
expires_in: Option<Duration>,
}
impl DpopAccessToken {
#[must_use]
pub fn new(
token: SecretString,
jkt: String,
received_at: SystemTime,
expires_in: Option<Duration>,
) -> Self {
Self {
token,
jkt,
received_at,
expires_in,
}
}
#[must_use]
pub fn jkt(&self) -> &str {
&self.jkt
}
#[must_use]
pub fn token(&self) -> &SecretString {
&self.token
}
pub fn expose_header_value(&self) -> Result<HeaderValue, InvalidHeaderValue> {
HeaderValue::from_str(&format!("DPoP {}", self.token.expose_secret()))
}
#[must_use]
pub fn effective_expiry(
&self,
default_expires_in: Duration,
expires_margin: Duration,
) -> SystemTime {
let expires_in = self.expires_in.unwrap_or(default_expires_in);
self.received_at + expires_in - expires_margin
}
#[must_use]
pub fn is_expired(&self, default_expires_in: Duration, expires_margin: Duration) -> bool {
SystemTime::now() >= self.effective_expiry(default_expires_in, expires_margin)
}
}
#[derive(Debug, Clone)]
pub struct BearerAccessToken {
token: SecretString,
received_at: SystemTime,
expires_in: Option<Duration>,
}
impl BearerAccessToken {
#[must_use]
pub fn new(token: SecretString, received_at: SystemTime, expires_in: Option<Duration>) -> Self {
Self {
token,
received_at,
expires_in,
}
}
#[must_use]
pub fn expose_token(&self) -> &str {
self.token.expose_secret()
}
pub fn expose_header_value(&self) -> Result<HeaderValue, InvalidHeaderValue> {
HeaderValue::from_str(&format!("Bearer {}", self.token.expose_secret()))
}
#[must_use]
pub fn effective_expiry(
&self,
default_expires_in: Duration,
expires_margin: Duration,
) -> SystemTime {
let expires_in = self.expires_in.unwrap_or(default_expires_in);
self.received_at + expires_in - expires_margin
}
#[must_use]
pub fn is_expired(&self, default_expires_in: Duration, expires_margin: Duration) -> bool {
SystemTime::now() >= self.effective_expiry(default_expires_in, expires_margin)
}
}