From f98a1d12ccad27846ac4a18346f0e9df06fb3955 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 24 Jun 2026 12:33:39 -0700 Subject: [PATCH] =?UTF-8?q?feat(ai-gateway):=20KeyAuthenticator=20trait=20?= =?UTF-8?q?=E2=80=94=20the=20auth=20swap=20seam?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crates/ai-gateway/src/auth/client/mod.rs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 litellm-rust/crates/ai-gateway/src/auth/client/mod.rs diff --git a/litellm-rust/crates/ai-gateway/src/auth/client/mod.rs b/litellm-rust/crates/ai-gateway/src/auth/client/mod.rs new file mode 100644 index 00000000000..fdd754b1c5c --- /dev/null +++ b/litellm-rust/crates/ai-gateway/src/auth/client/mod.rs @@ -0,0 +1,28 @@ +//! The auth **swap seam**. +//! +//! [`KeyAuthenticator`] is the single trait the extractor depends on. v0 ships +//! [`python::PythonAuthClient`], which delegates verification to the Python proxy +//! over HTTP. A later phase can implement `KeyAuthenticator` natively in Rust (DB +//! lookup, budget checks, etc.) and swap it in at startup — no route, extractor, +//! or state-shape change required, because everything depends on the trait object, +//! not the concrete client. + +pub mod python; + +use crate::auth::UserApiKeyAuth; + +/// Why a key verification failed. `Unauthorized` maps to a `401` for the caller; +/// `Upstream` carries a sanitized backend-error detail (also surfaced as `401` by +/// the extractor so an unreachable backend never silently lets a request through). +#[derive(Debug)] +pub enum AuthError { + Unauthorized, + Upstream(String), +} + +/// Resolves a raw API key into a [`UserApiKeyAuth`]. The one interface auth +/// backends implement; see the module docs for the swap rationale. +#[axum::async_trait] +pub trait KeyAuthenticator: Send + Sync { + async fn verify(&self, key: &str) -> Result; +}