reinhardt-auth 0.1.0-alpha.16

Authentication and authorization system
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
# reinhardt-auth

Authentication and authorization system for Reinhardt framework.

## Overview

Comprehensive authentication and authorization system inspired by Django and
Django REST Framework. Provides JWT tokens, permission classes, user models, and
password hashing with Argon2.

## Installation

Add `reinhardt` to your `Cargo.toml`:

```toml
[dependencies]
reinhardt = { version = "0.1.0-alpha.1", features = ["auth"] }

# Or use a preset:
# reinhardt = { version = "0.1.0-alpha.1", features = ["standard"] }  # Recommended
# reinhardt = { version = "0.1.0-alpha.1", features = ["full"] }      # All features
```

Then import authentication features:

```rust
use reinhardt::auth::{User, SimpleUser, AnonymousUser};
use reinhardt::auth::{JwtAuth, HttpBasicAuth, AuthenticationBackend};
use reinhardt::auth::{AllowAny, IsAuthenticated, IsAuthenticatedOrReadOnly};
```

**Note:** Authentication features are included in the `standard` and `full` feature presets.

## Implemented ✓

### Core Authentication

#### JWT (JSON Web Token) Authentication

- **Claims Management**: `Claims` struct with user identification, expiration,
  and issue times
- **Token Generation**: Automatic 24-hour expiration by default
- **Token Verification**: Built-in expiration checking and signature validation
- **Encode/Decode**: Full JWT token encoding and decoding support

```rust
use reinhardt::auth::jwt::{JwtAuth, Claims};
use chrono::Duration;

let jwt_auth = JwtAuth::new(b"my-secret-key");
let token = jwt_auth.generate_token("user123".to_string(), "john_doe".to_string()).unwrap();
let claims = jwt_auth.verify_token(&token).unwrap();
```

#### HTTP Basic Authentication

- **BasicAuthentication**: HTTP Basic auth backend with user management
- **Base64 Encoding/Decoding**: Standard HTTP Basic auth header parsing
- **User Registration**: Add users with username/password pairs
- **Request Authentication**: Extract and verify credentials from Authorization
  headers

```rust
use reinhardt::auth::{HttpBasicAuth, AuthenticationBackend};

let mut auth = HttpBasicAuth::new();
auth.add_user("alice", "secret123");

// Request with Basic auth header will be authenticated
let result = auth.authenticate(&request).unwrap();
```

### User Management

#### User Trait

- **Core User Interface**: Unified trait for authenticated and anonymous users
- **User Identification**: `id()`, `username()`, `get_username()` methods
- **Authentication Status**: `is_authenticated()`, `is_active()`, `is_admin()`
  checks
- **Django Compatibility**: Methods compatible with Django's user interface

#### User Implementations

- **SimpleUser**: Fully-featured user with UUID, username, email, active/admin
  flags
- **AnonymousUser**: Zero-sized type representing unauthenticated visitors
- **Serialization Support**: Serde integration for SimpleUser

```rust
use reinhardt::auth::{User, SimpleUser, AnonymousUser};
use uuid::Uuid;

let user = SimpleUser {
    id: Uuid::new_v4(),
    username: "john".to_string(),
    email: "john@example.com".to_string(),
    is_active: true,
    is_admin: false,
};

assert!(user.is_authenticated());
assert!(!user.is_admin());
```

### Django-Style User Models

#### BaseUser Trait (AbstractBaseUser equivalent)

- **Minimal Authentication Interface**: Minimal set of fields for user
  authentication
- **Automatic Password Hashing**: Argon2id hashing by default, fully
  customizable
- **Associated Type Default**:
  `type Hasher: PasswordHasher + Default = Argon2Hasher`
- **Password Management**:
  - `set_password()`: Automatically hashes with configured hasher
  - `check_password()`: Verifies password against hash
  - `set_unusable_password()`: Marks password as unusable (for OAuth-only
    accounts)
  - `has_usable_password()`: Checks if user can log in with password
- **Session Authentication**: `get_session_auth_hash()` for session invalidation
  on password change
- **Username Normalization**: NFKC Unicode normalization to prevent homograph
  attacks
- **Django Compatibility**: Method names and behavior match Django's
  AbstractBaseUser

