use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JwtClaims {
pub sub: String,
pub iss: String,
pub aud: Option<String>,
pub exp: i64,
pub iat: Option<i64>,
pub email: Option<String>,
pub name: Option<String>,
pub preferred_username: Option<String>,
#[serde(flatten)]
pub extra: HashMap<String, Value>,
}
impl Default for JwtClaims {
fn default() -> Self {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs() as i64;
Self {
sub: "anonymous".to_string(),
iss: "unknown".to_string(),
aud: None,
exp: now + 3600, iat: Some(now),
email: None,
name: None,
preferred_username: None,
extra: HashMap::new(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OidcDiscoveryDocument {
pub issuer: String,
pub jwks_uri: String,
pub authorization_endpoint: Option<String>,
pub token_endpoint: Option<String>,
pub userinfo_endpoint: Option<String>,
pub end_session_endpoint: Option<String>,
}
#[derive(Clone)]
pub struct CachedJwks {
pub keys: HashMap<String, (jsonwebtoken::DecodingKey, jsonwebtoken::Algorithm)>,
pub fetched_at: SystemTime,
pub cache_duration: Duration,
}
#[derive(Clone)]
pub struct CachedDiscoveryRaw {
pub raw_json: String,
pub fetched_at: SystemTime,
pub cache_duration: Duration,
}
#[derive(Debug, Clone, Default)]
pub struct JwtValidationOptions {
pub skip_issuer_validation: bool,
pub skip_audience_validation: bool,
pub expected_audience: Option<String>,
}
#[derive(Debug, Clone)]
pub struct OidcClientConfig {
pub issuer_url: String,
pub client_id: String,
pub client_secret: Option<String>,
pub redirect_uri: String,
pub scope: String,
pub code_challenge_method: String,
}
#[derive(Debug, Clone)]
pub struct ResourceServerConfig {
pub issuer_url: String,
pub client_id: String,
pub validation_options: JwtValidationOptions,
}
#[derive(Debug, Clone, Default)]
pub struct DevConfig {
pub local_dev_mode: bool,
pub local_dev_email: Option<String>,
pub local_dev_name: Option<String>,
pub local_dev_username: Option<String>,
}
impl DevConfig {
pub fn enabled() -> Self {
Self {
local_dev_mode: true,
local_dev_email: Some("dev@localhost".to_string()),
local_dev_name: Some("Dev User".to_string()),
local_dev_username: Some("dev".to_string()),
}
}
pub fn create_dev_claims(&self) -> JwtClaims {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs() as i64;
JwtClaims {
sub: self
.local_dev_username
.clone()
.unwrap_or_else(|| "dev-user".to_string()),
iss: "dev".to_string(),
aud: Some("development".to_string()),
exp: now + 86400, iat: Some(now),
email: self.local_dev_email.clone(),
name: self.local_dev_name.clone(),
preferred_username: self.local_dev_username.clone(),
extra: HashMap::new(),
}
}
pub fn is_enabled(&self) -> bool {
self.local_dev_mode
}
}