Skip to main content

siderite_sessions/
lib.rs

1//! Cookie sessions and CSRF tokens for siderite applications.
2//!
3//! This crate is an adapter: it owns cookie mechanics, id generation,
4//! rotation, expiry and CSRF tokens, and nothing about identity. Users,
5//! login flows and password storage stay in the application, which calls
6//! [`Session::login`] once it has authenticated someone. Nothing in
7//! `siderite-core` depends on it.
8//!
9//! - [`SessionLayer`] loads the session named by the cookie, exposes it as
10//!   the [`Session`] extractor and writes changes back.
11//! - [`SessionConfig`] sets cookie flags (`__Host-` name, `HttpOnly`,
12//!   `Secure`, `Path=/`, `SameSite=Lax`), lifetimes and the CSRF key.
13//! - [`SessionStore`] is the storage trait. Stores only ever see the
14//!   SHA-256 hex of a session id ([`id_hash`]). [`MemoryStore`] is
15//!   included; [`CacheStore`] (feature `cache`) uses any
16//!   `siderite_cache::Cache`, Redis included.
17//!
18//! The requirements this crate implements are in
19//! `docs/plans/SESSIONS_CSRF.md`. For cross-site request forgery pair it
20//! with [`siderite_core::middleware::CsrfOrigin`]; add a CSRF token for
21//! forms and for `SameSite=None`.
22//!
23//! ```no_run
24//! use siderite_core::{App, get, post};
25//! use siderite_sessions::{
26//!     MemoryStore, Session, SessionConfig, SessionLayer,
27//! };
28//!
29//! async fn login(session: Session) -> &'static str {
30//!     // ...authenticate the user first...
31//!     session.login("ada");
32//!     "welcome"
33//! }
34//!
35//! async fn me(session: Session) -> String {
36//!     session.user().unwrap_or_else(|| "anonymous".into())
37//! }
38//!
39//! # async fn run() -> Result<(), Box<dyn std::error::Error>> {
40//! let store = MemoryStore::default();
41//! let layer = SessionLayer::new(store, SessionConfig::new())?;
42//! App::new()
43//!     .route("/login", post(login))
44//!     .route("/me", get(me))
45//!     .layer(layer)
46//!     .run("0.0.0.0:8000")
47//!     .await?;
48//! # Ok(())
49//! # }
50//! ```
51#![forbid(unsafe_code)]
52
53#[cfg(feature = "cache")]
54mod cache_store;
55mod config;
56mod id;
57mod layer;
58mod memory;
59mod session;
60mod store;
61mod token;
62
63#[cfg(feature = "cache")]
64pub use cache_store::CacheStore;
65pub use config::{SessionConfig, SessionConfigError};
66pub use id::id_hash;
67pub use layer::SessionLayer;
68pub use memory::MemoryStore;
69pub use session::Session;
70pub use siderite_core::SameSite;
71pub use store::{SessionRecord, SessionStore, StoreError};