```rust
use reinhardt::auth::BaseUser;
use uuid::Uuid;
use chrono::Utc;
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct MyUser {
    id: Uuid,
    email: String,
    password_hash: Option<String>,
    last_login: Option<chrono::DateTime<Utc>>,
    is_active: bool,
}

impl BaseUser for MyUser {
    type PrimaryKey = Uuid;
    // type Hasher = Argon2Hasher; // Default, can be omitted or customized

    fn get_username_field() -> &'static str { "email" }
    fn get_username(&self) -> &str { &self.email }
    fn password_hash(&self) -> Option<&str> { self.password_hash.as_deref() }
    fn set_password_hash(&mut self, hash: String) { self.password_hash = Some(hash); }
    fn last_login(&self) -> Option<chrono::DateTime<Utc>> { self.last_login }
    fn set_last_login(&mut self, time: chrono::DateTime<Utc>) { self.last_login = Some(time); }
    fn is_active(&self) -> bool { self.is_active }
}

let mut user = MyUser {
    id: Uuid::new_v4(),
    email: "alice@example.com".to_string(),
    password_hash: None,
    last_login: None,
    is_active: true,
};

// Password is automatically hashed with Argon2id
user.set_password("securepass123").unwrap();
assert!(user.check_password("securepass123").unwrap());
```

#### FullUser Trait (AbstractUser equivalent)

- **Complete User Model**: Extends BaseUser with additional fields
- **User Profile Fields**:
  - `username()`: Unique username for login
  - `email()`: Email address
  - `first_name()` / `last_name()`: User's name
  - `is_staff()`: Can access admin interface
  - `is_superuser()`: Has all permissions
  - `date_joined()`: Account creation timestamp
- **Helper Methods**:
  - `get_full_name()`: Combines first and last name
  - `get_short_name()`: Returns first name only
- **Django Compatibility**: Matches Django's AbstractUser interface

```rust
use reinhardt::auth::{BaseUser, FullUser, DefaultUser};
use uuid::Uuid;
use chrono::Utc;

let mut user = DefaultUser {
    id: Uuid::new_v4(),
    username: "alice".to_string(),
    email: "alice@example.com".to_string(),
    first_name: "Alice".to_string(),
    last_name: "Smith".to_string(),
    password_hash: None,
    last_login: None,
    is_active: true,
    is_staff: false,
    is_superuser: false,
    date_joined: Utc::now(),
    user_permissions: Vec::new(),
    groups: Vec::new(),
};

assert_eq!(user.get_full_name(), "Alice Smith");
assert_eq!(user.get_short_name(), "Alice");
```

#### PermissionsMixin Trait

- **Authorization Interface**: Permission and group management
- **Permission Checking**:
  - `has_perm(perm)`: Check if user has specific permission
  - `has_module_perms(app_label)`: Check if user has any permission for app
  - `get_all_permissions()`: Get all user and group permissions
- **Superuser Bypass**: Superusers automatically pass all permission checks
- **Group Support**: Users can belong to multiple groups
- **Django Compatibility**: Permission format `"app_label.permission_name"`

```rust
use reinhardt::auth::{DefaultUser, PermissionsMixin};
use uuid::Uuid;
use chrono::Utc;

let user = DefaultUser {
    id: Uuid::new_v4(),
    username: "bob".to_string(),
    email: "bob@example.com".to_string(),
    first_name: "Bob".to_string(),
    last_name: "Johnson".to_string(),
    password_hash: None,
    last_login: None,
    is_active: true,
    is_staff: true,
    is_superuser: false,
    date_joined: Utc::now(),
    user_permissions: vec![
        "blog.add_post".to_string(),
        "blog.change_post".to_string(),
    ],
    groups: vec!["editors".to_string()],
};

assert!(user.has_perm("blog.add_post"));
assert!(user.has_module_perms("blog"));
```

#### DefaultUser Struct

- **Ready-to-Use Implementation**: Combines BaseUser, FullUser, and
  PermissionsMixin
- **Database Model**: `#[derive(Model)]` for ORM integration
- **Table Name**: `auth_user` (Django-compatible)
- **All Fields Included**: Username, email, names, passwords, permissions,
  groups, flags, timestamps
- **Zero Configuration**: Works out of the box with automatic Argon2id hashing

