Expand description
§Nonce Auth
A Rust library for secure nonce-based authentication with pluggable storage backends.
This library provides a complete solution for implementing nonce-based authentication in client-server applications. It uses HMAC-SHA256 signatures and pluggable storage backends for persistent nonce storage to ensure that each request can only be used once.
§Features
- HMAC-SHA256 Signing: Cryptographic signing of requests using shared secrets
- Replay Attack Prevention: Each nonce can only be used once
- Time Window Validation: Requests outside the time window are rejected
- Context Isolation: Nonces can be scoped to different business contexts
- Pluggable Storage: Flexible storage backends (memory, database, Redis, etc.)
- Async Support: Fully asynchronous API design
- Client-Server Separation: Clean separation of client and server responsibilities
§Quick Start
§Basic Usage
use nonce_auth::{NonceClient, NonceServer, storage::MemoryStorage};
use std::time::Duration;
use std::sync::Arc;
use hmac::Mac;
// Create a storage backend
let storage = Arc::new(MemoryStorage::new());
// Create client and server with shared secret
let secret = b"shared_secret_key";
let client = NonceClient::new(secret);
let server = NonceServer::new(secret, storage, None, None);
// Initialize the storage backend
server.init().await?;
// Client generates authentication data with custom signature
let protection_data = client.create_protection_data(|mac, timestamp, nonce| {
mac.update(timestamp.as_bytes());
mac.update(nonce.as_bytes());
})?;
// Server verifies the authentication data with matching signature algorithm
match server.verify_protection_data(&protection_data, None, |mac| {
mac.update(protection_data.timestamp.to_string().as_bytes());
mac.update(protection_data.nonce.as_bytes());
}).await {
Ok(()) => println!("Authentication verified successfully"),
Err(e) => println!("Verification failed: {e}"),
}§With Context Isolation
use nonce_auth::{NonceClient, NonceServer, storage::MemoryStorage};
use std::sync::Arc;
use hmac::Mac;
let storage = Arc::new(MemoryStorage::new());
let client = NonceClient::new(b"secret");
let server = NonceServer::new(b"secret", storage, None, None);
let protection_data = client.create_protection_data(|mac, timestamp, nonce| {
mac.update(timestamp.as_bytes());
mac.update(nonce.as_bytes());
})?;
// Same nonce can be used in different contexts
server.verify_protection_data(&protection_data, Some("api_v1"), |mac| {
mac.update(protection_data.timestamp.to_string().as_bytes());
mac.update(protection_data.nonce.as_bytes());
}).await?;
server.verify_protection_data(&protection_data, Some("api_v2"), |mac| {
mac.update(protection_data.timestamp.to_string().as_bytes());
mac.update(protection_data.nonce.as_bytes());
}).await?;§Storage Backends
The library supports pluggable storage backends through the NonceStorage trait:
§In-Memory Storage (for testing/development)
use nonce_auth::storage::MemoryStorage;
use std::sync::Arc;
let storage = Arc::new(MemoryStorage::new());§Custom Storage Implementation
use nonce_auth::storage::{NonceStorage, NonceEntry, StorageStats};
use nonce_auth::NonceError;
use async_trait::async_trait;
use std::time::Duration;
pub struct CustomStorage {
// Your storage implementation
}
#[async_trait]
impl NonceStorage for CustomStorage {
async fn get(&self, nonce: &str, context: Option<&str>) -> Result<Option<NonceEntry>, NonceError> {
// Implementation
todo!()
}
async fn set(&self, nonce: &str, context: Option<&str>, ttl: Duration) -> Result<(), NonceError> {
// Implementation
todo!()
}
async fn exists(&self, nonce: &str, context: Option<&str>) -> Result<bool, NonceError> {
// Implementation
todo!()
}
async fn cleanup_expired(&self, cutoff_time: i64) -> Result<usize, NonceError> {
// Implementation
todo!()
}
async fn get_stats(&self) -> Result<StorageStats, NonceError> {
// Implementation
todo!()
}
}§Architecture
The library is designed with clear separation between client and server responsibilities:
NonceClient: Lightweight client for generating signed requestsNonceServer: Server-side verification and nonce management with pluggable storage- [
NonceStorage]: Abstract storage trait for implementing custom backends ProtectionData: The data structure exchanged between client and serverNonceError: Comprehensive error handling for all failure modes
Re-exports§
pub use nonce::NonceClient;pub use nonce::NonceConfig;pub use nonce::NonceError;pub use nonce::NonceServer;
Modules§
Structs§
- Protection
Data - Authentication data for nonce-based request verification.