oxify-authn
Security Kernel - Enterprise-Grade Authentication for OxiFY
Overview
oxify-authn is the authentication layer of OxiFY's Zero Trust Security architecture. It provides comprehensive authentication mechanisms designed for enterprise LLM platforms with strict security requirements.
Codename: The Gatekeeper
Status: ✅ ALL PHASES COMPLETE - Production Ready (v2.2)
Ported from: OxiRS - Battle-tested in production semantic web applications
Enterprise-Grade Security
Unlike basic authentication systems, oxify-authn provides a complete enterprise authentication suite:
- Multiple Auth Methods: JWT, OAuth2/OIDC, SAML 2.0, LDAP/AD, WebAuthn/FIDO2, Certificate-based (mTLS)
- Advanced Security: MFA/TOTP, session management, token revocation, rate limiting, password policies
- Risk-Based Auth: Location anomaly detection, device fingerprinting, impossible travel detection
- Token Rotation: Automatic refresh token rotation with family tracking and grace periods
- API Key Management: Scoped keys with rate limiting, expiration, and usage tracking
- Security Analytics: Real-time metrics, behavioral profiling, AI-powered anomaly detection
- IdP Integration: Azure AD, Okta, Auth0 with automatic OIDC discovery
- Performance: <1ms JWT validation, comprehensive benchmarks included
Features
Core Authentication (Phase 1) ✅
- JWT Authentication: HS256/HS384/HS512, RS256/RS384/RS512, ES256/ES384 support
- OAuth2/OIDC: Authorization Code Flow with PKCE (GitHub, Google, custom providers)
- Password Management: Argon2 hashing with configurable strength policies
- TOTP/MFA: RFC 6238 TOTP with backup codes and QR enrollment
Enterprise Features (Phase 2) ✅
- Session Management: Stateful sessions with multi-device support, IP/UA binding
- Token Revocation: Blacklist with automatic cleanup and revocation reasons
- Rate Limiting: Per-IP and per-user limits with exponential backoff
- Password Policies: NIST-compliant configurable requirements
- Audit Events: Comprehensive event tracking (login, MFA, tokens, OAuth, security)
- SAML 2.0: Service Provider with AuthnRequest, Response validation, metadata
- LDAP/AD: User authentication, attribute retrieval, group membership, connection pooling
- WebAuthn/FIDO2: Passwordless authentication with platform/cross-platform authenticators
Advanced Security (Phase 3) ✅
- Risk-Based Auth: Location anomaly, device fingerprinting, impossible travel detection
- Token Rotation: One-time use tokens, family tracking, sliding window expiration
- Login History: Pattern tracking for behavioral analysis
Integration Features (Phase 4) ✅
- API Key Management: Scoped keys with prefix, rate limits, IP whitelist, expiration
- Security Metrics: Authentication metrics, performance tracking, KPIs, time-series analysis
- Certificate Auth: X.509 validation, mTLS, chain validation, CRL/OCSP revocation
- IdP Support: Azure AD, Okta, Auth0 with OIDC discovery and multi-tenant
- AI Security: Statistical anomaly detection, behavioral profiling, threat intelligence
Quality & Performance (Phase 5) ✅
- Benchmarks: Comprehensive performance benchmarks using Criterion
- Examples: Integration examples for quick start
- Documentation: 15 doc tests, 154 unit tests, zero warnings policy
Installation
[dependencies]
oxify-authn = { path = "../crates/security/oxify-authn" }
oxify-authn = { path = "../crates/security/oxify-authn", features = ["jwt", "oauth", "password"] }
Feature Flags
| Feature |
Description |
Default |
jwt |
JWT token management |
✅ Yes |
oauth |
OAuth2/OIDC support |
✅ Yes |
password |
Password hashing (Argon2) |
✅ Yes |
mfa |
TOTP multi-factor auth |
❌ No |
session |
Stateful session management |
❌ No |
revocation |
Token revocation/blacklist |
❌ No |
ratelimit |
Rate limiting |
❌ No |
saml |
SAML 2.0 Service Provider |
❌ No |
ldap |
LDAP/AD integration |
❌ No |
webauthn |
WebAuthn/FIDO2 passwordless |
❌ No |
risk |
Risk-based authentication |
❌ No |
rotation |
Token rotation |
❌ No |
apikey |
API key management |
❌ No |
metrics |
Security metrics and analytics |
❌ No |
cert |
Certificate-based authentication |
❌ No |
idp |
Advanced IdP support (Azure AD, Okta, Auth0) |
❌ No |
ai |
AI-powered security (anomaly detection, behavioral profiling) |
❌ No |
Quick Start
JWT Authentication
use oxify_authn::{JwtManager, JwtConfig, User, Permission};
use chrono::Utc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = JwtConfig::development();
let jwt_manager = JwtManager::new(&config)?;
let user = User {
username: "alice".to_string(),
roles: vec!["admin".to_string()],
email: Some("alice@example.com".to_string()),
full_name: Some("Alice Smith".to_string()),
last_login: Some(Utc::now()),
permissions: vec![Permission::Read, Permission::Write],
};
let token = jwt_manager.generate_token(&user)?;
println!("Token: {}", token);
let validation = jwt_manager.validate_token(&token)?;
println!("User: {}", validation.user.username);
Ok(())
}
Password Hashing
use oxify_authn::{PasswordManager, PasswordStrength};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let password_manager = PasswordManager::new();
let strength = password_manager.check_password_strength("MyP@ssw0rd123!");
match strength {
PasswordStrength::VeryStrong => println!("Great password!"),
PasswordStrength::Strong => println!("Good password"),
_ => println!("Consider a stronger password"),
}
let hash = password_manager.hash_password("MyP@ssw0rd123!")?;
println!("Hash: {}", hash);
let is_valid = password_manager.verify_password("MyP@ssw0rd123!", &hash)?;
assert!(is_valid);
Ok(())
}
OAuth2 Authentication
use oxify_authn::{OAuth2Service, OAuth2Config};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = OAuth2Config::github(
"your-client-id",
"your-client-secret",
);
let oauth_service = OAuth2Service::new(config);
let redirect_uri = "http://localhost:3000/auth/callback";
let (auth_url, state) = oauth_service
.generate_authorization_url(redirect_uri, true)
.await?;
println!("Visit: {}", auth_url);
Ok(())
}
Core Components
JwtManager
Manages JWT token lifecycle.
pub struct JwtManager {
}
impl JwtManager {
pub fn new(config: &JwtConfig) -> Result<Self>;
pub fn generate_token(&self, user: &User) -> Result<String>;
pub fn validate_token(&self, token: &str) -> Result<TokenValidation>;
pub fn refresh_token(&self, token: &str) -> Result<String>;
pub fn extract_token_from_header(header: &str) -> Option<&str>;
}
Supported Algorithms: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384
PasswordManager
Handles password hashing and verification using Argon2.
pub struct PasswordManager {
}
impl PasswordManager {
pub fn new() -> Self;
pub fn hash_password(&self, password: &str) -> Result<String>;
pub fn verify_password(&self, password: &str, hash: &str) -> Result<bool>;
pub fn check_password_strength(&self, password: &str) -> PasswordStrength;
}
Password Strength Scoring:
- Length (8+, 12+, 16+ chars)
- Character diversity (uppercase, lowercase, digits, special)
- Returns: VeryWeak, Weak, Medium, Strong, VeryStrong
OAuth2Service
OAuth2 and OIDC client for third-party authentication.
pub struct OAuth2Service {
config: OAuth2Config,
}
impl OAuth2Service {
pub async fn generate_authorization_url(
&self,
redirect_uri: &str,
use_pkce: bool,
) -> Result<(String, String)>;
pub async fn exchange_code(
&self,
code: &str,
redirect_uri: &str,
) -> Result<TokenResponse>;
pub async fn refresh_access_token(
&self,
refresh_token: &str,
) -> Result<TokenResponse>;
pub async fn fetch_user_info(
&self,
access_token: &str,
) -> Result<serde_json::Value>;
}
Provider Presets:
OAuth2Config::github(client_id, client_secret)
OAuth2Config::google(client_id, client_secret)
OAuth2Config::custom(...) for any provider
Authentication Flow Examples
1. API Token Authentication
use axum::{
extract::State,
http::{Request, StatusCode},
middleware::Next,
response::Response,
};
use std::sync::Arc;
pub async fn auth_middleware(
State(jwt_manager): State<Arc<JwtManager>>,
mut request: Request<axum::body::Body>,
next: Next,
) -> Result<Response, StatusCode> {
let auth_header = request
.headers()
.get("Authorization")
.and_then(|h| h.to_str().ok())
.ok_or(StatusCode::UNAUTHORIZED)?;
let token = JwtManager::extract_token_from_header(auth_header)
.ok_or(StatusCode::UNAUTHORIZED)?;
let validation = jwt_manager
.validate_token(token)
.map_err(|_| StatusCode::UNAUTHORIZED)?;
request.extensions_mut().insert(validation.user);
Ok(next.run(request).await)
}
2. OAuth2 Login Flow
use axum::{
extract::{Query, State},
response::{IntoResponse, Redirect},
Json,
};
use serde::Deserialize;
use std::sync::Arc;
#[derive(Deserialize)]
struct CallbackQuery {
code: String,
state: String,
}
async fn oauth_login(
State(oauth_service): State<Arc<OAuth2Service>>,
) -> impl IntoResponse {
let (auth_url, state) = oauth_service
.generate_authorization_url("http://localhost:3000/auth/callback", true)
.await
.unwrap();
Redirect::to(&auth_url)
}
async fn oauth_callback(
State(oauth_service): State<Arc<OAuth2Service>>,
State(jwt_manager): State<Arc<JwtManager>>,
Query(params): Query<CallbackQuery>,
) -> Result<Json<serde_json::Value>, StatusCode> {
let tokens = oauth_service
.exchange_code(¶ms.code, "http://localhost:3000/auth/callback")
.await
.map_err(|_| StatusCode::UNAUTHORIZED)?;
let user_info = oauth_service
.fetch_user_info(&tokens.access_token)
.await
.map_err(|_| StatusCode::UNAUTHORIZED)?;
let user = User {
username: user_info["login"].as_str().unwrap().to_string(),
email: user_info["email"].as_str().map(String::from),
roles: vec!["user".to_string()],
permissions: vec![Permission::Read],
full_name: user_info["name"].as_str().map(String::from),
last_login: Some(chrono::Utc::now()),
};
let jwt = jwt_manager
.generate_token(&user)
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
Ok(Json(serde_json::json!({
"token": jwt,
"user": user,
})))
}
3. Password-Based Login
use axum::{extract::State, http::StatusCode, Json};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Deserialize)]
struct LoginRequest {
username: String,
password: String,
}
#[derive(Serialize)]
struct LoginResponse {
token: String,
user: User,
}
async fn login(
State(password_manager): State<Arc<PasswordManager>>,
State(jwt_manager): State<Arc<JwtManager>>,
Json(req): Json<LoginRequest>,
) -> Result<Json<LoginResponse>, StatusCode> {
let user = User {
username: req.username.clone(),
roles: vec!["user".to_string()],
email: Some(format!("{}@example.com", req.username)),
full_name: Some(req.username.clone()),
last_login: Some(chrono::Utc::now()),
permissions: vec![Permission::Read, Permission::Write],
};
let token = jwt_manager
.generate_token(&user)
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
Ok(Json(LoginResponse { token, user }))
}
4. SAML 2.0 Authentication
use oxify_authn::{ServiceProvider, SpConfigBuilder};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let sp_config = SpConfigBuilder::new(
"https://myapp.example.com/saml/metadata",
"https://myapp.example.com/saml/acs",
)
.entity_id("https://myapp.example.com")
.require_response_signature(true)
.require_assertion_signature(true)
.build()?;
let sp = ServiceProvider::new(sp_config);
let (authn_request, relay_state) = sp.generate_authn_request(
"https://idp.example.com/saml/sso",
None,
)?;
let redirect_url = sp.build_redirect_url(&authn_request, &relay_state)?;
println!("Redirect to: {}", redirect_url);
Ok(())
}
5. LDAP/Active Directory Authentication
use oxify_authn::{LdapAuthenticator, LdapConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = LdapConfig::builder()
.url("ldaps://ldap.example.com:636")
.base_dn("dc=example,dc=com")
.bind_dn("cn=admin,dc=example,dc=com")
.bind_password("admin_password")
.user_search_filter("(&(objectClass=person)(uid={username}))")
.add_user_attribute("mail")
.add_user_attribute("cn")
.add_user_attribute("uid")
.use_tls(true)
.timeout_seconds(30)
.max_connections(20) .build()?;
let ldap_auth = LdapAuthenticator::new(config);
let ldap_user = ldap_auth.authenticate("alice", "password123").await?;
println!("Authenticated: {} ({})", ldap_user.username, ldap_user.email);
let groups = ldap_auth.get_user_groups("alice").await?;
println!("Groups: {:?}", groups);
Ok(())
}
6. WebAuthn/FIDO2 Passwordless Authentication
use oxify_authn::{WebAuthnAuthenticator, WebAuthnConfigBuilder, InMemoryCredentialStore};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = WebAuthnConfigBuilder::new(
"example.com",
"https://example.com",
)
.user_verification_required(true)
.build()?;
let credential_store = InMemoryCredentialStore::new();
let webauthn = WebAuthnAuthenticator::new(config, credential_store);
let user_id = uuid::Uuid::new_v4();
let (registration_challenge, state) = webauthn.start_registration(
&user_id,
"alice",
"Alice Wonderland",
)?;
let (auth_challenge, state) = webauthn.start_authentication(&user_id)?;
Ok(())
}
7. Risk-Based Authentication
use oxify_authn::{RiskAnalyzer, RiskConfig, LoginContextBuilder, RiskLevel};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = RiskConfig::default();
let mut analyzer = RiskAnalyzer::new(config);
let context = LoginContextBuilder::new("alice")
.ip("203.0.113.45")
.user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64)")
.location("New York", "US", 40.7128, -74.0060)
.build();
let assessment = analyzer.analyze_login(&context)?;
match assessment.risk_level {
RiskLevel::High | RiskLevel::Critical => {
println!("High risk login! Require step-up authentication");
println!("Reasons: {:?}", assessment.reasons);
}
_ => {
println!("Normal risk level, proceed with login");
}
}
Ok(())
}
8. API Key Management
use oxify_authn::{ApiKeyManager, ApiKeyConfig, ApiKeyScope};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = ApiKeyConfig {
prefix: "sk_live_".to_string(),
default_expiration_secs: 86400 * 30, ..Default::default()
};
let mut manager = ApiKeyManager::new(config);
let generated = manager.generate_key(
"user123",
"Production API Key",
vec![ApiKeyScope::Read, ApiKeyScope::Write],
None, None, None, )?;
println!("API Key: {}", generated.key);
println!("Store this securely - it won't be shown again!");
let validation = manager.validate_key(&generated.key)?;
println!("User: {}, Scopes: {:?}", validation.user_id, validation.scopes);
Ok(())
}
9. Security Metrics and Analytics
use oxify_authn::{MetricsCollector, AuthEvent};
use chrono::Utc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut collector = MetricsCollector::new();
collector.record_event(AuthEvent::LoginSuccess {
user_id: "alice".to_string(),
ip: "192.0.2.1".to_string(),
});
collector.record_event(AuthEvent::LoginFailure {
username: "bob".to_string(),
ip: "192.0.2.2".to_string(),
reason: "Invalid password".to_string(),
});
let metrics = collector.get_metrics();
println!("Security Score: {}", metrics.security_score);
println!("Success Rate: {:.2}%", metrics.success_rate * 100.0);
println!("Total Logins: {}", metrics.total_logins);
println!("Failed Logins: {}", metrics.failed_logins);
let time_series = collector.get_time_series_data(3600)?; for point in time_series {
println!("{}: {} logins", point.timestamp, point.total_events);
}
Ok(())
}
Configuration
Development Config
let config = JwtConfig::development();
Production Config
use oxify_authn::{JwtConfig, Algorithm};
let config = JwtConfig {
algorithm: Algorithm::RS256,
secret: std::env::var("JWT_SECRET")?,
issuer: "oxify.io".to_string(),
audience: vec!["api.oxify.io".to_string()],
expiration_secs: 3600, };
Security Best Practices
- JWT Secrets: Use strong, random secrets in production (min 32 bytes for HS256)
- Token Expiration: Keep JWT expiration short (1-24 hours) and use refresh tokens
- HTTPS Only: Always use HTTPS in production for token transmission
- Password Policy: Enforce minimum strength requirements
- PKCE: Always use PKCE for OAuth2 public clients (SPAs, mobile apps)
- CSRF Protection: Validate OAuth2 state parameter to prevent CSRF attacks
- Rate Limiting: Implement rate limiting on authentication endpoints
- Audit Logging: Log all authentication events for security monitoring
Testing
Run the comprehensive test suite:
cd crates/security/oxify-authn
cargo test --all-features
cargo test --features "jwt,password"
cargo test --features "saml,ldap"
cargo test --features "webauthn,risk,ai"
cargo bench --all-features
cargo run --example simple_auth --all-features
Test Coverage:
- ✅ 156 unit tests (100% passing)
- ✅ 15 doc tests (100% passing)
- ✅ Zero warnings policy enforced
- ✅ Clippy clean
- ✅ All features tested with integration examples
Performance
Run benchmarks with cargo bench --all-features:
- JWT generation: <1ms (HS256), ~2ms (RS256)
- JWT validation: <1ms (HS256), ~1ms (RS256)
- Password hashing (Argon2): ~100ms (intentionally slow for security)
- Password verification: ~100ms
- Session creation: <1ms (in-memory)
- Session validation: <1ms (in-memory)
- Rate limiting check: <1µs (in-memory)
- API key validation: <1ms (SHA256 hash)
- Metrics collection: <10µs per event
- Risk analysis: ~1ms (with history)
- OAuth2 token exchange: 200-500ms (network dependent)
- SAML AuthnRequest generation: ~2ms
- LDAP authentication: 50-200ms (network dependent)
See benches/auth_benchmarks.rs for detailed benchmark suite.
Dependencies
Core dependencies:
jsonwebtoken - JWT encoding/decoding (HS256/RS256/ES256)
argon2 - Argon2id password hashing
oauth2 - OAuth2/OIDC client
reqwest - HTTP client for OAuth2 and IdP integration
chrono - Timestamp handling
serde / serde_json - Serialization
uuid - Unique identifier generation
Optional dependencies (by feature):
totp-rs - TOTP/MFA support (mfa)
quick-xml - SAML XML parsing (saml)
flate2 - SAML compression (saml)
ldap3 - LDAP/AD authentication (ldap)
webauthn-rs - WebAuthn/FIDO2 support (webauthn)
url - URL parsing for SAML and WebAuthn (saml, webauthn)
All dependencies are production-ready and actively maintained.
License
Apache-2.0
Attribution
Ported from OxiRS with permission. Original implementation by the OxiLabs team.