```rust
use reinhardt::auth::{BaseUser, DefaultUser, DefaultUserManager};
use std::collections::HashMap;

# tokio_test::block_on(async {
let mut manager = DefaultUserManager::new();

// Create a regular user
let user = manager.create_user(
    "alice",
    Some("securepass123"),
    HashMap::new()
).await.unwrap();

assert_eq!(user.username, "alice");
assert!(user.is_active);
assert!(!user.is_staff);

// Create a superuser
let admin = manager.create_superuser(
    "admin",
    Some("adminsecret"),
    HashMap::new()
).await.unwrap();

assert!(admin.is_staff);
assert!(admin.is_superuser);
# })
```

#### BaseUserManager Trait

- **User Creation Interface**: `create_user()` and `create_superuser()` methods
- **Async Support**: Full async/await integration
- **Extra Fields**: Accept arbitrary extra data via HashMap
- **Email Normalization**: `normalize_email()` static method
- **Django Compatibility**: Matches Django's UserManager interface

#### DefaultUserManager

- **In-Memory Implementation**: Built-in manager for DefaultUser
- **Thread-Safe**: Uses `Arc<RwLock<HashMap>>` for concurrent access
- **User Lookup**: `get_by_id()` and `get_by_username()` methods
- **Demonstration Purpose**: For testing and prototyping (use ORM-based manager
  in production)

### Password Security

#### Password Hashing

- **PasswordHasher Trait**: Composable password hashing interface
- **Argon2Hasher**: Production-ready Argon2id implementation (recommended)
- **Hash Generation**: Secure salt generation using OS random number generator
- **Password Verification**: Constant-time comparison for security

```rust
use reinhardt::auth::{Argon2Hasher, PasswordHasher};

let hasher = Argon2Hasher::new();
let hash = hasher.hash("my_password").unwrap();
assert!(hasher.verify("my_password", &hash).unwrap());
```

### Authentication Backends

#### AuthBackend Trait

- **Composable Architecture**: Support for multiple authentication strategies
- **Async Support**: Full async/await integration with `async_trait`
- **User Authentication**: `authenticate(username, password)` method
- **User Lookup**: `get_user(user_id)` for session restoration

#### Composite Authentication

- **CompositeAuthBackend**: Chain multiple authentication backends
- **Fallback Support**: Try backends in order until one succeeds
- **Flexible Configuration**: Add backends dynamically at runtime

```rust
use reinhardt::auth::CompositeAuthBackend;

let mut composite = CompositeAuthBackend::new();
composite.add_backend(Box::new(database_backend));
composite.add_backend(Box::new(ldap_backend));

// Will try database first, then LDAP
let user = composite.authenticate("alice", "password").await;
```

### Permission System

#### Permission Trait

- **Permission Interface**: Async `has_permission()` method with context
- **PermissionContext**: Request-aware context with authentication flags
- **Composable Permissions**: Build complex permission logic

#### Built-in Permission Classes

- **AllowAny**: Allow all requests without authentication
- **IsAuthenticated**: Require authenticated user
- **IsAdminUser**: Require authenticated admin user
- **IsActiveUser**: Require authenticated and active user
- **IsAuthenticatedOrReadOnly**: Authenticated for write, read-only for
  anonymous users

```rust
use reinhardt::auth::{Permission, IsAuthenticated, PermissionContext};

let permission = IsAuthenticated;
let context = PermissionContext {
    request: &request,
    is_authenticated: true,
    is_admin: false,
    is_active: true,
};

assert!(permission.has_permission(&context).await);
```

### Error Handling

#### AuthenticationError

- **InvalidCredentials**: Wrong username or password
- **UserNotFound**: User does not exist
- **SessionExpired**: Session has expired
- **InvalidToken**: Token is malformed or invalid
- **Unknown**: Generic error with custom message

#### AuthenticationBackend Trait

- **Unified Error Handling**: All backends use `AuthenticationError`
- **Standard Error Trait**: Implements `std::error::Error`
- **Display Implementation**: User-friendly error messages

### Session-Based Authentication

#### SessionAuthentication

- **Session Management**: `Session` struct with HashMap-based data storage
- **SessionStore Trait**: Async interface for session persistence
  - `load()`: Retrieve session by ID
  - `save()`: Persist session data
  - `delete()`: Remove session
- **InMemorySessionStore**: Built-in in-memory session storage
- **SessionId**: Type-safe session identifier wrapper
- **Cookie Integration**: Secure session cookie handling

