Skip to main content

SessionStore

Trait SessionStore 

Source
pub trait SessionStore:
    Send
    + Sync
    + 'static {
    // Required methods
    fn insert_session(
        &self,
        session: &SessionRecord,
        token: &TokenHash,
    ) -> impl Future<Output = Result<(), StoreError>> + Send;
    fn find_by_token(
        &self,
        token: &TokenHash,
    ) -> impl Future<Output = Result<Option<TokenLookup>, StoreError>> + Send;
    fn apply(
        &self,
        update: &SessionUpdate,
    ) -> impl Future<Output = Result<bool, StoreError>> + Send;
    fn delete_session(
        &self,
        session_id: Uuid,
    ) -> impl Future<Output = Result<bool, StoreError>> + Send;
    fn delete_subject_sessions(
        &self,
        subject: &str,
    ) -> impl Future<Output = Result<Vec<Uuid>, StoreError>> + Send;
    fn list_subject_sessions(
        &self,
        subject: &str,
    ) -> impl Future<Output = Result<Vec<SessionRecord>, StoreError>> + Send;
    fn delete_expired(
        &self,
        now: DateTime<Utc>,
        idle_cutoff: DateTime<Utc>,
    ) -> impl Future<Output = Result<u64, StoreError>> + Send;
    fn record_event(
        &self,
        event: &SessionEvent,
    ) -> impl Future<Output = Result<(), StoreError>> + Send;
    fn delete_events_before(
        &self,
        cutoff: DateTime<Utc>,
    ) -> impl Future<Output = Result<u64, StoreError>> + Send;

    // Provided methods
    fn sharded(&self) -> bool { ... }
    fn claim_event(
        &self,
        scope: ClaimScope<'_>,
        kind: EventKind,
        now: DateTime<Utc>,
        window: TimeDelta,
    ) -> impl Future<Output = Result<bool, StoreError>> + Send { ... }
}
Expand description

Session persistence.

Every method must be safe to call concurrently from many processes. Each returned future must be Send. Timestamps may be stored at microsecond precision.

Required Methods§

Source

fn insert_session( &self, session: &SessionRecord, token: &TokenHash, ) -> impl Future<Output = Result<(), StoreError>> + Send

Stores a new session with token as its current token (issued_at = created_at, unused, not superseded).

Source

fn find_by_token( &self, token: &TokenHash, ) -> impl Future<Output = Result<Option<TokenLookup>, StoreError>> + Send

Finds the session holding token, current or superseded.

Source

fn apply( &self, update: &SessionUpdate, ) -> impl Future<Output = Result<bool, StoreError>> + Send

Applies update atomically, in this order:

  1. If rotation is set and its Supersede condition holds for the current token: supersede it, insert the new token as current, prune old superseded tokens.
  2. Mark mark_used used if it belongs to the session and is unused; this includes the token step 1 just inserted.
  3. Set last_seen_at = now and every Some field.

A session must never have more than one current token. Returns whether the rotation happened; a missing session is not an error and returns false.

Source

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

Deletes a session and its tokens. Returns whether it existed.

Source

fn delete_subject_sessions( &self, subject: &str, ) -> impl Future<Output = Result<Vec<Uuid>, StoreError>> + Send

Deletes every session of subject (canonical JSON). Returns the ids it deleted.

Source

fn list_subject_sessions( &self, subject: &str, ) -> impl Future<Output = Result<Vec<SessionRecord>, StoreError>> + Send

Every session of subject (canonical JSON), including expired ones not yet purged.

Source

fn delete_expired( &self, now: DateTime<Utc>, idle_cutoff: DateTime<Utc>, ) -> impl Future<Output = Result<u64, StoreError>> + Send

Deletes sessions with expires_at <= now or last_seen_at <= idle_cutoff. Returns how many.

Source

fn record_event( &self, event: &SessionEvent, ) -> impl Future<Output = Result<(), StoreError>> + Send

Appends a security event. Stores without an event log may discard it.

Source

fn delete_events_before( &self, cutoff: DateTime<Utc>, ) -> impl Future<Output = Result<u64, StoreError>> + Send

Deletes events with at < cutoff. Returns how many. Also deletes event claims older than cutoff.

Provided Methods§

Source

fn sharded(&self) -> bool

Whether the store partitions data into buckets that must be co-located.

When true, the guard gives every session an id whose session_bucket it picks, and mines each of the session’s tokens until its token_bucket is the same, so one session’s records always live together. The default, false, skips that work.

Source

fn claim_event( &self, scope: ClaimScope<'_>, kind: EventKind, now: DateTime<Utc>, window: TimeDelta, ) -> impl Future<Output = Result<bool, StoreError>> + Send

Claims the right to report a kind event for scope, for deduplication across processes. Succeeds (true) unless a claim for the same scope and kind was made after now - window, and records now as the new claim when it does. Session and subject claims are independent. Must be atomic across processes.

The guard claims ClaimScope::Session before recording an unenforced event (shadow_dedup_window) and ClaimScope::Subject before calling the hook for an enforced one (alert_dedup_window).

The default always succeeds, which leaves shadow deduplication to each process and disables alert deduplication.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementations on Foreign Types§

Source§

impl<T: SessionStore> SessionStore for Arc<T>

Source§

fn sharded(&self) -> bool

Source§

fn insert_session( &self, session: &SessionRecord, token: &TokenHash, ) -> impl Future<Output = Result<(), StoreError>> + Send

Source§

fn find_by_token( &self, token: &TokenHash, ) -> impl Future<Output = Result<Option<TokenLookup>, StoreError>> + Send

Source§

fn apply( &self, update: &SessionUpdate, ) -> impl Future<Output = Result<bool, StoreError>> + Send

Source§

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

Source§

fn delete_subject_sessions( &self, subject: &str, ) -> impl Future<Output = Result<Vec<Uuid>, StoreError>> + Send

Source§

fn list_subject_sessions( &self, subject: &str, ) -> impl Future<Output = Result<Vec<SessionRecord>, StoreError>> + Send

Source§

fn delete_expired( &self, now: DateTime<Utc>, idle_cutoff: DateTime<Utc>, ) -> impl Future<Output = Result<u64, StoreError>> + Send

Source§

fn record_event( &self, event: &SessionEvent, ) -> impl Future<Output = Result<(), StoreError>> + Send

Source§

fn delete_events_before( &self, cutoff: DateTime<Utc>, ) -> impl Future<Output = Result<u64, StoreError>> + Send

Source§

fn claim_event( &self, scope: ClaimScope<'_>, kind: EventKind, now: DateTime<Utc>, window: TimeDelta, ) -> impl Future<Output = Result<bool, StoreError>> + Send

Implementors§

Source§

impl SessionStore for MemoryStore

Source§

impl SessionStore for PgStore

Available on crate feature postgres only.
Source§

impl SessionStore for ValkeyStore

Available on crate feature valkey only.