middle 0.2.0

Client Authorization Middleware for APIs secured via OAuth2 or Bearer Tokens. Tonic & reqwest integration. Based on the `oauth2` crate.
Documentation
mod bearer_token;
#[cfg(feature = "client-credentials")]
mod client_credentials;

use std::sync::Arc;

pub use bearer_token::*;
#[cfg(feature = "client-credentials")]
pub use client_credentials::*;
use http::HeaderValue;

/// Main trait of this crate.
pub trait Authorizer {
    /// Returns the authorization header to used for requests.
    ///
    /// # Errors
    /// Fails if a token is not available, for example because the refresh failed.
    fn authorization_header(&self) -> Result<Arc<HeaderValue>, crate::error::Error>;

    #[cfg(feature = "tonic")]
    /// Returns the authorization header to used for requests.
    ///
    /// # Errors
    /// - Fails if `Self::authorization_header()` fails.
    /// - Fails if the header value is not ASCII
    fn authorization_header_tonic(
        &self,
    ) -> Result<tonic::metadata::MetadataValue<tonic::metadata::Ascii>, tonic::Status> {
        use std::str::FromStr;

        let header = self
            .authorization_header()
            .map_err(|e| tonic::Status::unauthenticated(e.to_string()))?;
        let header_str = header.to_str().map_err(|e| {
            tonic::Status::unauthenticated(format!(
                "{}: {e}",
                crate::error::Error::InvalidHeaderValue {}
            ))
        })?;

        tonic::metadata::MetadataValue::from_str(header_str).map_err(|e| {
            tonic::Status::unauthenticated(format!(
                "{}: {e}",
                crate::error::Error::InvalidHeaderValue {}
            ))
        })
    }

    #[cfg(feature = "runtime-tokio")]
    /// Returns the background task that was launched to refresh the token.
    /// Returns `None` if the authorizer does not need to refresh the token.
    fn refresh_task(&self) -> Option<Arc<tokio::task::JoinHandle<()>>>;
}

/// Helper function to ensure that a string is ASCII.
///
/// # Errors
/// Fails with `InvalidHeaderValue` if the string is not ASCII.
pub(crate) fn require_ascii(s: &str) -> Result<(), crate::error::Error> {
    if s.is_ascii() {
        Ok(())
    } else {
        Err(crate::error::Error::InvalidHeaderValue)
    }
}