```rust
use reinhardt::auth::{SessionAuthentication, Authentication};
use reinhardt::auth::sessions::backends::InMemorySessionBackend;

let session_backend = InMemorySessionBackend::new();
let auth = SessionAuthentication::new(session_backend);

// Authenticate user from request (checks session cookie)
let user = auth.authenticate(&request).await?;

// Get user by ID
if let Some(user) = auth.get_user("user_id").await? {
    println!("User: {}", user.get_username());
}
```

### Multi-Factor Authentication (MFA)

#### TOTP-Based MFA

- **MFAAuthentication**: Time-based one-time password (TOTP) authentication
- **Secret Management**: Secure per-user secret storage
- **QR Code Generation**: Generate TOTP URLs for authenticator apps (Google
  Authenticator, Authy)
- **Code Verification**: Verify TOTP codes with configurable time window
- **Registration Flow**: User enrollment with secret generation
- **Time Window**: Configurable tolerance for time skew (default: 1 time step)

```rust
use reinhardt::auth::MFAAuthentication;

let mfa = MFAAuthentication::new("MyApp");

// Register user for MFA
let totp_url = mfa.register_user("alice").await?;
// User scans QR code generated from totp_url

// Verify code during login
let code = "123456"; // from user's authenticator app
assert!(mfa.verify_code("alice", code).await?);
```

### OAuth2 Support

#### OAuth2 Authentication

- **OAuth2Authentication**: Full OAuth2 provider implementation
- **Grant Types**: Authorization Code, Client Credentials, Refresh Token,
  Implicit
- **Application Management**: `OAuth2Application` with client credentials
- **Token Management**: `OAuth2Token` with access and refresh tokens
- **Authorization Flow**:
  - Authorization code generation and validation
  - Token exchange (code → access token)
  - Token refresh with refresh tokens
- **OAuth2TokenStore Trait**: Persistent token storage interface
- **InMemoryTokenStore**: Built-in in-memory token storage

```rust
use reinhardt::auth::{OAuth2Authentication, GrantType, InMemoryOAuth2Store};

let store = InMemoryOAuth2Store::new();
let oauth2 = OAuth2Authentication::new(store);

// Register OAuth2 application
oauth2.register_application(
    "client123",
    "secret456",
    "https://example.com/callback",
    vec![GrantType::AuthorizationCode]
).await?;

// Authorization code flow
let code = oauth2.generate_authorization_code("client123", "user123", vec!["read", "write"]).await?;
let token = oauth2.exchange_code(&code, "client123").await?;

// Use access token
let claims = oauth2.verify_token(&token.access_token).await?;
```

### Token Blacklist & Rotation

#### Token Blacklist

- **TokenBlacklist Trait**: Interface for token invalidation
- **BlacklistReason**: Categorized revocation reasons
  - `Logout`: User-initiated logout
  - `Compromised`: Security incident
  - `ManualRevoke`: Admin revocation
  - `Rotated`: Automatic token rotation
- **InMemoryBlacklist**: Built-in in-memory blacklist storage
- **Cleanup**: Automatic removal of expired blacklist entries
- **Statistics**: Usage tracking and monitoring

#### Token Rotation

- **TokenRotationManager**: Automatic refresh token rotation
- **RefreshTokenStore Trait**: Persistent refresh token storage
- **Rotation Flow**: Invalidate old token when issuing new one
- **Security**: Prevents refresh token reuse attacks
- **InMemoryRefreshStore**: Built-in in-memory refresh token storage

```rust
use reinhardt::auth::{
    TokenBlacklist, InMemoryBlacklist, BlacklistReason,
    TokenRotationManager, InMemoryRefreshStore
};

// Token blacklist
let blacklist = InMemoryBlacklist::new();
use chrono::{Utc, Duration};
let expires_at = Utc::now() + Duration::hours(24);
blacklist.blacklist("old_token", expires_at, BlacklistReason::Logout).await?;
assert!(blacklist.is_blacklisted("old_token").await?);

// Token rotation
let refresh_store = InMemoryRefreshStore::new();
let rotation_manager = TokenRotationManager::new(blacklist, refresh_store);

let new_token = rotation_manager.rotate_token("old_refresh_token", "user123").await?;
```

### Remote User Authentication

#### Header-Based Authentication

- **RemoteUserAuthentication**: Authenticate via trusted HTTP headers
- **Reverse Proxy Integration**: Support for authentication proxies (nginx,
  Apache, etc.)
