pub mod api;
pub mod api_client;
pub mod auth;
pub mod cli;
pub mod management;
pub mod settlement;
use std::sync::Arc;
use anyhow::{Context, Result};
use bitrouter_providers::hosted::account::credentials::default_credentials_path;
use bitrouter_providers::hosted::account::manager::CredentialManager;
use bitrouter_providers::hosted::applier::{BitrouterAuthApplier, PROVIDER_ID};
use bitrouter_sdk::config::{Config, ProviderConfig};
use bitrouter_sdk::language_model::auth::AuthAppliers;
use bitrouter_telemetry::otel::TelemetryBearer;
const FIRST_PARTY_TELEMETRY_ORIGIN: &str = "https://telemetry.bitrouter.ai";
const DEFAULT_ACCOUNT_ORIGIN: &str = "https://api.bitrouter.ai";
pub fn enable_in_zero_config(config: &mut Config) {
let Ok(path) = default_credentials_path() else {
return;
};
enable_in_zero_config_with_path(config, &path);
}
fn enable_in_zero_config_with_path(config: &mut Config, credentials_path: &std::path::Path) {
if config.providers.contains_key(PROVIDER_ID) {
return;
}
if !credentials_path.exists() {
return;
}
config.providers.insert(
PROVIDER_ID.to_string(),
ProviderConfig {
auto_discover: true,
..ProviderConfig::default()
},
);
}
pub fn default_manager() -> Result<Arc<CredentialManager>> {
let path = default_credentials_path().context("resolving BitRouter Cloud credentials path")?;
let manager = CredentialManager::new(path)
.map_err(|error| anyhow::anyhow!("building BitRouter Cloud credential manager: {error}"))?;
Ok(Arc::new(manager))
}
#[derive(Clone)]
pub(crate) struct StandaloneCloudCredentials {
manager: Option<Arc<CredentialManager>>,
}
impl StandaloneCloudCredentials {
pub(crate) fn new() -> Self {
Self {
manager: default_manager().ok(),
}
}
#[cfg(test)]
pub(crate) fn with_manager(manager: Arc<CredentialManager>) -> Self {
Self {
manager: Some(manager),
}
}
pub(crate) async fn routing_fallback(&self, target_base_url: &str) -> Option<String> {
let manager = self.manager.as_ref()?.clone();
cloud_bearer_for_base_url_with_manager(manager, target_base_url).await
}
pub(crate) async fn telemetry_bearer(
&self,
endpoint: &str,
) -> Option<Arc<dyn TelemetryBearer>> {
let manager = self.manager.as_ref()?.clone();
cloud_bearer_source(manager, endpoint).await
}
}
pub fn register_if_configured(
config: &Config,
appliers: &mut AuthAppliers,
manager: Arc<CredentialManager>,
) -> Result<()> {
if !config.providers.contains_key(PROVIDER_ID) {
return Ok(());
}
appliers.register(PROVIDER_ID, Arc::new(BitrouterAuthApplier::new(manager)));
Ok(())
}
pub struct CloudBearer {
manager: Arc<CredentialManager>,
expected_origin: String,
}
impl std::fmt::Debug for CloudBearer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CloudBearer")
.field("manager", &"<redacted>")
.field("expected_origin", &self.expected_origin)
.finish()
}
}
#[async_trait::async_trait]
impl TelemetryBearer for CloudBearer {
async fn bearer(&self) -> Option<String> {
self.manager
.resolve_bearer(None, Some(&self.expected_origin))
.await
.map(|credential| credential.secret().to_owned())
.ok()
}
}
pub async fn cloud_bearer_source(
manager: Arc<CredentialManager>,
expected_origin: impl Into<String>,
) -> Option<Arc<dyn TelemetryBearer>> {
manager.current().await.ok()??;
let expected_origin = credential_origin_for_exporter(&expected_origin.into());
Some(Arc::new(CloudBearer {
manager,
expected_origin,
}))
}
fn credential_origin_for_exporter(exporter: &str) -> String {
let exporter_origin = reqwest::Url::parse(exporter)
.ok()
.map(|url| url.origin().ascii_serialization());
match exporter_origin.as_deref() {
Some(FIRST_PARTY_TELEMETRY_ORIGIN) => DEFAULT_ACCOUNT_ORIGIN.to_owned(),
_ => exporter.to_owned(),
}
}
pub async fn cloud_bearer_for_base_url(target_base_url: &str) -> Option<String> {
let manager = default_manager().ok()?;
cloud_bearer_for_base_url_with_manager(manager, target_base_url).await
}
pub async fn cloud_bearer_for_base_url_with_manager(
manager: Arc<CredentialManager>,
target_base_url: &str,
) -> Option<String> {
manager
.resolve_bearer(None, Some(target_base_url))
.await
.map(|credential| credential.secret().to_owned())
.ok()
}
pub async fn cloud_api_key_for_base_url(target_base_url: &str) -> Option<String> {
let manager = default_manager().ok()?;
manager
.resolve_api_key(None, Some(target_base_url))
.await
.map(|credential| credential.secret().to_owned())
.ok()
}
#[cfg(test)]
mod tests {
use super::*;
use bitrouter_providers::hosted::account::credentials::{Credentials, StoredCredential};
use bitrouter_providers::hosted::account::manager::CredentialManager;
use bitrouter_providers::hosted::applier::BitrouterAuthApplier;
use bitrouter_sdk::language_model::AuthApplier;
use bitrouter_sdk::language_model::types::{ApiProtocol, RoutingTarget};
use chrono::{Duration, Utc};
use serde_json::json;
use wiremock::matchers::{body_string_contains, method, path as wm_path};
use wiremock::{Mock, MockServer, ResponseTemplate};
fn fresh_tmp_creds_path(
label: &str,
) -> anyhow::Result<(tempfile::TempDir, std::path::PathBuf)> {
let directory = tempfile::Builder::new()
.prefix(&format!("bitrouter-cloud-glue-{label}-"))
.tempdir()?;
let path = directory.path().join("account-credentials.json");
Ok((directory, path))
}
fn target_for_origin(origin: &str) -> RoutingTarget {
RoutingTarget {
provider_name: bitrouter_providers::hosted::applier::PROVIDER_ID.to_owned(),
service_id: "gpt-4o".to_owned(),
api_base: origin.to_owned(),
api_key: String::new(),
api_protocol: ApiProtocol::ChatCompletions,
chat_token_limit_field: None,
chat_supports_store: None,
chat_supports_stream_options: None,
reasoning_effort: None,
account_label: None,
api_key_override: None,
api_base_override: None,
auth_scheme: Default::default(),
}
}
#[tokio::test]
async fn shared_manager_single_flights_oauth_refresh_for_auth_and_telemetry()
-> anyhow::Result<()> {
let server = MockServer::start().await;
let origin = server.uri();
Mock::given(method("GET"))
.and(wm_path("/.well-known/oauth-authorization-server"))
.respond_with(ResponseTemplate::new(200).set_body_json(json!({
"issuer": origin,
"device_authorization_endpoint": format!("{origin}/oauth/device_authorization"),
"token_endpoint": format!("{origin}/oauth/token"),
})))
.mount(&server)
.await;
Mock::given(method("POST"))
.and(wm_path("/oauth/token"))
.and(body_string_contains("grant_type=refresh_token"))
.respond_with(ResponseTemplate::new(200).set_body_json(json!({
"access_token": "rotated-access",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "rotated-refresh",
"scope": "inference:invoke",
})))
.mount(&server)
.await;
let (_directory, path) = fresh_tmp_creds_path("shared-refresh")?;
let manager = Arc::new(CredentialManager::with_client(
path.clone(),
reqwest::Client::new(),
));
manager
.save(
bitrouter_providers::hosted::account::credentials::StoredCredential::from(
bitrouter_providers::hosted::account::credentials::Credentials {
access_token: "stale-access".to_owned(),
refresh_token: Some("original-refresh".to_owned()),
expires_at: Utc::now() + Duration::seconds(10),
refresh_token_expires_at: None,
token_type: "Bearer".to_owned(),
scope: "inference:invoke".to_owned(),
client_id: "bitrouter-cli".to_owned(),
authorization_server: origin.clone(),
namespace_id: Some("ns-test".to_owned()),
subject: None,
},
),
)
.await?;
let applier = BitrouterAuthApplier::new(Arc::clone(&manager));
let telemetry = CloudBearer {
manager: Arc::clone(&manager),
expected_origin: origin.clone(),
};
let request = reqwest::Client::new().post(&origin).build()?;
let target = target_for_origin(&origin);
let (applied, bearer) = tokio::join!(applier.apply(request, &target), telemetry.bearer(),);
assert_eq!(
applied?.headers()[reqwest::header::AUTHORIZATION],
"Bearer rotated-access"
);
assert_eq!(bearer.as_deref(), Some("rotated-access"));
let current = manager
.current()
.await?
.ok_or_else(|| anyhow::anyhow!("rotated credential was not persisted"))?;
let oauth = current
.oauth()
.ok_or_else(|| anyhow::anyhow!("rotated credential is not OAuth"))?;
assert_eq!(oauth.refresh_token.as_deref(), Some("rotated-refresh"));
let refreshes = server
.received_requests()
.await
.ok_or_else(|| anyhow::anyhow!("wiremock did not record requests"))?
.into_iter()
.filter(|request| request.method == "POST")
.count();
assert_eq!(refreshes, 1);
Ok(())
}
#[test]
fn enable_in_zero_config_noop_when_no_credentials_file() -> anyhow::Result<()> {
let (_directory, path) = fresh_tmp_creds_path("noop")?;
let mut config = Config::default();
enable_in_zero_config_with_path(&mut config, &path);
assert!(!config.providers.contains_key(PROVIDER_ID));
Ok(())
}
#[test]
fn enable_in_zero_config_inserts_when_credentials_file_present() -> anyhow::Result<()> {
let (_directory, path) = fresh_tmp_creds_path("inserts")?;
std::fs::write(&path, "{}")?;
let mut config = Config::default();
enable_in_zero_config_with_path(&mut config, &path);
let provider = match config.providers.get(PROVIDER_ID) {
Some(provider) => provider,
None => anyhow::bail!("bitrouter provider was not auto-enabled"),
};
assert!(
provider.auto_discover,
"auto_discover should be true so /models populates the routable list"
);
Ok(())
}
#[test]
fn enable_in_zero_config_noop_when_already_configured() -> anyhow::Result<()> {
let (_directory, path) = fresh_tmp_creds_path("already")?;
std::fs::write(&path, "{}")?;
let mut config = Config::default();
config.providers.insert(
PROVIDER_ID.to_string(),
ProviderConfig {
api_base: "https://example.invalid".to_string(),
..ProviderConfig::default()
},
);
enable_in_zero_config_with_path(&mut config, &path);
let provider = match config.providers.get(PROVIDER_ID) {
Some(provider) => provider,
None => anyhow::bail!("configured bitrouter provider disappeared"),
};
assert_eq!(provider.api_base, "https://example.invalid");
Ok(())
}
#[tokio::test]
async fn cloud_bearer_source_none_when_not_signed_in() -> anyhow::Result<()> {
let (_directory, path) = fresh_tmp_creds_path("absent")?;
let manager = Arc::new(CredentialManager::with_client(path, reqwest::Client::new()));
assert!(
cloud_bearer_source(manager, "https://telemetry.bitrouter.ai")
.await
.is_none()
);
Ok(())
}
#[tokio::test]
async fn cloud_bearer_source_uses_custom_exporter_same_origin_api_key() -> anyhow::Result<()> {
let (_directory, path) = fresh_tmp_creds_path("api-key-bearer")?;
let manager = Arc::new(CredentialManager::with_client(path, reqwest::Client::new()));
manager
.save(StoredCredential::api_key(
"brk_telemetry.secret".to_owned(),
"https://collector.example".to_owned(),
))
.await?;
let source = match cloud_bearer_source(manager, "https://collector.example/v1/traces").await
{
Some(source) => source,
None => anyhow::bail!("stored API key did not produce a telemetry source"),
};
assert_eq!(
source.bearer().await.as_deref(),
Some("brk_telemetry.secret")
);
Ok(())
}
#[tokio::test]
async fn default_first_party_exporter_uses_default_account_credential() -> anyhow::Result<()> {
let (_directory, path) = fresh_tmp_creds_path("default-telemetry-origin")?;
let manager = Arc::new(CredentialManager::with_client(path, reqwest::Client::new()));
manager
.save(StoredCredential::api_key(
"brk_default-account.secret".to_owned(),
"https://api.bitrouter.ai".to_owned(),
))
.await?;
let source = match cloud_bearer_source(manager, "https://telemetry.bitrouter.ai/v1/traces")
.await
{
Some(source) => source,
None => anyhow::bail!("default account credential did not produce telemetry source"),
};
assert_eq!(
source.bearer().await.as_deref(),
Some("brk_default-account.secret")
);
Ok(())
}
#[tokio::test]
async fn custom_exporter_cannot_receive_default_account_credential() -> anyhow::Result<()> {
let (_directory, path) = fresh_tmp_creds_path("custom-telemetry-origin")?;
let manager = Arc::new(CredentialManager::with_client(path, reqwest::Client::new()));
manager
.save(StoredCredential::api_key(
"brk_default-account.secret".to_owned(),
"https://api.bitrouter.ai".to_owned(),
))
.await?;
let source = match cloud_bearer_source(manager, "https://collector.example/v1/traces").await
{
Some(source) => source,
None => anyhow::bail!("stored credential did not produce telemetry source"),
};
assert!(source.bearer().await.is_none());
Ok(())
}
#[tokio::test]
async fn cloud_gateway_bearer_is_scoped_to_the_login_origin() -> anyhow::Result<()> {
let (_directory, path) = fresh_tmp_creds_path("gateway-origin")?;
let manager = Arc::new(CredentialManager::with_client(path, reqwest::Client::new()));
manager
.save(StoredCredential::api_key(
"brk_gateway.secret".to_owned(),
"https://api.bitrouter.ai".to_owned(),
))
.await?;
assert_eq!(
cloud_bearer_for_base_url_with_manager(
Arc::clone(&manager),
"https://api.bitrouter.ai/v1/responses",
)
.await
.as_deref(),
Some("brk_gateway.secret")
);
assert!(
cloud_bearer_for_base_url_with_manager(manager, "https://api.bitrouter.ai.evil/v1")
.await
.is_none()
);
Ok(())
}
#[tokio::test]
async fn settlement_resolver_rejects_oauth_but_accepts_same_origin_api_key()
-> anyhow::Result<()> {
let (_oauth_directory, oauth_path) = fresh_tmp_creds_path("settlement-oauth")?;
let oauth = Arc::new(CredentialManager::with_client(
oauth_path,
reqwest::Client::new(),
));
oauth
.save(StoredCredential::from(Credentials {
access_token: "oauth-access-token".to_owned(),
refresh_token: Some("oauth-refresh-token".to_owned()),
expires_at: Utc::now() + Duration::minutes(10),
refresh_token_expires_at: None,
token_type: "Bearer".to_owned(),
scope: "inference:invoke".to_owned(),
client_id: "bitrouter-cli".to_owned(),
authorization_server: "https://api.bitrouter.ai".to_owned(),
namespace_id: Some("ns-test".to_owned()),
subject: None,
}))
.await?;
assert!(
oauth
.resolve_api_key(None, Some("https://api.bitrouter.ai"))
.await
.is_err()
);
let (_api_key_directory, api_key_path) = fresh_tmp_creds_path("settlement-api-key")?;
let api_key = Arc::new(CredentialManager::with_client(
api_key_path,
reqwest::Client::new(),
));
api_key
.save(StoredCredential::api_key(
"brk_gateway.secret".to_owned(),
"https://api.bitrouter.ai".to_owned(),
))
.await?;
let resolved = api_key
.resolve_api_key(None, Some("https://api.bitrouter.ai/v1"))
.await?;
assert_eq!(resolved.secret(), "brk_gateway.secret");
Ok(())
}
#[test]
fn cloud_bearer_debug_redacts_manager() -> anyhow::Result<()> {
let (_directory, path) = fresh_tmp_creds_path("dbg")?;
let manager = Arc::new(CredentialManager::with_client(path, reqwest::Client::new()));
let bearer = CloudBearer {
manager,
expected_origin: "https://telemetry.bitrouter.ai".to_owned(),
};
let rendered = format!("{bearer:?}");
assert!(rendered.contains("<redacted>"));
Ok(())
}
#[tokio::test]
async fn malformed_credentials_file_is_swallowed_as_anonymous() -> anyhow::Result<()> {
let (_directory, path) = fresh_tmp_creds_path("malformed")?;
std::fs::write(&path, "{ not valid json")?;
let manager = Arc::new(CredentialManager::with_client(path, reqwest::Client::new()));
assert!(
cloud_bearer_source(manager, "https://telemetry.bitrouter.ai")
.await
.is_none()
);
Ok(())
}
}