Skip to main content

codlet_core/store/
session.rs

1//! Session storage trait (RFC-006).
2
3use std::future::Future;
4
5use crate::hashing::{KeyVersion, LookupKey};
6use crate::secret::{SessionId, SubjectId};
7
8use super::error::StoreError;
9
10/// An active session record returned by validation.
11#[derive(Debug, Clone)]
12pub struct ActiveSessionRecord {
13    /// Opaque session record identifier (not a bearer credential).
14    pub id: SessionId,
15    /// The subject this session authenticates.
16    pub subject: SubjectId,
17    /// Expiry as Unix seconds (UTC).
18    pub expires_at: u64,
19}
20
21/// Parameters for inserting a new session.
22pub struct SessionRecord {
23    /// Store-assigned identifier.
24    pub id: SessionId,
25    /// Domain-separated HMAC of the session secret.
26    pub lookup_key: LookupKey,
27    /// Key version that produced `lookup_key`.
28    pub key_version: KeyVersion,
29    /// The authenticated subject.
30    pub subject: SubjectId,
31    /// Creation time as Unix seconds (UTC).
32    pub created_at: u64,
33    /// Expiry as Unix seconds (UTC).
34    pub expires_at: u64,
35}
36
37/// Session storage (RFC-006).
38///
39/// Sessions are stored by their HMAC lookup key, never by the plaintext secret.
40/// The plaintext lives only in the cookie.
41pub trait SessionStore {
42    /// Look up an active session by HMAC lookup key candidates.
43    ///
44    /// Returns the first record matching any candidate that is not expired and
45    /// not revoked at `now`. Returns `Ok(None)` if no such session exists.
46    fn find_active_session(
47        &self,
48        candidates: &[LookupKey],
49        now: u64,
50    ) -> impl Future<Output = Result<Option<ActiveSessionRecord>, StoreError>>;
51
52    /// Insert a new session record.
53    fn insert_session(&self, record: SessionRecord)
54    -> impl Future<Output = Result<(), StoreError>>;
55
56    /// Revoke a session by its record ID (logout / incident response).
57    /// Revocation is monotonic: a revoked session cannot be unrevoked.
58    fn revoke_session(
59        &self,
60        session_id: &SessionId,
61        now: u64,
62    ) -> impl Future<Output = Result<(), StoreError>>;
63}