- **Header Configuration**: Configurable header name (default: `REMOTE_USER`)
- **Header Validation**: Verify header presence and format
- **Automatic Logout**: Optional force logout when header is missing
- **SSO Support**: Single sign-on integration

```rust
use reinhardt::auth::RemoteUserAuthentication;

// Standard configuration
let auth = RemoteUserAuthentication::new("REMOTE_USER");

// With force logout
let auth = RemoteUserAuthentication::new("REMOTE_USER").force_logout_if_no_header(true);

// Authenticate from request
let user = auth.authenticate(&request).await?;
```

## Usage Examples

### Complete Authentication Flow

```rust
use reinhardt::auth::{
    JwtAuth, HttpBasicAuth, AuthBackend,
    SimpleUser, User, Argon2Hasher, PasswordHasher,
    Permission, IsAuthenticated, PermissionContext
};

// 1. Set up JWT authentication
let jwt_auth = JwtAuth::new(b"secret-key");

// 2. Set up Basic authentication with a user
let mut basic_auth = HttpBasicAuth::new();
basic_auth.add_user("alice", "password123");

// 3. Authenticate user and generate JWT
let user = basic_auth.authenticate(&request).unwrap().unwrap();
let token = jwt_auth.generate_token(
    user.id(),
    user.username().to_string()
).unwrap();

// 4. Verify token on subsequent requests
let claims = jwt_auth.verify_token(&token).unwrap();

// 5. Check permissions
let permission = IsAuthenticated;
let context = PermissionContext {
    request: &request,
    is_authenticated: true,
    is_admin: user.is_admin(),
    is_active: user.is_active(),
};

if permission.has_permission(&context).await {
    // Grant access
}
```

### Custom Authentication Backend

```rust
use reinhardt::auth::{AuthBackend, SimpleUser, Argon2Hasher, PasswordHasher};
use async_trait::async_trait;
use std::collections::HashMap;

struct MyAuthBackend {
    users: HashMap<String, (String, SimpleUser)>,
    hasher: Argon2Hasher,
}

#[async_trait]
impl AuthBackend for MyAuthBackend {
    type User = SimpleUser;

    async fn authenticate(
        &self,
        username: &str,
        password: &str,
    ) -> Result<Option<Self::User>, reinhardt_exception::Error> {
        if let Some((hash, user)) = self.users.get(username) {
            if self.hasher.verify(password, hash)? {
                return Ok(Some(user.clone()));
            }
        }
        Ok(None)
    }

    async fn get_user(&self, user_id: &str)
        -> Result<Option<Self::User>, reinhardt_exception::Error> {
        Ok(self.users.values()
            .find(|(_, u)| u.id.to_string() == user_id)
            .map(|(_, u)| u.clone()))
    }
}
```


## sessions

### Features

### Implemented ✓

#### Core Session Backend

- **SessionBackend Trait** - Async trait defining session storage operations (load, save, delete, exists)
- **SessionError** - Error types for session operations (cache errors, serialization errors)
- **Generic Session Storage** - Type-safe session data storage with `serde` support

#### Cache-Based Backends

- **InMemorySessionBackend** - In-memory session storage using `InMemoryCache`
  - Fast, volatile storage (sessions lost on restart)
  - TTL (Time-To-Live) support for automatic expiration
  - Suitable for development and single-instance deployments
- **CacheSessionBackend** - Generic cache-based session backend
  - Works with any `Cache` trait implementation
  - Supports external cache systems (Redis, Memcached, etc.)
  - Configurable TTL for session expiration
  - Horizontal scalability for distributed systems

#### Dependency Injection Support

- Integration with `reinhardt-di` for dependency injection
- Session backend registration and resolution

#### High-Level Session API

- **Session<B>** struct - Django-style session object with dictionary-like interface
  - Type-safe with generic backend parameter `B: SessionBackend`
  - Dictionary-like methods: `get()`, `set()`, `delete()`, `contains_key()`
  - Session iteration methods: `keys()`, `values()`, `items()`
  - Manual session clearing: `clear()`
  - Manual modification tracking: `mark_modified()`, `mark_unmodified()`
  - Session modification tracking: `is_modified()`, `is_accessed()`
  - Session key management: `get_or_create_key()`, `generate_key()`
  - Session lifecycle: `flush()` (clear and new key), `cycle_key()` (keep data, new key)
  - Automatic persistence: `save()` method with TTL support (default: 3600 seconds)
  - Comprehensive doctests and unit tests (36 total tests)

