SessionStorage

Trait SessionStorage 

Source
pub trait SessionStorage: Send + Sync {
    // Required methods
    fn create_user_session(
        &self,
        user_id: String,
        session_id: Uuid,
        expires_at: OffsetDateTime,
    ) -> impl Future<Output = Result<()>> + Send;
    fn get_user_sessions(
        &self,
        user_id: &str,
    ) -> impl Future<Output = Result<Vec<SessionData>>> + Send;
    fn revoke_user_session(
        &self,
        user_id: &str,
        session_id: &Uuid,
    ) -> impl Future<Output = Result<()>> + Send;
    fn revoke_all_user_sessions(
        &self,
        user_id: &str,
    ) -> impl Future<Output = Result<()>> + Send;

    // Provided methods
    fn user_session_exists(
        &self,
        user_id: &str,
        session_id: &Uuid,
    ) -> impl Future<Output = Result<bool>> + Send { ... }
    fn get_session_data(
        &self,
        user_id: &str,
        session_id: &Uuid,
    ) -> impl Future<Output = Result<Option<SessionData>>> + Send { ... }
    fn cleanup_expired_sessions(
        &self,
        user_id: &str,
    ) -> impl Future<Output = Result<()>> + Send { ... }
}
Expand description

Trait for session storage backends.

With the JWT-based session data approach, the storage is now responsible for managing refresh tokens organized by user_id. Each user can have multiple active sessions stored as an array. Session data is stored directly in the JWT access token.

All methods are async and return Send futures, allowing them to be used safely across thread boundaries in async contexts.

§Example Implementation

use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use time::OffsetDateTime;
use uuid::Uuid;
use axum_jwt_sessions::error::Result;
use axum_jwt_sessions::{SessionData, SessionStorage};

struct UserSessionStorage {
    user_sessions: Arc<RwLock<HashMap<String, Vec<SessionData>>>>,
}

impl SessionStorage for UserSessionStorage {
    async fn create_user_session(&self, user_id: String, session_id: Uuid, expires_at: OffsetDateTime) -> Result<()> {
        let mut sessions = self.user_sessions.write().await;
        let user_sessions = sessions.entry(user_id).or_insert_with(Vec::new);

        user_sessions.push(SessionData {
            session_id,
            expires_at,
        });

        Ok(())
    }

    async fn get_user_sessions(&self, user_id: &str) -> Result<Vec<SessionData>> {
        let sessions = self.user_sessions.read().await;
        let now = OffsetDateTime::now_utc();

        if let Some(user_sessions) = sessions.get(user_id) {
            // Return only non-expired sessions
            let active_sessions: Vec<SessionData> = user_sessions
                .iter()
                .filter(|session| session.expires_at > now)
                .cloned()
                .collect();
            Ok(active_sessions)
        } else {
            Ok(Vec::new())
        }
    }

    async fn revoke_user_session(&self, user_id: &str, session_id: &Uuid) -> Result<()> {
        let mut sessions = self.user_sessions.write().await;
        if let Some(user_sessions) = sessions.get_mut(user_id) {
            user_sessions.retain(|session| session.session_id != *session_id);
            if user_sessions.is_empty() {
                sessions.remove(user_id);
            }
        }
        Ok(())
    }

    async fn revoke_all_user_sessions(&self, user_id: &str) -> Result<()> {
        self.user_sessions.write().await.remove(user_id);
        Ok(())
    }
}

Required Methods§

Source

fn create_user_session( &self, user_id: String, session_id: Uuid, expires_at: OffsetDateTime, ) -> impl Future<Output = Result<()>> + Send

Create a new session for a user

Source

fn get_user_sessions( &self, user_id: &str, ) -> impl Future<Output = Result<Vec<SessionData>>> + Send

Get all active sessions for a user (excludes expired sessions)

Source

fn revoke_user_session( &self, user_id: &str, session_id: &Uuid, ) -> impl Future<Output = Result<()>> + Send

Revoke a specific session for a user

Source

fn revoke_all_user_sessions( &self, user_id: &str, ) -> impl Future<Output = Result<()>> + Send

Revoke all sessions for a user

Provided Methods§

Source

fn user_session_exists( &self, user_id: &str, session_id: &Uuid, ) -> impl Future<Output = Result<bool>> + Send

Check if a specific session exists for a user (not revoked or expired)

Source

fn get_session_data( &self, user_id: &str, session_id: &Uuid, ) -> impl Future<Output = Result<Option<SessionData>>> + Send

Get session data for a specific session_id within a user’s sessions

Source

fn cleanup_expired_sessions( &self, user_id: &str, ) -> impl Future<Output = Result<()>> + Send

Clean up expired sessions for a user

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§