use crate::{Claims, JwtSecret}; use http::{header::AUTHORIZATION, HeaderValue}; use std::{ task::{Context, Poll}, time::{Duration, SystemTime, UNIX_EPOCH}, }; use tower::{Layer, Service}; /// A layer that adds a new JWT token to every request using `AuthClientService`. #[derive(Debug)] pub struct AuthClientLayer { secret: JwtSecret, } impl AuthClientLayer { /// Create a new `AuthClientLayer` with the given `secret`. pub const fn new(secret: JwtSecret) -> Self { Self { secret } } } impl Layer for AuthClientLayer { type Service = AuthClientService; fn layer(&self, inner: S) -> Self::Service { AuthClientService::new(self.secret, inner) } } /// Automatically authenticates every client request with the given `secret`. #[derive(Debug, Clone)] pub struct AuthClientService { secret: JwtSecret, inner: S, } impl AuthClientService { const fn new(secret: JwtSecret, inner: S) -> Self { Self { secret, inner } } } impl Service> for AuthClientService where S: Service>, { type Response = S::Response; type Error = S::Error; type Future = S::Future; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { self.inner.poll_ready(cx) } fn call(&mut self, mut request: http::Request) -> Self::Future { request.headers_mut().insert(AUTHORIZATION, secret_to_bearer_header(&self.secret)); self.inner.call(request) } } /// Helper function to convert a secret into a Bearer auth header value with claims according to /// . /// The token is valid for 60 seconds. pub fn secret_to_bearer_header(secret: &JwtSecret) -> HeaderValue { format!( "Bearer {}", secret .encode(&Claims { iat: (SystemTime::now().duration_since(UNIX_EPOCH).unwrap() + Duration::from_secs(60)) .as_secs(), exp: None, }) .unwrap() ) .parse() .unwrap() }