Skip to main content

uvb_storage_api/
session.rs

1use async_trait::async_trait;
2use serde::{Deserialize, Serialize};
3use std::time::{Duration, SystemTime};
4use thiserror::Error;
5use uvb_core::TenantId;
6
7#[derive(Debug, Error)]
8pub enum SessionError {
9    #[error("session not found")]
10    NotFound,
11    #[error("session expired")]
12    Expired,
13    #[error("storage error: {0}")]
14    Storage(String),
15}
16
17/// Represents an authenticated session after successful verification
18#[derive(Clone, Debug, Serialize, Deserialize)]
19pub struct SessionRecord {
20    pub id: String,
21    pub user_id: String,
22    pub tenant_id: TenantId,
23    pub transaction_id: String,
24    pub factors_used: Vec<String>,
25    pub assurance_level: i32,
26    pub metadata: serde_json::Value,
27    pub created_at: SystemTime,
28    pub expires_at: SystemTime,
29    pub last_activity_at: SystemTime,
30}
31
32/// Trait for pluggable session storage
33///
34/// Ideal for:
35/// - Redis (with TTL)
36/// - Memcached
37/// - PostgreSQL (with periodic cleanup)
38/// - JWT (stateless, no storage)
39#[async_trait]
40pub trait SessionStore: Send + Sync {
41    /// Create a new session
42    async fn create(&self, record: SessionRecord) -> Result<String, SessionError>;
43
44    /// Get a session by ID
45    async fn get(&self, id: &str) -> Result<Option<SessionRecord>, SessionError>;
46
47    /// Update session (e.g., extend expiration, update metadata)
48    async fn update(&self, record: SessionRecord) -> Result<(), SessionError>;
49
50    /// Delete a session (logout)
51    async fn delete(&self, id: &str) -> Result<(), SessionError>;
52
53    /// Delete all sessions for a user (force logout)
54    async fn delete_by_user(
55        &self,
56        user_id: &str,
57        tenant_id: &TenantId,
58    ) -> Result<usize, SessionError>;
59
60    /// Extend session expiration (sliding window)
61    async fn extend(&self, id: &str, duration: Duration) -> Result<(), SessionError>;
62
63    /// Update last activity timestamp
64    async fn touch(&self, id: &str) -> Result<(), SessionError>;
65
66    /// Cleanup expired sessions (background job)
67    async fn cleanup_expired(&self) -> Result<usize, SessionError>;
68
69    /// List active sessions for a user
70    async fn list_by_user(
71        &self,
72        user_id: &str,
73        tenant_id: &TenantId,
74    ) -> Result<Vec<SessionRecord>, SessionError>;
75}