#### Storage Backends

- **DatabaseSessionBackend** (feature: `database`) - Persistent session storage in database
  - Session model with expiration timestamps
  - Automatic session cleanup with `cleanup_expired()`
  - SQLite, PostgreSQL, and MySQL support via sqlx
  - Table creation with `create_table()`
  - Indexed expiration dates for efficient cleanup
  - 9 comprehensive tests
- **FileSessionBackend** (feature: `file`) - File-based session storage
  - Session files stored in configurable directory (default: `/tmp/reinhardt_sessions`)
  - File locking using `fs2` for concurrent access safety
  - JSON serialization with TTL support
  - Automatic expired session cleanup on access
  - 11 comprehensive tests
- **CookieSessionBackend** (feature: `cookie`) - Encrypted session data in cookies
  - AES-256-GCM encryption for session data
  - HMAC-SHA256 signing for tamper detection
  - Automatic size limitation checking (4KB max)
  - Secure client-side storage
  - 11 comprehensive tests

#### HTTP Middleware

- **SessionMiddleware** (feature: `middleware`) - HTTP middleware for session management
  - Automatic session loading from cookies
  - Automatic session saving on response
  - Cookie configuration: name, path, domain
  - Security settings: secure, httponly, samesite
  - TTL and max-age support
- **HttpSessionConfig** - Comprehensive middleware configuration
- **SameSite** enum - Cookie SameSite attribute (Strict, Lax, None)

#### Session Management Features

- **Session expiration and cleanup** - Implemented via `cleanup_expired()` in DatabaseSessionBackend
- **Session key rotation** - Implemented via `cycle_key()` and `flush()` in Session API
- **Cross-site request forgery (CSRF) protection integration** - CSRF module available
- **Session serialization formats** - JSON via serde_json, MessagePack, CBOR, Bincode
- **Session storage migration tools** - Migration module available

#### Session Serialization Formats

- **JSON** (always available) - Human-readable, widely compatible via `serde_json`
- **MessagePack** (feature: `messagepack`) - Compact binary format, cross-platform via `rmp-serde`
- **CBOR** (feature: `cbor`) - RFC 7049 compliant binary format via `ciborium`
- **Bincode** (feature: `bincode`) - Fastest for Rust-to-Rust communication

#### Session Compression

- **CompressedSessionBackend** (feature: `compression`) - Automatic compression wrapper
  - Threshold-based compression (default: 512 bytes, configurable)
  - Only compresses data exceeding threshold to avoid overhead
  - **Zstd compression** (feature: `compression-zstd`) - Best balance of speed and ratio
  - **Gzip compression** (feature: `compression-gzip`) - Wide compatibility
  - **Brotli compression** (feature: `compression-brotli`) - Best compression ratio

#### Session Replication

- **ReplicatedSessionBackend** (feature: `replication`) - High availability with multi-backend replication
  - **AsyncReplication** - Eventual consistency, highest throughput
  - **SyncReplication** - Strong consistency, both backends updated in parallel
  - **AcknowledgedReplication** - Primary first, then secondary with acknowledgment
  - Configurable retry attempts and delays for failure handling

#### Session Analytics

- **InstrumentedSessionBackend** - Automatic session event tracking wrapper
- **LoggerAnalytics** - Tracing-based logging (always available)
- **PrometheusAnalytics** (feature: `analytics-prometheus`) - Prometheus metrics export
  - `session_created_total` - Total sessions created
  - `session_accessed_total` - Total session accesses
  - `session_access_latency_seconds` - Access latency histogram
  - `session_size_bytes` - Session data size histogram
  - `session_deleted_total` - Deletions by reason (explicit, expired, flushed)
  - `session_expired_total` - Total expired sessions

#### Multi-Tenant Session Isolation

- **TenantSessionBackend** (feature: `tenant`) - Tenant-specific session namespacing
  - Prefix-based keying: `tenant:{tenant_id}:session:{session_id}`
  - Configurable key prefix pattern
  - Maximum sessions per tenant limit
  - Strict isolation mode for security
  - **TenantSessionOperations** trait: `list_sessions()`, `count_sessions()`, `delete_all_sessions()`

## License

Licensed under the BSD 3-Clause License.