Crate nonce_auth

Source
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 requests
  • NonceServer: 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 server
  • NonceError: 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§

nonce
storage
Storage backend abstractions and implementations.

Structs§

ProtectionData
Authentication data for nonce-based request verification.