Backbone Auth

Enterprise-Grade Authentication & Authorization System for the Backbone Framework
Production-ready security with JWT, password hashing, Role-Based Access Control (RBAC), and comprehensive threat protection.
🚀 Overview
Backbone Auth is a complete authentication and authorization system designed for modern Rust applications. It provides enterprise-grade security features including multi-factor authentication, device fingerprinting, rate limiting, and comprehensive audit logging while maintaining developer-friendly APIs.
🎯 Key Features
- 🔐 Enterprise Security: Multi-layered authentication with JWT, Argon2 password hashing, and 2FA support
- 🛡️ Threat Protection: Rate limiting, device fingerprinting, IP tracking, and brute force prevention
- 🔑 Flexible Authorization: Advanced RBAC with wildcards, hierarchical permissions, and dynamic role management
- 📊 Security Monitoring: Comprehensive audit trails, security alerts, and risk scoring
- ⚡ High Performance: Async/await throughout for scalable, high-concurrency applications
- 🔧 Production Ready: Database integration patterns, configuration management, and deployment guides
🏗️ Architecture
┌─────────────────────────────────────────────────────────────┐
│ BACKBONE AUTH SYSTEM │
├─────────────────────────────────────────────────────────────┤
│ 🌐 Web Layer │
│ ├─ HTTP/gRPC Endpoints │
│ ├─ Middleware (CORS, Security Headers) │
│ └─ Request/Response Validation │
├─────────────────────────────────────────────────────────────┤
│ 🔐 Authentication Layer │
│ ├─ AuthService (JWT, Password Hashing) │
│ ├─ Enhanced Authentication (Security Context) │
│ ├─ Token Management (Access + Refresh Tokens) │
│ └─ Session Management │
├─────────────────────────────────────────────────────────────┤
│ 🛡️ Security Layer │
│ ├─ Rate Limiting & Brute Force Protection │
│ ├─ Device Fingerprinting & IP Tracking │
│ ├─ Threat Detection & Risk Scoring │
│ ├─ Security Monitoring & Alerts │
│ └─ Audit Logging & Compliance │
├─────────────────────────────────────────────────────────────┤
│ 🔑 Authorization Layer (RBAC) │
│ ├─ Role Management (Dynamic, Hierarchical) │
│ ├─ Permission System (Granular, Wildcards) │
│ ├─ User-Role Assignment │
│ └─ Access Control Evaluation │
├─────────────────────────────────────────────────────────────┤
│ 💾 Data Layer │
│ ├─ UserRepository (PostgreSQL, MongoDB) │
│ ├─ SecurityService (Redis, Rate Limiting) │
│ ├─ Configuration Management │
│ └─ Caching & Session Storage │
└─────────────────────────────────────────────────────────────┘
🚀 Quick Start
Basic Usage
use backbone_auth::*;
use uuid::Uuid;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let auth_config = AuthServiceConfig {
jwt_secret: std::env::var("JWT_SECRET")?,
token_expiry_hours: 24,
};
let auth_service = AuthService::new(auth_config);
let auth_result = auth_service.authenticate("user@example.com", "secure_password").await?;
println!("✅ User authenticated: {}", auth_result.user_id);
if let Some(token) = auth_result.token {
let validation = auth_service.validate_token(&token).await?;
if validation.valid {
println!("✅ Token valid for user: {}", validation.user_id.unwrap());
}
}
let mut permission_service = PermissionService::new();
permission_service.assign_role(&auth_result.user_id.to_string(), "admin")?;
let has_access = permission_service.has_permission(
&auth_result.user_id.to_string(),
"admin:users"
)?;
println!("🔑 Admin access: {}", has_access);
Ok(())
}
Production-Ready Authentication
use backbone_auth::*;
async fn production_login(
auth_service: &AuthService,
user_repository: &dyn UserRepository,
security_service: &dyn SecurityService,
) -> Result<AuthResultEnhanced> {
let auth_request = AuthRequest {
email: "user@company.com".to_string(),
password: "SecureP@ssw0rd123!".to_string(),
remember_me: Some(true),
device_info: Some(DeviceInfo {
device_id: Some("device_12345".to_string()),
device_type: "web".to_string(),
platform: Some("macos".to_string()),
user_agent: Some("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)".to_string()),
fingerprint: None,
}),
ip_address: Some("192.168.1.100".to_string()),
user_agent: Some("Mozilla/5.0...".to_string()),
};
let result = auth_service.authenticate_enhanced(
auth_request,
user_repository,
security_service
).await?;
println!("🔐 Authenticated user: {}", result.user_id);
println!("🔑 Access token: {}", &result.token[..20]);
println!("⚠️ 2FA Required: {}", result.requires_2fa);
println!("🛡️ Security flags: {:?}", result.security_flags);
Ok(result)
}
🔐 Authentication
Service Configuration
let config = AuthServiceConfig {
jwt_secret: "dev_secret_change_in_production".to_string(),
token_expiry_hours: 24,
};
let config = AuthServiceConfig {
jwt_secret: std::env::var("JWT_SECRET")?, token_expiry_hours: 1, };
let auth_service = AuthService::new(config);
Enhanced Authentication Flow
The enhanced authentication provides comprehensive security:
async fn authenticate_with_security(
auth_service: &AuthService,
request: AuthRequest,
) -> Result<AuthResultEnhanced> {
auth_service.authenticate_enhanced(
request,
&user_repository, &security_service ).await
}
Token Management
let access_token = auth_service.generate_token(&user_id).await?;
let auth_result = auth_service.authenticate_enhanced(request, &user_repo, &security_service).await?;
println!("Access Token: {}", auth_result.token);
println!("Refresh Token: {:?}", auth_result.refresh_token);
let validation = auth_service.validate_token(&token).await?;
if validation.valid {
println!("Token valid for user: {}", validation.user_id.unwrap());
} else {
println!("Token invalid or expired");
}
Password Security
use argon2::{Argon2, PasswordHash, PasswordHasher, password_hash::{SaltString, rand_core::OsRng}};
fn hash_password(password: &str) -> Result<String> {
let salt = SaltString::generate(&mut OsRng);
let argon2 = Argon2::default();
let password_hash = argon2.hash_password(password.as_bytes(), &salt)?;
Ok(password_hash.to_string())
}
let is_valid = auth_service.verify_password(
"user_password",
"$argon2id$v=19$m=65536,t=3,p=4$..."
)?;
🔑 Authorization (RBAC)
Permission System Architecture
The permission system supports multiple access control patterns:
"resource:action" "resource:*" "*:action" "*:*"
Role Management
let mut permission_service = PermissionService::new();
let developer_role = Role {
name: "developer".to_string(),
description: "Full development access".to_string(),
permissions: vec![
Permission {
name: "code:read".to_string(),
description: "Read source code".to_string(),
resource: "code".to_string(),
action: "read".to_string(),
},
Permission {
name: "code:write".to_string(),
description: "Write and commit code".to_string(),
resource: "code".to_string(),
action: "write".to_string(),
},
Permission {
name: "deploy:*".to_string(),
description: "Deploy applications".to_string(),
resource: "deploy".to_string(),
action: "*".to_string(),
},
],
};
permission_service.add_role(developer_role)?;
let user_id = "user_12345";
permission_service.assign_role(user_id, "developer")?;
permission_service.assign_role(user_id, "user")?;
Permission Checking
let can_read_code = permission_service.has_permission(user_id, "code:read")?;
let can_deploy = permission_service.has_permission(user_id, "deploy:production")?;
let admin_access = permission_service.has_permission(user_id, "admin:*")?;
let user_permissions = permission_service.get_user_permissions(user_id)?;
for permission in user_permissions {
println!("🔑 {} - {}", permission.name, permission.description);
}
let is_admin = permission_service.has_role(user_id, "admin")?;
let is_developer = permission_service.has_role(user_id, "developer")?;
let roles = permission_service.get_user_roles(user_id);
println!("👤 User roles: {:?}", roles);
Hierarchical Permissions
let team_lead_role = Role {
name: "team_lead".to_string(),
description: "Team lead with extended permissions".to_string(),
permissions: vec![
Permission {
name: "team:read".to_string(),
resource: "team".to_string(),
action: "read".to_string(),
description: "View team members".to_string(),
},
Permission {
name: "team:write".to_string(),
resource: "team".to_string(),
action: "write".to_string(),
description: "Manage team members".to_string(),
},
Permission {
name: "user:*".to_string(),
resource: "user".to_string(),
action: "*".to_string(),
description: "Full user management".to_string(),
},
Permission {
name: "project:*".to_string(),
resource: "project".to_string(),
action: "read".to_string(),
description: "Read all projects".to_string(),
},
],
};
🛡️ Security Features
Rate Limiting & Brute Force Protection
use async_trait::async_trait;
use redis::Client;
struct RedisSecurityService {
redis: Client,
}
#[async_trait]
impl SecurityService for RedisSecurityService {
async fn check_rate_limit(&self, email: &str, ip_address: Option<&str>) -> Result<()> {
let key = format!("auth_rate_limit:{}", email);
let attempts: i32 = self.redis.get(&key).await.unwrap_or(0);
if attempts >= 5 {
return Err(anyhow::anyhow!("Too many authentication attempts"));
}
self.redis.incr(&key).await?;
self.redis.expire(&key, 900).await?;
Ok(())
}
async fn log_failed_auth_attempt(&self, user_id: &Uuid, ip_address: Option<&str>) -> Result<()> {
tracing::warn!(
user_id = %user_id,
ip_address = %ip_address.unwrap_or("unknown"),
"Failed authentication attempt"
);
Ok(())
}
async fn analyze_login_attempt(
&self,
user_id: &Uuid,
device_info: &Option<DeviceInfo>,
ip_address: Option<&str>
) -> Result<SecurityFlags> {
let mut flags = SecurityFlags::default();
if let Some(device) = device_info {
flags.new_device = self.is_new_device(user_id, device).await?;
}
if let Some(ip) = ip_address {
flags.new_location = self.is_new_location(user_id, ip).await?;
}
flags.risk_score = self.calculate_risk_score(&flags).await?;
Ok(flags)
}
}
Device Fingerprinting
fn generate_device_fingerprint(user_agent: &str, ip: &str) -> String {
use sha2::{Sha256, Digest};
let mut hasher = Sha256::new();
hasher.update(user_agent.as_bytes());
hasher.update(ip.as_bytes());
format!("{:x}", hasher.finalize())
}
let device_info = DeviceInfo {
device_id: Some(generate_device_fingerprint(&user_agent, &ip_address)),
device_type: detect_device_type(&user_agent),
platform: detect_platform(&user_agent),
user_agent: Some(user_agent.to_string()),
fingerprint: Some(generate_browser_fingerprint(&user_agent)),
};
Security Monitoring
tracing::info!(
user_id = %user_id,
ip_address = %request.ip_address,
device_type = %request.device_info.as_ref().map(|d| &d.device_type).unwrap_or("unknown"),
risk_score = %result.security_flags.risk_score,
"User authentication completed"
);
tracing::warn!(
user_id = %user_id,
ip_address = %request.ip_address,
reason = "new_device_detected",
risk_score = %result.security_flags.risk_score,
"Security alert: New device login"
);
tracing::error!(
user_id = %user_id,
ip_address = %request.ip_address,
reason = "multiple_failed_attempts",
"Security threat detected"
);
🏗️ Database Integration
PostgreSQL Implementation
use sqlx::PgPool;
use async_trait::async_trait;
struct PostgresUserRepository {
pool: PgPool,
}
#[async_trait]
impl UserRepository for PostgresUserRepository {
async fn find_by_email(&self, email: &str) -> Result<Option<User>> {
let user = sqlx::query_as!(
User,
r#"
SELECT
id, email, password_hash, is_active, is_locked, roles,
two_factor_enabled, two_factor_methods, account_expires_at,
requires_password_change, last_login_at, failed_login_attempts,
locked_until, created_at, updated_at
FROM users
WHERE email = $1 AND deleted_at IS NULL
"#,
email
)
.fetch_optional(&self.pool)
.await?;
Ok(user)
}
async fn create(&self, user: &User) -> Result<User> {
let created_user = sqlx::query_as!(
User,
r#"
INSERT INTO users (
id, email, password_hash, is_active, is_locked, roles,
two_factor_enabled, two_factor_methods, account_expires_at,
requires_password_change, created_at, updated_at
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, NOW(), NOW())
RETURNING *
"#,
user.id,
user.email,
user.password_hash,
user.is_active,
user.is_locked,
&user.roles,
user.two_factor_enabled,
&user.two_factor_methods,
user.account_expires_at,
user.requires_password_change
)
.fetch_one(&self.pool)
.await?;
Ok(created_user)
}
async fn update_last_login(&self, user_id: &Uuid) -> Result<()> {
sqlx::query!(
"UPDATE users SET last_login_at = NOW() WHERE id = $1",
user_id
)
.execute(&self.pool)
.await?;
Ok(())
}
async fn increment_failed_attempts(&self, user_id: &Uuid) -> Result<()> {
sqlx::query!(
r#"
UPDATE users
SET failed_login_attempts = failed_login_attempts + 1,
updated_at = NOW()
WHERE id = $1
"#,
user_id
)
.execute(&self.pool)
.await?;
Ok(())
}
}
MongoDB Implementation
use mongodb::{Client, Collection};
use mongodb::bson::{doc, Document};
struct MongoUserRepository {
collection: Collection<User>,
}
#[async_trait]
impl UserRepository for MongoUserRepository {
async fn find_by_email(&self, email: &str) -> Result<Option<User>> {
let user = self.collection
.find_one(
doc! { "email": email, "deleted_at": null },
None
)
.await?;
Ok(user)
}
async fn create(&self, user: &User) -> Result<User> {
let user_clone = user.clone();
self.collection.insert_one(user_clone, None).await?;
Ok(user.clone())
}
}
Database Schema (PostgreSQL)
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
is_active BOOLEAN DEFAULT true,
is_locked BOOLEAN DEFAULT false,
roles JSONB DEFAULT '[]'::jsonb,
two_factor_enabled BOOLEAN DEFAULT false,
two_factor_methods JSONB DEFAULT '[]'::jsonb,
account_expires_at TIMESTAMP WITH TIME ZONE,
requires_password_change BOOLEAN DEFAULT false,
last_login_at TIMESTAMP WITH TIME ZONE,
failed_login_attempts INTEGER DEFAULT 0,
locked_until TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
deleted_at TIMESTAMP WITH TIME ZONE
);
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_active ON users(is_active) WHERE deleted_at IS NULL;
CREATE INDEX idx_users_last_login ON users(last_login_at) DESC;
CREATE TABLE auth_audit_log (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID,
email VARCHAR(255),
action VARCHAR(50) NOT NULL,
ip_address INET,
user_agent TEXT,
device_fingerprint VARCHAR(255),
success BOOLEAN NOT NULL,
failure_reason TEXT,
security_flags JSONB,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_auth_audit_user ON auth_audit_log(user_id);
CREATE INDEX idx_auth_audit_created ON auth_audit_log(created_at) DESC;
⚙️ Configuration
Environment Configuration
JWT_SECRET=your_super_secure_random_secret_at_least_32_characters
JWT_EXPIRY_HOURS=1
DATABASE_URL=postgresql://user:password@localhost:5432/backbone_auth
REDIS_URL=redis://localhost:6379
MAX_LOGIN_ATTEMPTS=5
LOGIN_ATTEMPT_WINDOW=900 SESSION_TIMEOUT=3600 ENABLE_2FA=true
ACCOUNT_LOCKOUT_DURATION=3600
SMTP_SERVER=smtp.gmail.com:587
SMTP_USER=noreply@yourapp.com
SMTP_PASS=your_smtp_password
Application Configuration (YAML)
auth:
jwt:
secret: "${JWT_SECRET}"
expiry_hours: 1
refresh_token_days: 30
password:
min_length: 8
max_length: 128
require_uppercase: true
require_lowercase: true
require_numbers: true
require_special_chars: true
security:
max_login_attempts: 5
attempt_window_seconds: 900
account_lockout_duration: 3600
enable_device_fingerprinting: true
enable_ip_tracking: true
risk_score_threshold: 0.7
two_factor:
enabled: true
methods: ["totp", "sms", "email"]
issuer: "YourApp"
sessions:
timeout_seconds: 3600
refresh_threshold_seconds: 300
database:
url: "${DATABASE_URL}"
max_connections: 20
connection_timeout: 30
redis:
url: "${REDIS_URL}"
pool_size: 10
Configuration Loading
use serde::Deserialize;
use config::{Config, ConfigError, Environment};
#[derive(Debug, Deserialize)]
struct AuthConfig {
jwt: JwtConfig,
password: PasswordConfig,
security: SecurityConfig,
two_factor: TwoFactorConfig,
database: DatabaseConfig,
redis: RedisConfig,
}
impl AuthConfig {
pub fn from_env() -> Result<Self, ConfigError> {
let config = Config::builder()
.add_source(config::File::with_name("config/auth"))
.add_source(Environment::with_prefix("auth"))
.build()?;
config.try_deserialize()
}
}
let config = AuthConfig::from_env()?;
let auth_service = AuthService::new(AuthServiceConfig {
jwt_secret: config.jwt.secret,
token_expiry_hours: config.jwt.expiry_hours,
});
🔧 Advanced Usage
Two-Factor Authentication
use totp_lite::{totp, Stepper};
struct TOTPSecurityService {
issuer: String,
}
impl TOTPSecurityService {
fn generate_secret(&self) -> String {
use rand::Rng;
let mut rng = rand::thread_rng();
(0..32)
.map(|_| rng.gen_range(0..10))
.map(|d| char::from_digit(d, 10).unwrap())
.collect()
}
fn generate_qr_code(&self, secret: &str, user_email: &str) -> Result<String> {
let uri = format!(
"otpauth://totp/{}:{}?secret={}&issuer={}",
urlencoding::encode(&self.issuer),
urlencoding::encode(user_email),
secret,
urlencoding::encode(&self.issuer)
);
Ok(uri)
}
fn verify_totp(&self, secret: &str, code: &str) -> Result<bool> {
let stepper = Stepper::new(30, 6);
let decoded_secret = base32::decode(base32::Alphabet::RFC4648 { padding: true }, secret)?;
let expected = totp(&stepper, &decoded_secret, std::time::SystemTime::now());
let code = u32::from_str_radix(code, 10)?;
Ok(expected == code)
}
}
Session Management
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
struct UserSession {
user_id: Uuid,
session_id: String,
device_fingerprint: String,
ip_address: String,
created_at: DateTime<Utc>,
expires_at: DateTime<Utc>,
last_activity: DateTime<Utc>,
is_active: bool,
}
struct SessionManager {
sessions: Arc<RwLock<HashMap<String, UserSession>>>,
}
impl SessionManager {
async fn create_session(&self, user_id: &Uuid, device_fingerprint: &str, ip_address: &str) -> Result<String> {
let session_id = Uuid::new_v4().to_string();
let now = Utc::now();
let expires_at = now + Duration::hours(1);
let session = UserSession {
user_id: *user_id,
session_id: session_id.clone(),
device_fingerprint: device_fingerprint.to_string(),
ip_address: ip_address.to_string(),
created_at: now,
expires_at,
last_activity: now,
is_active: true,
};
let mut sessions = self.sessions.write().await;
sessions.insert(session_id.clone(), session);
Ok(session_id)
}
async fn validate_session(&self, session_id: &str) -> Option<UserSession> {
let sessions = self.sessions.read().await;
if let Some(session) = sessions.get(session_id) {
if session.expires_at > Utc::now() && session.is_active {
return Some(session.clone());
}
}
None
}
async fn revoke_session(&self, session_id: &str) -> Result<()> {
let mut sessions = self.sessions.write().await;
if let Some(session) = sessions.get_mut(session_id) {
session.is_active = false;
}
Ok(())
}
}
API Integration Example
use axum::{extract::State, http::StatusCode, response::Json, Router};
use serde_json::json;
type AuthState = Arc<AppState>;
struct AppState {
auth_service: AuthService,
user_repository: Arc<dyn UserRepository>,
security_service: Arc<dyn SecurityService>,
permission_service: Arc<Mutex<PermissionService>>,
}
async fn login(
State(state): State<AuthState>,
Json(request): Json<LoginRequest>,
) -> Result<Json<LoginResponse>, StatusCode> {
let auth_request = AuthRequest {
email: request.email,
password: request.password,
remember_me: request.remember_me,
device_info: request.device_info,
ip_address: request.ip_address,
user_agent: request.user_agent,
};
match state.auth_service.authenticate_enhanced(
auth_request,
state.user_repository.as_ref(),
state.security_service.as_ref()
).await {
Ok(result) => Ok(Json(LoginResponse {
user_id: result.user_id,
token: result.token,
refresh_token: result.refresh_token,
expires_at: result.expires_at,
requires_2fa: result.requires_2fa,
security_flags: result.security_flags,
})),
Err(_) => Err(StatusCode::UNAUTHORIZED),
}
}
async fn protected_endpoint(
State(state): State<AuthState>,
auth: AuthMiddleware,
) -> Result<Json<Value>, StatusCode> {
let user_id = auth.user_id.to_string();
let has_permission = state.permission_service
.lock()
.await
.has_permission(&user_id, "admin:users")?;
if !has_permission {
return Err(StatusCode::FORBIDDEN);
}
Ok(Json(json!({
"message": "Access granted",
"user_id": auth.user_id
})))
}
let app = Router::new()
.route("/login", axum::routing::post(login))
.route("/protected", axum::routing::get(protected_endpoint))
.layer(axum::middleware::from_fn(auth_middleware));
🧪 Testing
Unit Tests
#[cfg(test)]
mod tests {
use super::*;
use tokio_test;
#[tokio::test]
async fn test_jwt_flow() -> Result<()> {
let auth_service = AuthService::with_secret("test_secret");
let user_id = Uuid::new_v4();
let token = auth_service.generate_token(&user_id).await?;
let validation = auth_service.validate_token(&token).await?;
assert!(validation.valid);
assert_eq!(validation.user_id.unwrap(), user_id);
Ok(())
}
#[tokio::test]
async fn test_permission_system() -> Result<()> {
let mut permission_service = PermissionService::new();
let user_id = "test_user";
permission_service.assign_role(user_id, "admin")?;
assert!(permission_service.has_permission(user_id, "admin:all")?);
assert!(permission_service.has_permission(user_id, "random:permission")?);
permission_service.remove_role(user_id, "admin")?;
assert!(!permission_service.has_permission(user_id, "admin:all")?);
Ok(())
}
#[test]
fn test_password_validation() {
let auth_service = AuthService::with_secret("test");
assert!(auth_service.is_valid_password_format("SecurePass123"));
assert!(auth_service.is_valid_password_format("MyP@ssw0rd!"));
assert!(!auth_service.is_valid_password_format("short"));
assert!(!auth_service.is_valid_password_format("nouppercase1"));
assert!(!auth_service.is_valid_password_format("NOLOWERCASE1"));
assert!(!auth_service.is_valid_password_format("NoNumbers!"));
}
#[test]
fn test_email_validation() {
let auth_service = AuthService::with_secret("test");
assert!(auth_service.is_valid_email("user@example.com"));
assert!(auth_service.is_valid_email("test.email+tag@domain.co.uk"));
assert!(!auth_service.is_valid_email("invalid-email"));
assert!(!auth_service.is_valid_email("@domain.com"));
assert!(!auth_service.is_valid_email("user@"));
}
}
Integration Tests
#[cfg(test)]
mod integration_tests {
use super::*;
use sqlx::PgPool;
async fn setup_test_db() -> PgPool {
dotenv::dotenv().ok();
let database_url = std::env::var("TEST_DATABASE_URL")
.unwrap_or_else(|_| "postgresql://localhost/backbone_auth_test".to_string());
let pool = PgPool::connect(&database_url).await.unwrap();
sqlx::migrate!("./migrations").run(&pool).await.unwrap();
pool
}
#[tokio::test]
async fn test_complete_auth_flow() -> Result<()> {
let pool = setup_test_db().await;
let user_repository = Arc::new(PostgresUserRepository::new(pool));
let security_service = Arc::new(MockSecurityService::new());
let auth_service = AuthService::new(AuthServiceConfig {
jwt_secret: "test_secret".to_string(),
token_expiry_hours: 1,
});
let user_id = Uuid::new_v4();
let user = User {
id: user_id,
email: "test@example.com".to_string(),
password_hash: hash_password("SecurePass123")?,
is_active: true,
is_locked: false,
roles: vec!["user".to_string()],
};
user_repository.create(&user).await?;
let auth_request = AuthRequest {
email: "test@example.com".to_string(),
password: "SecurePass123".to_string(),
remember_me: Some(false),
device_info: None,
ip_address: Some("127.0.0.1".to_string()),
user_agent: Some("test-agent".to_string()),
};
let result = auth_service.authenticate_enhanced(
auth_request,
user_repository.as_ref(),
security_service.as_ref()
).await?;
assert_eq!(result.user_id, user_id);
assert!(!result.token.is_empty());
assert!(!result.requires_2fa);
let validation = auth_service.validate_token(&result.token).await?;
assert!(validation.valid);
assert_eq!(validation.user_id.unwrap(), user_id);
Ok(())
}
}
📊 Performance & Security
Security Headers
use tower_http::{
cors::{Any, CorsLayer},
trace::TraceLayer,
};
let app = Router::new()
.layer(
CorsLayer::new()
.allow_origin(Any)
.allow_methods(Any)
.allow_headers(Any)
)
.layer(
tower_http::compression::CompressionLayer::new()
)
.layer(
tower_http::trace::TraceLayer::new_for_http()
)
.layer(axum::middleware::from_fn(security_headers_middleware));
async fn security_headers_middleware(
request: Request,
next: Next,
) -> Response {
let mut response = next.run(request).await;
let headers = response.headers_mut();
headers.insert("X-Content-Type-Options", "nosniff".parse().unwrap());
headers.insert("X-Frame-Options", "DENY".parse().unwrap());
headers.insert("X-XSS-Protection", "1; mode=block".parse().unwrap());
headers.insert(
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains".parse().unwrap()
);
headers.insert("Content-Security-Policy", "default-src 'self'".parse().unwrap());
response
}
Monitoring & Metrics
use prometheus::{Counter, Histogram, register_counter, register_histogram};
lazy_static! {
static ref AUTH_REQUESTS_TOTAL: Counter = register_counter!(
"auth_requests_total",
"Total number of authentication requests"
).unwrap();
static ref AUTH_DURATION: Histogram = register_histogram!(
"auth_request_duration_seconds",
"Authentication request duration in seconds"
).unwrap();
static ref AUTH_FAILURES_TOTAL: Counter = register_counter!(
"auth_failures_total",
"Total number of authentication failures"
).unwrap();
}
async fn authenticate_with_metrics(
auth_service: &AuthService,
request: AuthRequest,
) -> Result<AuthResultEnhanced> {
let timer = AUTH_DURATION.start_timer();
AUTH_REQUESTS_TOTAL.inc();
let result = auth_service.authenticate_enhanced(request, &user_repo, &security_service).await;
if result.is_err() {
AUTH_FAILURES_TOTAL.inc();
}
timer.observe_duration();
result
}
🚀 Deployment
Docker Configuration
# Dockerfile
FROM rust:1.75-slim as builder
WORKDIR /app
COPY Cargo.toml Cargo.lock ./
COPY src ./src
RUN cargo build --release
FROM debian:bookworm-slim
# Install runtime dependencies
RUN apt-get update && apt-get install -y \
ca-certificates \
libpq5 \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/backbone-auth /usr/local/bin/backbone-auth
EXPOSE 8080
ENV JWT_SECRET=your_production_secret_here
ENV DATABASE_URL=postgresql://user:password@db:5432/backbone_auth
ENV REDIS_URL=redis://redis:6379
CMD ["backbone-auth"]
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- JWT_SECRET=${JWT_SECRET}
- DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@db:5432/backbone_auth
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
db:
image: postgres:15
environment:
- POSTGRES_DB=backbone_auth
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
- ./migrations:/docker-entrypoint-initdb.d
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:
Kubernetes Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: backbone-auth
spec:
replicas: 3
selector:
matchLabels:
app: backbone-auth
template:
metadata:
labels:
app: backbone-auth
spec:
containers:
- name: backbone-auth
image: backbone-auth:latest
ports:
- containerPort: 8080
env:
- name: JWT_SECRET
valueFrom:
secretKeyRef:
name: auth-secrets
key: jwt-secret
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-credentials
key: url
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
📚 API Reference
For complete API documentation, see:
🤝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
git clone https://github.com/backbone-framework/backbone-auth.git
cd backbone-auth
cargo build
cargo test
cargo run --example basic_usage
cargo fmt --check
cargo clippy -- -D warnings
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🔗 Related Projects
Built with ❤️ by the Backbone Framework Team
For enterprise support, consulting, or custom development, please contact us at team@backbone.dev