use async_trait::async_trait;
use bytes::Bytes;
use crate::error::Error;
use crate::http::header::AUTHORIZATION;
use crate::http::{HeaderValue, Request};
use crate::types::SensitiveString;
#[async_trait]
pub trait TokenProvider: Send + Sync {
async fn access_token(&self) -> Result<String, Error>;
async fn refresh(&self) -> bool {
false
}
}
#[derive(Debug, Clone)]
pub struct StaticTokenProvider {
pub token: SensitiveString,
}
impl StaticTokenProvider {
pub fn new(token: impl Into<SensitiveString>) -> StaticTokenProvider {
StaticTokenProvider {
token: token.into(),
}
}
}
#[async_trait]
impl TokenProvider for StaticTokenProvider {
async fn access_token(&self) -> Result<String, Error> {
if self.token.is_empty() {
Err(Error::auth("no token configured"))
} else {
Ok(self.token.expose().to_string())
}
}
}
#[async_trait]
pub trait AuthStrategy: Send + Sync {
async fn authenticate(&self, request: &mut Request<Bytes>) -> Result<(), Error>;
async fn refresh(&self) -> bool {
false
}
}
pub struct BearerAuth<P: TokenProvider> {
provider: P,
}
impl<P: TokenProvider> BearerAuth<P> {
pub fn new(provider: P) -> BearerAuth<P> {
BearerAuth { provider }
}
}
#[async_trait]
impl<P: TokenProvider> AuthStrategy for BearerAuth<P> {
async fn authenticate(&self, request: &mut Request<Bytes>) -> Result<(), Error> {
let token = self.provider.access_token().await?;
let value = HeaderValue::from_str(&format!("Bearer {token}"))
.map_err(|_| Error::auth("access token is not a valid header value"))?;
request.headers_mut().insert(AUTHORIZATION, value);
Ok(())
}
async fn refresh(&self) -> bool {
self.provider.refresh().await
}
}