micromegas_auth/
default_provider.rs

1//! Default authentication provider initialization for Micromegas services.
2//!
3//! This module provides the standard way to initialize authentication with both
4//! API key and OIDC providers from environment variables.
5
6use crate::api_key::{ApiKeyAuthProvider, parse_key_ring};
7use crate::multi::MultiAuthProvider;
8use crate::oidc::{OidcAuthProvider, OidcConfig};
9use crate::types::AuthProvider;
10use micromegas_tracing::info;
11use std::sync::Arc;
12
13/// Initializes the default authentication provider with API key and OIDC from environment.
14///
15/// Reads configuration from:
16/// - `MICROMEGAS_API_KEYS`: JSON array of API keys
17/// - `MICROMEGAS_OIDC_CONFIG`: OIDC configuration JSON
18/// - `MICROMEGAS_ADMINS`: JSON array of admin user emails/subjects
19///
20/// Returns `Ok(Some(...))` if at least one provider is configured.
21/// Returns `Ok(None)` if no providers are configured (auth disabled).
22/// Returns `Err` on configuration errors.
23///
24/// # Example
25///
26/// ```rust,no_run
27/// use micromegas_auth::default_provider::provider;
28///
29/// # async fn example() -> anyhow::Result<()> {
30/// let auth_provider = provider().await?;
31/// if let Some(provider) = auth_provider {
32///     println!("Authentication enabled");
33/// } else {
34///     println!("No authentication configured");
35/// }
36/// # Ok(())
37/// # }
38/// ```
39pub async fn provider() -> anyhow::Result<Option<Arc<dyn AuthProvider>>> {
40    provider_with_prefix("").await
41}
42
43/// Initializes auth providers using env vars scoped to a prefix.
44///
45/// For prefix `"MICROMEGAS_INGESTION"`:
46/// - API keys: tries `MICROMEGAS_INGESTION_API_KEYS`, falls back to `MICROMEGAS_API_KEYS`
47/// - OIDC:     tries `MICROMEGAS_INGESTION_OIDC_CONFIG`, falls back to `MICROMEGAS_OIDC_CONFIG`
48/// - Admins:   tries `MICROMEGAS_INGESTION_ADMINS`, falls back to `MICROMEGAS_ADMINS`
49///
50/// With an empty prefix the behaviour is identical to [`provider`].
51pub async fn provider_with_prefix(prefix: &str) -> anyhow::Result<Option<Arc<dyn AuthProvider>>> {
52    // Resolve API keys var with fallback
53    let api_keys_json = if prefix.is_empty() {
54        std::env::var("MICROMEGAS_API_KEYS").ok()
55    } else {
56        std::env::var(format!("{prefix}_API_KEYS"))
57            .or_else(|_| std::env::var("MICROMEGAS_API_KEYS"))
58            .ok()
59    };
60
61    // Resolve OIDC config var with fallback
62    let oidc_config_var: String = if prefix.is_empty() {
63        "MICROMEGAS_OIDC_CONFIG".to_string()
64    } else if std::env::var(format!("{prefix}_OIDC_CONFIG")).is_ok() {
65        format!("{prefix}_OIDC_CONFIG")
66    } else {
67        "MICROMEGAS_OIDC_CONFIG".to_string()
68    };
69
70    // Resolve admin users var with fallback
71    let admin_var: String = if prefix.is_empty() {
72        "MICROMEGAS_ADMINS".to_string()
73    } else {
74        let prefixed = format!("{prefix}_ADMINS");
75        if std::env::var(&prefixed).is_ok() {
76            prefixed
77        } else {
78            "MICROMEGAS_ADMINS".to_string()
79        }
80    };
81
82    // Initialize API key provider if configured
83    let api_key_provider = if let Some(keys_json) = api_keys_json {
84        let keyring = parse_key_ring(&keys_json)?;
85        info!("API key authentication enabled");
86        Some(Arc::new(ApiKeyAuthProvider::new(keyring)) as Arc<dyn AuthProvider>)
87    } else {
88        info!("API key auth not configured");
89        None
90    };
91
92    // Initialize OIDC provider if configured
93    let oidc_provider = match OidcConfig::from_env_var(&oidc_config_var) {
94        Ok(config) => {
95            info!("Initializing OIDC authentication");
96            Some(Arc::new(OidcAuthProvider::new(config, &admin_var).await?) as Arc<dyn AuthProvider>)
97        }
98        Err(e) => {
99            info!("OIDC not configured ({e}) - OIDC auth disabled");
100            None
101        }
102    };
103
104    // Build multi-provider from available providers
105    let mut multi = MultiAuthProvider::new();
106    if let Some(p) = api_key_provider {
107        multi = multi.with_provider(p);
108    }
109    if let Some(p) = oidc_provider {
110        multi = multi.with_provider(p);
111    }
112
113    // Return None if no providers configured
114    if multi.is_empty() {
115        return Ok(None);
116    }
117
118    Ok(Some(Arc::new(multi) as Arc<dyn AuthProvider>))
119}