This document outlines the security practices, built-in protections, and deployment guidance for axum-gate v2.0.0-dev.
| Version | Supported |
|---|---|
| 2.0.0-dev | ✅ |
| < 2.0.0-dev | ❌ |
Only the latest stable release and the most recent release candidate receive security updates.
- Algorithm: Uses Argon2id (latest variant) with cryptographically secure parameters
- Salting: Each password gets a unique, randomly generated salt using
OsRng - PHC string format: Stores Argon2id hashes in the standard PHC string format
- No Plaintext Storage: Only Argon2id hashes are persisted; plaintext secrets never touch disk
The crate provides three security presets:
| Preset | Memory (MiB) | Time Cost | Parallelism | Use Case |
|---|---|---|---|---|
HighSecurity |
64 | 3 | 1 | Production (default in release) |
Interactive |
32 | 2 | 1 | User-facing applications |
DevFast |
4 | 1 | 1 | Development only (debug builds) |
Default Behavior:
- Release builds:
HighSecuritypreset automatically - Debug builds:
DevFastpreset (4 MiB memory, 1 iteration, 1 thread) for faster iteration - Release opt-in:
insecure-fast-hashfeature enablesDevFastin release builds (⚠️ NEVER use in production)
- Constant-Time Verification: Always performs Argon2 computation, even for non-existent accounts
- Dummy Hash Verification: Uses a pre-computed dummy hash for non-existent users
- Unified Error Response: Returns generic
InvalidCredentialsfor both "user not found" and "wrong password" - No Early Returns: Authentication logic defers all branching until after hash computation
- HMAC Signature Validation: All tokens verified with configured signing key
- Expiration Enforcement: Standard
expclaim validation with configurable lifetime - Issuer Validation: Required
issclaim must match expected issuer - Tamper Detection: Any modification to payload or header invalidates signature
- Algorithm Consistency: Enforces that token algorithm matches expected algorithm
By default, this crate uses the rust_crypto backend for JWT cryptographic operations.
This is a pure Rust implementation that doesn't require external dependencies.
The crate uses the rust_crypto backend by default, which is a pure-Rust implementation and does not require external system dependencies.
Note that the rust_crypto backend depends on the rsa crate which was affected by vulnerability
RUSTSEC-2023-0071 (Marvin Attack). This is a timing attack that could
potentially allow key recovery.
- Development Default: Generates ephemeral random key per process (testing only)
- Production Requirements:
- Use stable, high-entropy secret (≥32 bytes recommended)
- Load from environment variables or secret management systems
- Store outside source control
- Rotate periodically (currently a manual process)
Example Production Setup:
// Load from environment (recommended)
let secret = std::env::var("JWT_SECRET").expect("JWT_SECRET not set");
// Construct symmetric encoding/decoding keys
let enc_key = jsonwebtoken::EncodingKey::from_secret(secret.as_bytes());
let dec_key = jsonwebtoken::DecodingKey::from_secret(secret.as_bytes());
// Build options with persistent keys (avoid JsonWebToken::default in production)
use axum_gate::codecs::jwt::{JsonWebToken, JsonWebTokenOptions, JwtClaims};
let options = JsonWebTokenOptions {
enc_key,
dec_key,
header: None,
validation: None,
};
// Create a codec that survives restarts as long as JWT_SECRET stays the same
use std::sync::Arc;
use axum_gate::prelude::*;
let jwt_codec = Arc::new(
JsonWebToken::<JwtClaims<Account<Role, Group>>>::new_with_options(options)
);When using cookie-based authentication, apply these security settings:
use axum_gate::prelude::*;
use cookie::SameSite;
use cookie::time::Duration;
// Recommended production cookie settings
let template = CookieTemplate::recommended()
.name("auth-token")
.persistent(Duration::hours(24)) // Explicit expiration
.same_site(SameSite::Strict); // Strong CSRF protection
let secure_cookie = template.build_with_value(&token_value);- Always use
secure(true)in production (HTTPS required) - Set
http_only(true)to prevent JavaScript access (XSS mitigation) - Use
SameSite::StrictorLaxfor CSRF protection - Avoid
SameSite::Noneunless cross-site requests are required - Consider
__Host-prefix for additional security (requires Secure + no Domain + Path="/") - Optional user context (cookies): When you need anonymous routes that can still personalize content, configure CookieGate with
allow_anonymous_with_optional_user(). This never blocks requests and insertsOption<Account<..>>andOption<RegisteredClaims>; enforce access in handlers if required.
- Default Deny:
Gatewith no policy denies all requests - Least Privilege: Combine roles and permissions narrowly
- Hierarchical Roles: Parent-child relationships with explicit traversal
- Fine-Grained Permissions: 64-bit deterministic IDs from permission names
- CookieGate optional mode: For routes that should never be blocked but may use authenticated context when present, configure CookieGate with
allow_anonymous_with_optional_user(). This installsOption<Account<..>>andOption<RegisteredClaims>without enforcing authentication or authorization in the middleware. Handlers must perform any necessary checks. - BearerGate modes: Bearer gate supports (1) strict JWT mode (enforces policy), (2) optional mode via
allow_anonymous_with_optional_user()(never blocks; inserts optional context), and (3) static token mode viawith_static_token("...")for internal services.
- Deterministic Hashing: Uses SHA-256 prefix for 64-bit permission IDs
- Collision Validation: Built-in
validate_permissions![]macro for compile-time checks - Runtime Validation:
PermissionCollisionCheckerfor dynamic permission sets - Cross-Node Consistency: Deterministic hashing ensures identical permission evaluation across distributed deployments
Example Permission Validation:
use axum_gate::prelude::*;
// Compile-time validation ensures no collisions
validate_permissions![
"create:user",
"update:user",
"delete:user",
"view:dashboard",
];While axum-gate doesn't provide rate limiting directly, it integrates seamlessly with tower middleware:
use tower::{ServiceBuilder, limit::RateLimitLayer, buffer::BufferLayer};
let protected_routes = Router::new()
.route("/login", post(login_handler))
.layer(
ServiceBuilder::new()
.layer(BufferLayer::new(1024))
.layer(RateLimitLayer::new(5, Duration::from_secs(60))) // 5/minute
);Recommended Rate Limits:
- Login endpoints: 5-10 requests per minute per IP
- Password reset: 3 requests per hour per email
- Protected APIs: 100-1000 requests per minute per user
- Admin endpoints: 10-50 requests per minute
- Interface Separation: Account and secret repositories can use different backends
- Least Privilege: Database users should have minimal required permissions
- Connection Security: Use TLS/SSL for database connections in production
- Backup Encryption: Ensure backups of authentication data are encrypted
| Backend | Feature Flag | Production Ready | Notes |
|---|---|---|---|
| In-Memory | (default) | ❌ Development only | Lost on restart |
| SurrealDB | storage-surrealdb |
✅ | Embedded or remote |
| SeaORM | storage-seaorm |
✅ | Multi-database support |
- SameSite=None: Vulnerable to CSRF attacks
- SameSite=Lax: Reduced CSRF risk, allows some cross-site navigation
- SameSite=Strict: Maximum CSRF protection, may break cross-site workflows
- Primary: Use
SameSite=Strictfor sensitive applications - Alternative: Implement double-submit cookie pattern
- API Clients: Use header-based authentication with the Bearer gate (implemented), or static token mode for internal services
- Client-Side Logout: JWT tokens remain valid until expiration
- No Server-Side Revocation: Cannot immediately invalidate specific tokens
- Global Invalidation: Requires signing key rotation (invalidates all sessions)
// Secure logout using axum-gate's built-in handler
use axum_gate::route_handlers::logout;
use axum_extra::extract::CookieJar;
use axum_gate::prelude::*;
async fn logout_handler(cookie_jar: CookieJar) -> CookieJar {
let cookie_template = CookieTemplate::recommended().name("auth-token");
logout(cookie_jar, cookie_template).await
}- Structured Logging: Comprehensive tracing integration with contextual metadata for all authentication operations
- Prometheus Metrics: Built-in counters and histograms (authorization decisions, JWT validation latency, account operations)
- Audit Logging: Emits structured tracing events when
audit-loggingis enabled; integrate with your tracing subscriber/sink - Security Metrics: Authorization success/denial tracking, JWT validation monitoring, account lifecycle events
Enable with the prometheus feature flag:
// Metrics are automatically collected and can be exposed
use axum_gate::prelude::*;
use axum_gate::audit::prometheus_metrics;
let registry = prometheus::Registry::new();
prometheus_metrics::install_prometheus_metrics_with_registry(®istry).expect("install metrics");
let app = Router::new()
.route("/", get(handler).layer(
Gate::cookie("app", jwt_codec)
.with_policy(policy)
.with_prometheus_registry(®istry) // Enable metrics collection
))
.route("/metrics", get(metrics_handler));Available Metrics:
axum_gate_authz_authorized_total- Successful authorization decisionsaxum_gate_authz_denied_total- Denied authorization attempts (by reason)axum_gate_jwt_invalid_total- Invalid JWT tokens (by failure type)axum_gate_account_delete_outcome_total- Account deletion operationsaxum_gate_account_insert_outcome_total- Account creation operationsaxum_gate_authz_decision_seconds- Authorization decision latency (histogram; by outcome)axum_gate_jwt_validation_seconds- JWT validation latency (histogram; by outcome)
Current Monitoring Setup:
use tracing::{info, warn, error};
// Add to your application
tracing_subscriber::fmt()
.with_max_level(tracing::Level::INFO)
.init();
// Monitor authentication events
info!("User {} logged in successfully", user_id);
warn!("Failed login attempt for {}", user_id);
error!("Suspicious activity: {} failed attempts from {}", count, ip);| Category | Requirement | Status |
|---|---|---|
| Transport Security | ✅ HTTPS with HSTS | Required |
| JWT Secrets | ✅ High-entropy (≥32 bytes) | Required |
| JWT Secrets | ✅ External secret management | Recommended |
| Argon2 Config | ✅ HighSecurity preset in production | Default |
| Cookie Security | ✅ Secure, HttpOnly, SameSite | Required |
| Rate Limiting | ✅ Login endpoint protection | Recommended |
| Database Security | ✅ TLS connections | Required |
| Backup Encryption | ✅ Encrypted backups | Required |
| Monitoring | ✅ Prometheus metrics (feature flag) | Available |
| Audit Logging | ✅ Basic audit logging (feature flag) | Available |
✅ = Built-in or available
Current Status: The project uses automated security scanning with the following configuration:
Temporarily Disabled Advisories:
RUSTSEC-2024-0436: Transitive dependency via surrealdb; upstream is tracking a fix/replacement for thepastecrate
This advisory is actively monitored and will be addressed when the upstream dependency (surrealdb) provides a solution. The decision to temporarily disable allows continued development while proper mitigations are implemented.
Audit Recommendations:
- Run
cargo auditregularly in your projects - Monitor RustSec Advisory Database
- Subscribe to security mailing lists for dependencies
- Use
cargo denyfor comprehensive dependency policy enforcement
- Unicode Handling: Full UTF-8 support for international passwords
- Memory Safety: Rust's ownership system prevents buffer overflows
- Type Safety: Strong typing prevents injection attacks
// Implement request size limits
use tower_http::limit::RequestBodyLimitLayer;
let app = Router::new()
.layer(RequestBodyLimitLayer::new(1024 * 1024)) // 1MB limit
.route("/login", post(login_handler));
// Validate input lengths
fn validate_password(password: &str) -> Result<(), ValidationError> {
if password.len() > 128 {
return Err(ValidationError::TooLong);
}
if password.len() < 8 {
return Err(ValidationError::TooShort);
}
Ok(())
}- Generic Error Messages: Public APIs return user-friendly, non-revealing errors
- Detailed Logging: Full error context logged server-side only
- Consistent Responses: Same error format regardless of failure type
// User-safe error responses
match auth_result {
Err(Error::InvalidCredentials) => "Invalid username or password",
Err(Error::AccountLocked) => "Account temporarily locked",
Err(_) => "Authentication temporarily unavailable",
}| Feature | Security Impact | Recommendation |
|---|---|---|
insecure-fast-hash |
NEVER enable in production | |
storage-surrealdb |
✅ Production-ready storage | Safe for production |
storage-seaorm |
✅ Production-ready storage | Safe for production |
audit-logging |
✅ Enhances security monitoring | Recommended for production |
prometheus |
✅ Enables metrics collection | Recommended for production monitoring |
// Production-safe feature configuration
[dependencies]
axum-gate = {
version = "2.0.0-dev",
features = ["storage-surrealdb", "audit-logging", "prometheus"]
}
// Development configuration (faster hashing automatically enabled in debug builds)
[dev-dependencies]
axum-gate = { version = "2.0.0-dev", features = ["storage-surrealdb"] }- Do NOT create public GitHub issues for security vulnerabilities
- Email: Send reports to the maintainer (info@emirror.de)
- Include:
- Detailed vulnerability description
- Steps to reproduce
- Potential impact assessment
- Suggested mitigation (if available)
- Acknowledgment: Within 48 hours
- Assessment: Within 1 week
- Fix Development: Within 2-4 weeks (depending on severity)
- Public Disclosure: After fix is released and users have time to update
- Published on GitHub Security Advisories
- Cross-posted to RustSec Advisory Database
- Included in release changelog with CVE reference if applicable
- OWASP: Follows OWASP Authentication Guidelines
- NIST: Aligns with NIST Cybersecurity Framework
- GDPR: Supports data minimization and secure processing
- HIPAA: Additional encryption and audit logging may be required
- PCI DSS: Consider additional tokenization for payment applications
- SOX: Ensure audit trails are implemented for financial applications
- SOC 2: Built-in audit logging and monitoring features support compliance efforts
- Security-First Design: Architecture reviews prioritize security
- Automated Testing: Security-focused unit and integration tests
- Dependency Management: Regular updates and vulnerability scanning with
cargo deny - Code Review: Security-focused review process
# Run security-focused tests
cargo test security
cargo test timing_attack
cargo test permission_collision
# Audit dependencies
cargo audit
# Check dependency policies
cargo deny check
# Check for common security issues
cargo clippy -- -D warnings- High Security: Slower but cryptographically stronger (production default)
- Interactive: Balanced security and performance for user-facing apps
- DevFast: Fast but weaker security (development only)
- JWT Pros: Stateless, scalable, no server-side session storage
- JWT Cons: Cannot revoke tokens before expiration, larger cookie size
- Mitigation: Short token lifetimes, refresh token rotation (planned v1.1.0)
Stay Secure: axum-gate v2.0.0-dev provides a robust security foundation with production-ready features. Defense-in-depth requires combining it with proper infrastructure hardening, monitoring, and operational security practices.
For the latest security updates and best practices, monitor the GitHub repository and security advisories.