use async_trait::async_trait;
use cratefield_core::{Auth, AuthError, Caller, Subject};
use http::HeaderMap;
use crate::jwks::AuthClient;
use crate::verify::token_fingerprint;
#[async_trait]
impl Auth for AuthClient {
async fn identify(&self, headers: &HeaderMap) -> Result<Caller, AuthError> {
let Some(presented) = headers.get(http::header::AUTHORIZATION) else {
return Ok(Caller::Anonymous);
};
let Some(token) = bearer(presented) else {
tracing::info!("rejected an Authorization header that is not a bearer token");
return Err(AuthError::NotVerified);
};
match self.verify(token).await {
Ok(claims) => Ok(Caller::Subject(
Subject::new(claims.sub).session(claims.sid).email(
claims
.email
.filter(|_| claims.email_verified.unwrap_or(false)),
),
)),
Err(err) => {
tracing::info!(
reason = %err,
token = %token_fingerprint(token),
"rejected a bearer token"
);
Err(AuthError::NotVerified)
}
}
}
}
fn bearer(presented: &http::HeaderValue) -> Option<&str> {
let value = presented.to_str().ok()?;
let rest = value
.strip_prefix("Bearer ")
.or_else(|| value.strip_prefix("bearer "))?;
(!rest.is_empty()).then_some(rest)
}