Codex Handbook
codex-api/src/auth.rs 86 lines
use codex_client::Request;use codex_client::TransportError;use http::HeaderMap;use std::future::Future;use std::pin::Pin;use std::sync::Arc;/// Error returned while applying authentication to an outbound request.#[derive(Debug, thiserror::Error)]pub enum AuthError {    #[error("request auth build error: {0}")]    Build(String),    #[error("transient auth error: {0}")]    Transient(String),}impl From<AuthError> for TransportError {    fn from(error: AuthError) -> Self {        match error {            AuthError::Build(message) => TransportError::Build(message),            AuthError::Transient(message) => TransportError::Network(message),        }    }}/// Applies authentication to API requests.////// Header-only providers can implement `add_auth_headers`; providers that sign/// complete requests can override `apply_auth`.pub trait AuthProvider: Send + Sync {    /// Adds any auth headers that are available without request body access.    ///    /// Implementations should be cheap and non-blocking. This method is also    /// used by telemetry and non-HTTP request paths.    fn add_auth_headers(&self, headers: &mut HeaderMap);    /// Returns any auth headers that are available without request body access.    fn to_auth_headers(&self) -> HeaderMap {        let mut headers = HeaderMap::new();        self.add_auth_headers(&mut headers);        headers    }    /// Applies auth to a complete outbound request and returns the request to send.    ///    /// The input `request` is moved into this method. Implementations may mutate    /// the owned request, or replace it entirely, before returning.    ///    /// Header-only auth providers can rely on the default implementation.    /// Request-signing providers can override this to inspect the final URL,    /// headers, and body bytes before the transport sends the request.    ///    /// Callers must always use the returned request as authoritative.    /// If this returns [`AuthError`], the request should not be sent.    fn apply_auth(&self, request: Request) -> AuthProviderFuture<'_> {        Box::pin(async move {            let mut request = request;            self.add_auth_headers(&mut request.headers);            Ok(request)        })    }}pub type AuthProviderFuture<'a> =    Pin<Box<dyn Future<Output = Result<Request, AuthError>> + Send + 'a>>;/// Shared auth handle passed through API clients.pub type SharedAuthProvider = Arc<dyn AuthProvider>;#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]pub struct AuthHeaderTelemetry {    pub attached: bool,    pub name: Option<&'static str>,}pub fn auth_header_telemetry(auth: &dyn AuthProvider) -> AuthHeaderTelemetry {    let mut headers = HeaderMap::new();    auth.add_auth_headers(&mut headers);    let name = headers        .contains_key(http::header::AUTHORIZATION)        .then_some("authorization");    AuthHeaderTelemetry {        attached: name.is_some(),        name,    }}