pub mod bearer;
pub mod middleware;
pub mod oidc;
use serde::{Deserialize, Serialize};
use solo_core::TenantId;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(tag = "mode", rename_all = "snake_case")]
pub enum AuthConfig {
Bearer { token: String },
Oidc {
discovery_url: String,
audience: String,
#[serde(default = "default_tenant_claim_name")]
tenant_claim_name: String,
},
}
fn default_tenant_claim_name() -> String {
"solo_tenant".to_string()
}
impl Default for AuthConfig {
fn default() -> Self {
AuthConfig::Bearer {
token: String::new(),
}
}
}
impl From<solo_storage::AuthSettings> for AuthConfig {
fn from(s: solo_storage::AuthSettings) -> Self {
match s {
solo_storage::AuthSettings::Bearer { token } => AuthConfig::Bearer { token },
solo_storage::AuthSettings::Oidc {
discovery_url,
audience,
tenant_claim_name,
} => AuthConfig::Oidc {
discovery_url,
audience,
tenant_claim_name,
},
}
}
}
#[derive(Debug, Clone)]
pub struct AuthenticatedPrincipal {
pub subject: String,
pub tenant_claim: Option<TenantId>,
pub scopes: Vec<String>,
pub claims: serde_json::Value,
}
impl AuthenticatedPrincipal {
pub fn bearer(default_tenant: TenantId) -> Self {
Self {
subject: "bearer".to_string(),
tenant_claim: Some(default_tenant),
scopes: Vec::new(),
claims: serde_json::Value::Null,
}
}
}
#[derive(Debug, thiserror::Error)]
pub enum AuthError {
#[error("missing Authorization header")]
MissingAuthHeader,
#[error("malformed Authorization header (expected `Bearer <token>`)")]
MalformedAuthHeader,
#[error("invalid bearer token")]
InvalidBearer,
#[error("invalid OIDC token: {reason}")]
InvalidOidcToken { reason: String },
#[error("OIDC token missing tenant claim '{claim_name}'")]
MissingTenantClaim { claim_name: String },
#[error("OIDC token has invalid tenant_id: {0}")]
InvalidTenantClaim(#[from] solo_core::TenantIdError),
#[error("OIDC discovery error: {0}")]
Discovery(String),
#[error("JWKS error: {0}")]
Jwks(String),
}