### Default AxumSession Setup with PostgreSQL Source: https://github.com/ascendingcreations/axumsession/blob/main/README.md Demonstrates the default setup for AxumSession using a PostgreSQL database pool. This example initializes the session store, configures the session table name, and integrates the session layer into an Axum router. It also includes a basic greet route that increments a session counter. ```rust use sqlx::{ConnectOptions, postgres::{PgPoolOptions, PgConnectOptions}}; use std::net::SocketAddr; use axum_session::{Session, SessionPgPool, SessionConfig, SessionStore, SessionLayer}; use axum::{ Router, routing::get, }; use tokio::net::TcpListener; #[tokio::main] async fn main() { let pool = connect_to_database().await.unwrap(); //This Defaults as normal Cookies. //To enable signed cookies for integrity, and authenticity please check the enable_signed_cookies_headers Example. let session_config = SessionConfig::default() .with_table_name("sessions_table"); // create SessionStore and initiate the database tables let session_store = SessionStore::::new(Some(pool.clone().into()), session_config).await.unwrap(); // build our application with some routes let app = Router::new() .route("/greet", get(greet)) .layer(SessionLayer::new(session_store)); // run it let addr = SocketAddr::from(([0, 0, 0, 0], 8000)); println!("listening on {}", addr); let listener = TcpListener::bind(addr).await.unwrap(); axum::serve(listener, app).await.unwrap(); } async fn greet(session: Session) -> String { let mut count: usize = session.get("count").unwrap_or(0); count += 1; session.set("count", count); count.to_string() } async fn connect_to_database() -> anyhow::Result> { // ... unimplemented!() } ``` -------------------------------- ### Axum Application Setup with SessionLayer Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/layer-and-middleware.md Example of setting up an Axum application with SessionLayer. It initializes a SessionStore and applies the layer to the router. The handler function demonstrates extracting the session. ```rust use axum::{Router, routing::get}; use axum_session::{SessionConfig, SessionStore, SessionLayer, SessionNullPool}; #[tokio::main] async fn main() { let config = SessionConfig::default(); let store = SessionStore::::new(None, config) .await .unwrap(); let layer = SessionLayer::new(store); let app = Router::new() .route("/", get(handler)) .layer(layer); } async fn handler(session: Session) -> String { "OK".to_string() } ``` -------------------------------- ### Basic Axum Session Setup Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/layer-and-middleware.md Demonstrates the fundamental setup of AxumSession using SessionNullPool for in-memory session management. This is suitable for development or simple applications. ```rust use axum::{Router, routing::get}; use axum_session::{SessionConfig, SessionStore, SessionLayer, Session, SessionNullPool}; #[tokio::main] async fn main() { let config = SessionConfig::default(); let store = SessionStore::::new(None, config).await?; let app = Router::new() .route("/login", post(login_handler)) .route("/profile", get(profile_handler)) .layer(SessionLayer::new(store)); let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?; axum::serve(listener, app).await?; } ``` -------------------------------- ### REST Mode Request Example Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/features-and-integration.md Example of an HTTP GET request using the 'X-Session-ID' header for session authentication in REST mode. ```bash GET /api/profile HTTP/1.1 X-Session-ID: 550e8400-e29b-41d4-a716-446655440000 ``` -------------------------------- ### PostgreSQL Session Store Setup Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/features-and-integration.md Configure and initialize a session store using PostgreSQL with axum_session_sqlx. Specify a custom table name for sessions. ```rust use sqlx::PgPool; use axum_session_sqlx::PostgresSessionPool; let pool = PgPool::connect(database_url).await?; let pg_pool = PostgresSessionPool::new(pool); let config = SessionConfig::default() .with_table_name("user_sessions"); let store = SessionStore::new(Some(pg_pool), config).await?; ``` -------------------------------- ### SQLite Session Store Setup Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/features-and-integration.md Initialize a session store using an in-memory SQLite database with axum_session_sqlx. A custom table name can be provided. ```rust use sqlx::SqlitePool; use axum_session_sqlx::SqliteSessionPool; let pool = SqlitePool::connect("sqlite::memory:").await?; let sqlite_pool = SqliteSessionPool::new(pool); let config = SessionConfig::default() .with_table_name("sessions"); let store = SessionStore::new(Some(sqlite_pool), config).await?; ``` -------------------------------- ### REST Mode Response Example Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/features-and-integration.md Example of an HTTP response in REST mode, including the 'X-Session-ID' header with a new session ID. ```bash HTTP/1.1 200 OK X-Session-ID: 550e8400-e29b-41d4-a716-446655440001 Content-Type: application/json {"user": "alice"} ``` -------------------------------- ### MongoDB Session Store Setup Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/features-and-integration.md Integrate axum-session with MongoDB using axum_session_mongo. Requires a MongoDB client instance and a database name. ```rust use mongodb::Client; use axum_session_mongo::MongoSessionStore; let mongo = Client::with_uri_str(uri).await?; let mongo_store = MongoSessionStore::new(mongo, "mydb".to_string()); let config = SessionConfig::default() .with_table_name("sessions"); let store = SessionStore::new(Some(mongo_store), config).await?; ``` -------------------------------- ### Redis Session Store Setup Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/features-and-integration.md Set up a session store using Redis with axum_session_redispool. Redis automatically handles key expiry, so no explicit configuration is needed for it. ```rust use redis::Client; use axum_session_redispool::RedisPoolLayer; let redis = Client::open("redis://127.0.0.1/")?; let redis_pool = RedisPoolLayer::new(redis); // No additional config needed; Redis auto-handles expiry let config = SessionConfig::default(); let store = SessionStore::new(Some(redis_pool), config).await?; ``` -------------------------------- ### Full Counter App Example Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/quick-start.md A complete Axum application demonstrating session management for a counter. It includes setting up the session store, defining routes, and handling session data within handlers. ```rust use axum:: routing::{get, post}, Router, response::Html, Json, }; use axum_session::{Session, SessionConfig, SessionStore, SessionLayer, SessionNullPool}; use serde_json::json; use std::net::SocketAddr; use tokio::net::TcpListener; #[tokio::main] async fn main() -> Result<(), Box> { let config = SessionConfig::default(); let store = SessionStore::::new(None, config).await?; let app = Router::new() .route("/", get(index)) .route("/increment", post(increment)) .route("/get", get(get_count)) .layer(SessionLayer::new(store)); let listener = TcpListener::bind("0.0.0.0:3000").await?; println!("Listening on http://0.0.0.0:3000"); axum::serve(listener, app).await?; Ok(()) } async fn index() -> Html<&'static str> { Html(r#"

Counter

Count: 0

"#) } async fn increment(session: Session) { let count: u32 = session.get("count").unwrap_or(0); session.set("count", count + 1); } async fn get_count(session: Session) -> Json { let count: u32 = session.get("count").unwrap_or(0); Json(json!({ "count": count })) } ``` -------------------------------- ### SessionNullPool Usage Example Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/database-pools.md Demonstrates how to initialize a SessionStore using the SessionNullPool for in-memory session management. Note that auto_handles_expiry() returns false for this pool. ```rust let store = SessionStore::::new(None, config).await?; ``` -------------------------------- ### Advanced Session Verification Example Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/features-and-integration.md Demonstrates how to use the `verify` method from the 'advanced' feature to check session validity and handle different error cases, including renewing the session if it's old. ```rust #[cfg(feature = "advanced")] { match session.verify() { Ok(()) => println!("Session valid"), Err(SessionError::OldSessionError) => { session.renew(); } _ => {} } } ``` -------------------------------- ### SessionAnyPool Usage Example Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/database-pools.md Shows how to create a SessionAnyPool instance by dynamically choosing between different database pools (e.g., PostgreSQL or SQLite) based on a condition. The constructor accepts any type implementing the DatabasePool trait. ```rust let pool = if use_postgres { SessionAnyPool::new(postgres_pool) } else { SessionAnyPool::new(sqlite_pool) }; pub fn new(pool: Pool) -> Self where Pool: 'static + DatabasePool + Send + Sync ``` -------------------------------- ### PostgreSQL Connection Pooling with PgPoolOptions Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/database-pools.md Example of configuring and establishing a connection pool for PostgreSQL using `PgPoolOptions`. It sets the maximum number of connections to 20. Always use connection pools for performance. ```rust let pool = PgPoolOptions::new() .max_connections(20) .connect(database_url).await?; ``` -------------------------------- ### Axum Session with Redis Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/layer-and-middleware.md Configures AxumSession to use Redis for session storage. This example uses the `redis` crate and `RedisPoolLayer` for connection pooling. ```rust use redis::Client; use axum_session_redispool::RedisPoolLayer; #[tokio::main] async fn main() { let redis = Client::open("redis://127.0.0.1/").unwrap(); let redis_pool = RedisPoolLayer::new(redis); let session_config = SessionConfig::default(); let store = SessionStore::new(Some(redis_pool), session_config).await?; let layer = SessionLayer::new(store); let app = Router::new() .route("/", get(handler)) .layer(layer); } ``` -------------------------------- ### Session Data Serialization Example Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/types.md Demonstrates how session data, including primitive types and vectors, are stored as JSON strings. This shows the conversion of Rust types into their JSON string representations within the session. ```rust session.set("user_id", 42u64); // Stored as: {"user_id": "42"} session.set("tags", vec!["a", "b"]); // Stored as: {"tags": "[\"a\",\"b\"]"} ``` -------------------------------- ### Session Data Deserialization Example Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/types.md Illustrates how session data, stored as JSON strings, is retrieved and deserialized back into Rust types. This covers basic types and vectors, showing the reverse process of serialization. ```rust let user_id: Option = session.get("user_id"); // Deserializes from "42" to 42 let tags: Option> = session.get("tags"); // Deserializes from "[\"a\",\"b\"]" to vec!["a", "b"] ``` -------------------------------- ### Retrieve Session Name Configuration Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/configuration.md Retrieves the current session name from the configuration. Use this to get the configured session name. ```rust let config = SessionConfig::default() .with_session_name("my_session"); let name = config.get_session_name(); assert_eq!(name, "my_session"); ``` -------------------------------- ### Handling Database Errors during Session Cleanup Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/errors.md Provides an example of catching `SessionError::DatabaseError` during a session cleanup operation. This allows for specific logging or recovery actions when database issues arise. ```rust match store.cleanup().await { Err(SessionError::DatabaseError(db_err)) => { eprintln!("Database error: {}", db_err); } Ok(deleted) => println!("Deleted {} sessions", deleted.len()), } ``` -------------------------------- ### Unit Test Session Storage Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/features-and-integration.md Tests the basic functionality of setting and getting session data. Ensures that session values are stored and retrieved correctly. ```rust #[cfg(test)] mod tests { use super::*; use axum_session::{SessionConfig, SessionStore, SessionNullPool}; #[tokio::test] async fn test_session_storage() { let config = SessionConfig::default(); let store = SessionStore::::new(None, config) .await .unwrap(); let (session, _) = Session::new(store, None).await.unwrap(); session.set("key", "value"); assert_eq!(session.get::("key"), Some("value".to_string())); } } ``` -------------------------------- ### Axum Session High Performance Configuration Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/features-and-integration.md Configure axum_session with key-store features for high performance. This setup includes bloom filter and database update interval settings. ```rust let config = SessionConfig::default() .with_bloom_filter(true) .with_filter_expected_elements(10_000_000) .with_always_save(false) .with_db_update_interval(Duration::seconds(30)); ``` -------------------------------- ### Enable Signed Cookies with a Generated Key Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/security.md Use this to enable HMAC-SHA256 signed cookies. A new ephemeral key is generated on each application start, invalidating all previous sessions. ```rust use axum_session::Key; use axum_session::SessionConfig; let config = SessionConfig::default() .with_key(Key::generate()); ``` -------------------------------- ### SQL Schema for Sessions Table Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/database-pools.md An example SQL schema for a 'sessions' table, suitable for storing session data. It includes columns for session ID, data, expiration timestamp, and creation time. ```sql CREATE TABLE sessions ( id VARCHAR(255) PRIMARY KEY, data TEXT NOT NULL, expires BIGINT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ``` -------------------------------- ### new Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/session-store.md Constructs a new SessionStore. It optionally connects to a database and creates the necessary table if a client is provided. Configuration for sessions is required. ```APIDOC ## new ### Description Constructs a new SessionStore and creates the database table if client is provided. ### Method `async fn new(client: Option, config: SessionConfig) -> Result` ### Parameters #### Path Parameters - **client** (Option) - Required - Optional database pool implementation - **config** (SessionConfig) - Required - Session configuration ### Response #### Success Response (Result) - Returns `Ok(Self)` on successful construction. #### Error Response (SessionError) - `SessionError::DatabaseError` - Database initialization failed. ### Example ```rust use axum_session::{SessionConfig, SessionStore, SessionNullPool}; #[tokio::main] async fn main() { let config = SessionConfig::default(); let store = SessionStore::::new(None, config) .await .unwrap(); } ``` ``` -------------------------------- ### Get Session ID Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/session.md Returns the unique identifier (UUID) for the current session. ```rust pub fn get_session_id(&self) -> String ``` ```rust let id = session.get_session_id(); println!("Session ID: {}", id); ``` -------------------------------- ### Get Mutable Session Store Reference Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/session.md Returns a mutable reference to the session store, allowing modifications to its contents. ```rust pub fn get_mut_store(&mut self) -> &mut SessionStore ``` ```rust let mut store = session.get_mut_store(); ``` -------------------------------- ### Initialize Session Store and Layer Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/index.md Configure the session store with a secret key and database table name, then create a SessionStore instance. Finally, add the SessionLayer to your Axum router. ```rust let config = SessionConfig::default() .with_key(Key::generate()) .with_table_name("sessions"); let store = SessionStore::::new( Some(db_pool), config, ).await?; let app = Router::new() .route("/", get(handler)) .layer(SessionLayer::new(store)); ``` -------------------------------- ### get Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/session-store.md Retrieves a specific value from session data using the session ID and a key. The value is deserialized into the specified type `T`. ```APIDOC ## get ### Description Retrieves a value from session data by ID and key. ### Method `fn get(&self, id: String, key: &str) -> Option` ### Parameters #### Path Parameters - **id** (String) - Required - Session ID - **key** (&str) - Required - Data key ### Return Type `Option` - The deserialized value if found, otherwise `None`. ``` -------------------------------- ### ReadOnlySession Get Method Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/session.md Retrieves data associated with a given key from the session. This method is identical in functionality to Session::get(). ```rust pub fn get(&self, key: &str) -> Option ``` -------------------------------- ### Initialize SQLx Session Store Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/quick-start.md Initialize the AxumSession store with a SQLx PostgreSQL pool and a custom table name. ```rust use axum_session::{SessionConfig, SessionStore}; #[tokio::main] async fn main() -> Result<(), Box> { let pool = create_pool().await?; let pg_pool = PostgresSessionPool::new(pool); let config = SessionConfig::default() .with_table_name("user_sessions"); let store = SessionStore::new(Some(pg_pool), config).await?; // ... use store Ok(()) } ``` -------------------------------- ### Get and Remove Session Data Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/session.md Removes a key from the session and returns its deserialized value. Returns None if the key is not present. ```rust pub fn get_remove(&self, key: &str) -> Option ``` ```rust let csrf_token: Option = session.get_remove("csrf"); if csrf_token.is_some() { // Token was consumed } ``` -------------------------------- ### Initialize Session Store Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/session-store.md Constructs a new SessionStore. Creates the database table if a client is provided. Use with `SessionNullPool` for basic in-memory storage or with a database pool for persistent storage. ```rust use axum_session::{SessionConfig, SessionStore, SessionNullPool}; #[tokio::main] async fn main() { let config = SessionConfig::default(); let store = SessionStore::::new(None, config) .await .unwrap(); } ``` -------------------------------- ### Create Database Pool Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/quick-start.md Establish a connection pool to your PostgreSQL database using SQLx. ```rust use sqlx::PgPool; use axum_session_sqlx::PostgresSessionPool; async fn create_pool() -> Result { PgPool::connect("postgres://user:pass@localhost/sessions").await } ``` -------------------------------- ### SQL Query: delete_by_expiry Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/database-pools.md An example SQL query to remove expired sessions from the database. It compares the 'expires' column with the current Unix timestamp. ```sql DELETE FROM sessions WHERE expires < (SELECT EXTRACT(EPOCH FROM NOW())::BIGINT) RETURNING id ``` -------------------------------- ### Runtime Database Selection for Sessions Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/features-and-integration.md Dynamically select the database backend for session storage at runtime based on build configurations (e.g., debug vs. release). ```rust use axum_session::SessionAnyPool; let pool = if cfg!(debug_assertions) { SessionAnyPool::new(SqliteSessionPool::new(sqlite_pool)) } else { SessionAnyPool::new(PostgresSessionPool::new(postgres_pool)) }; let config = SessionConfig::default(); let store = SessionStore::new(Some(pool), config).await?; ``` -------------------------------- ### Get and Remove Session Value Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/session-store.md Removes a key-value pair from session data and returns the associated value. The value is deserialized into the specified type `T`. ```rust pub fn get_remove( &self, id: String, key: &str ) -> Option ``` -------------------------------- ### Get Session Value Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/session-store.md Retrieves a specific value from session data using the session ID and a data key. The value is deserialized into the specified type `T`. ```rust pub fn get( &self, id: String, key: &str ) -> Option ``` -------------------------------- ### Manually Create Service with Session Layer Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/layer-and-middleware.md For advanced use cases, manually create a service by applying the SessionLayer to a handler using `ServiceBuilder`. Axum's `.layer()` is generally recommended. ```rust use axum::service::ServiceBuilder; use tower::Layer; let layer = SessionLayer::new(store); let service = layer.layer(handler); ``` -------------------------------- ### initiate Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/database-pools.md Creates the session storage table/collection if it doesn't exist. This method is called once during SessionStore::new() initialization and should be idempotent. ```APIDOC ## initiate ### Description Creates the session storage table/collection if it doesn't exist. ### Method Signature `async fn initiate(&self, table_name: &str) -> Result<(), DatabaseError>` ### Parameters #### Path Parameters - **table_name** (str) - Required - Table or collection name from config ### Return Type `Result<(), DatabaseError>` ### Errors - `DatabaseError::GenericCreateError` if table creation fails ``` -------------------------------- ### Get Immutable Session Store Reference Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/session.md Returns an immutable reference to the session store. This allows inspecting the store's properties without modifying them. ```rust pub fn get_store(&self) -> &SessionStore ``` ```rust let store = session.get_store(); let is_persistent = store.is_persistent(); ``` -------------------------------- ### Get Session Data Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/session.md Retrieves data from the session by key. The data must be deserializable from JSON. Returns None if the key is not found or deserialization fails. ```rust pub fn get(&self, key: &str) -> Option ``` ```rust async fn handler(session: Session) -> String { let user_id: Option = session.get("user_id"); match user_id { Some(id) => format!("User: {}", id), None => "No user".to_string(), } } ``` -------------------------------- ### Rust Function Signature: initiate Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/database-pools.md This method is called once during SessionStore initialization to create the session storage table or collection if it does not already exist. It is designed to be idempotent. ```rust async fn initiate(&self, table_name: &str) -> Result<(), DatabaseError> ``` -------------------------------- ### Use Session in Handlers Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/quick-start.md Access and modify session data within your Axum handlers. This example demonstrates reading a count, incrementing it, and returning the new value. ```rust use axum_session::Session; async fn handler(session: Session) -> String { // Read let count: u32 = session.get("count").unwrap_or(0); // Write session.set("count", count + 1); format!("Count: {}", count + 1) } ``` -------------------------------- ### Axum Nested Routes with Session Middleware Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/features-and-integration.md Demonstrates setting up nested Axum routes with a session-based authentication middleware. ```rust use axum::{routing::post, Router}; let protected = Router::new() .route("/profile", get(profile)) .route("/logout", post(logout)) .layer(axum::middleware::from_fn(auth_middleware)); let app = Router::new() .route("/login", post(login)) .nest("/api", protected) .layer(SessionLayer::new(store)); async fn auth_middleware( session: Session, mut req: Request, next: Next, ) -> Result { match session.get::("user_id") { Some(_) => Ok(next.run(req).await), None => Err(StatusCode::UNAUTHORIZED), } } ``` -------------------------------- ### Generate and Use Key Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/types.md Demonstrates how to generate an ephemeral cryptographic key or create one from a byte array. The key is used for cookie signing and encryption. ```rust // Generate ephemeral key (loses validity on restart) let key = Key::generate(); // From bytes (32 bytes for signing and encryption) let key = Key::from([0u8; 32]); ``` -------------------------------- ### Custom IdGenerator Implementation Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/types.md Provides an example of a custom IdGenerator implementation using an atomic counter to generate sequential session IDs. This custom generator can be configured with SessionConfig. ```rust use axum_session::IdGenerator; #[derive(Debug)] struct CustomSessionId { counter: std::sync::atomic::AtomicU64, } impl IdGenerator for CustomSessionId { fn generate(&self) -> String { let id = self.counter.fetch_add(1, std::sync::atomic::Ordering::SeqCst); format!("session_{{", id) } } // Usage let config = SessionConfig::default() .with_id_generator(CustomSessionId { counter: std::sync::atomic::AtomicU64::new(1), }); ``` -------------------------------- ### Add Axum Session Dependency Source: https://github.com/ascendingcreations/axumsession/blob/main/README.md Include the axum_session crate in your Cargo.toml to add session management to your Axum project. This example shows the basic dependency for Postgres with rustls. ```toml # Cargo.toml [dependencies] # Postgres + rustls axum_session = { version = "0.19.0" } ``` -------------------------------- ### Axum Session with SQLx (PostgreSQL) Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/layer-and-middleware.md Integrates AxumSession with a PostgreSQL database using SQLx for persistent session storage. Requires a `PgPool` and `PostgresSessionPool`. ```rust use sqlx::postgres::PgPool; use axum_session_sqlx::PostgresSessionPool; #[tokio::main] async fn main() { let database_url = "postgres://user:password@localhost/sessions_db"; let pool = PgPool::connect(database_url).await?; let pg_session_pool = PostgresSessionPool::new(pool); let session_config = SessionConfig::default() .with_table_name("sessions"); let store = SessionStore::new(Some(pg_session_pool), session_config).await?; let layer = SessionLayer::new(store); let app = Router::new() .route("/", get(handler)) .layer(layer); } ``` -------------------------------- ### Get Total Session Count Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/session.md Returns the total number of active sessions. The behavior depends on the session storage: it retrieves the count from the database if persistent, otherwise from memory. ```rust pub async fn count(&self) -> i64 ``` ```rust let total = session.count().await; println!("Total sessions: {}", total); ``` -------------------------------- ### Add Database Dependencies Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/quick-start.md Add the necessary dependencies to your Cargo.toml file for database persistence with PostgreSQL. ```toml [dependencies] axum_session = "0.20" axum_session_sqlx = { version = "0.20", features = ["postgres"] } sqlx = { version = "0.8", features = ["postgres", "runtime-tokio-rustls"] } ``` -------------------------------- ### Create Memory-Only Session Store Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/quick-start.md Initialize a default session configuration and create a memory-only session store. This is suitable for development or simple use cases. ```rust use axum_session::{SessionConfig, SessionStore, SessionNullPool}; #[tokio::main] async fn main() -> Result<(), Box> { // Create config with defaults let config = SessionConfig::default(); // Create store (None = no database) let store = SessionStore::::new(None, config).await?; Ok(()) } ``` -------------------------------- ### HMAC Signature with IP and User-Agent Components Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/security.md Demonstrates how the HMAC signature is constructed when IP and User-Agent binding is enabled. It concatenates relevant client information before updating the MAC. ```rust // Built from enabled components and included in HMAC signature let message = format!( "{ "} ip_value, // if use_ip xforward_value, // if use_xforward_ip forward_value, // if use_forward_ip real_ip_value, // if use_real_ip user_agent_value // if use_user_agent ); mac.update(format!("{}{}", cookie_value, message).as_bytes()); ``` -------------------------------- ### Key Methods Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/types.md Provides access to the signing and encryption material stored within the Key struct. These methods are internal to session management. ```rust // Public API (internal to session management) pub fn signing(&self) -> &[u8; 32] // Returns signing key material pub fn encryption(&self) -> &[u8; 32] // Returns encryption key material ``` -------------------------------- ### Load a Persistent Key from Configuration Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/security.md Loads a pre-defined 32-byte key from configuration for signing session cookies. This key is persistent across application restarts, maintaining session validity. ```rust // Load from configuration (persistent) let key = Key::from([/* 32 bytes */]); ``` -------------------------------- ### Conditional Session Creation (Opt-In Mode) Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/layer-and-middleware.md Use SessionMode::OptIn to control session persistence. Sessions are only persisted if `session.set_store(true)` is explicitly called, typically for authenticated users. ```rust let config = SessionConfig::default() .with_mode(SessionMode::OptIn); async fn maybe_persist(session: Session) -> String { let user_id = session.get::("user_id"); if user_id.is_some() { session.set_store(true); // Persist only for logged-in users } "OK".to_string() } ``` -------------------------------- ### Handle NoSessionError in Advanced Feature Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/errors.md This snippet demonstrates how to handle a `NoSessionError` which occurs when a session does not exist or has been unloaded. The example shows creating a new session if verification fails due to a missing session. ```rust #[cfg(feature = "advanced")] pub fn verify(&self) -> Result<(), SessionError> { // Returns NoSessionError if session not found } ``` ```rust match session.verify() { Err(SessionError::NoSessionError) => { eprintln!("Session expired, creating new"); session.create_data(); } _ => {} } ``` -------------------------------- ### Create Session Data (Manual Mode) Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/session.md Creates the session data structure. This method is only usable when the `SessionMode` is set to `Manual`. It will panic if called in any other mode. ```rust pub fn create_data(&self) ``` ```rust if session_mode.is_manual() { session.create_data(); } ``` -------------------------------- ### Configure Session with Signed Key Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/quick-start.md Configure AxumSession to use a generated or loaded key for signing, and enable secure and HTTP-only flags. ```rust let config = SessionConfig::default() .with_key(key) .with_secure(true) // HTTPS only .with_http_only(true); // No JS access ``` -------------------------------- ### Production Session Configuration Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/security.md Configure session settings for production environments, including signing, transport security, binding, and expiration. Ensure keys are loaded from secure configuration. ```rust let config = SessionConfig::default() // Signing .with_key(Key::from([/* loaded from secure config */])) .with_database_key(Key::from([/* loaded from secure config */])) // Transport Security .with_secure(true) // HTTPS only .with_http_only(true) // No JS access .with_prefix_with_host(true) // Host prefix .with_cookie_same_site(SameSite::Lax) // CSRF protection // Binding .with_ip_and_user_agent(true) .with_hashed_ip(true) .with_hashed_user_agent(true) // Expiration .with_lifetime(Duration::hours(2)) .with_memory_lifetime(Duration::minutes(30)) // ID Renewal // Call session.renew() after login // Bloom Filter .with_bloom_filter(true) .with_filter_false_positive_probability(0.01); ``` -------------------------------- ### Enable IP and User-Agent Binding Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/security.md Enables binding session signatures to the client's IP address and User-Agent string. This helps prevent session hijacking by ensuring the session originates from the same client context. ```rust let config = SessionConfig::default() .with_key(Key::generate()) .with_ip_and_user_agent(true); // Default: enabled ``` -------------------------------- ### Handling IO Errors in Session Loading Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/errors.md Demonstrates how to match and handle `SessionError::IO` specifically when loading a session. This is useful for diagnosing file system related issues. ```rust match store.load_session(id).await { Err(SessionError::IO(io_err)) => eprintln!("File error: {}", io_err), _ => {} } ``` -------------------------------- ### Handle OldSessionError in Advanced Feature Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/errors.md This snippet shows how to handle an `OldSessionError`, indicating that a session exists but is outdated (expired or not yet loaded). The example demonstrates renewing the session if verification fails due to it being old. ```rust #[cfg(feature = "advanced")] pub fn verify(&self) -> Result<(), SessionError> { // Returns OldSessionError if expired } ``` ```rust match session.verify() { Err(SessionError::OldSessionError) => { eprintln!("Session expired, renewing"); session.renew(); } _ => {} } ``` -------------------------------- ### Read and Write Session Data in Handlers Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/index.md Access session data within an Axum request handler using the injected Session type. You can get values by key, set new values, and update the session. The session is automatically saved when a response is returned. ```rust async fn handler( session: Session, ) -> impl IntoResponse { // Read session data let user_id: Option = session.get("user_id"); // Write session data session.set("last_request", Utc::now()); // Update and persist session.update(); // Session automatically saved on response (StatusCode::OK, "OK") } ``` -------------------------------- ### SessionLayer Constructor Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/layer-and-middleware.md Creates a new SessionLayer with a configured session store. Requires a SessionStore instance. ```rust pub fn new(session_store: SessionStore) -> Self> ``` -------------------------------- ### Add axum_session_redis_bb8_pool to Cargo.toml Source: https://github.com/ascendingcreations/axumsession/blob/main/databases/redis-bb8-pool/README.md Add the axum_session and axum_session_redis_bb8_pool crates to your Cargo.toml file to include the necessary dependencies for your project. ```toml # Cargo.toml [dependencies] axum_session = { version = "0.19.0" } axum_session_redis_bb8_pool = { version = "0.7.0" } ``` -------------------------------- ### Login Handler with Session Management Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/quick-start.md Handles user login, validates credentials, sets session variables, and renews the session to prevent fixation. ```rust use axum::{http::StatusCode, Json}; use serde::{Deserialize, Serialize}; #[derive(Deserialize)] struct LoginRequest { username: String, password: String, } #[derive(Serialize)] struct LoginResponse { success: bool, } async fn login( session: Session, Json(req): Json, ) -> (StatusCode, Json) { // Validate credentials if validate_credentials(&req.username, &req.password) { // Store user info session.set("user_id", 42); session.set("username", &req.username); // Prevent session fixation session.renew(); return ( StatusCode::OK, Json(LoginResponse { success: true }), ); } ( StatusCode::UNAUTHORIZED, Json(LoginResponse { success: false }), ) } fn validate_credentials(username: &str, password: &str) -> bool { // Your validation logic username == "admin" && password == "secret" } ``` -------------------------------- ### SessionConfig Constructor and Default Implementation Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/configuration.md Provides methods to create a new SessionConfig instance with default values. ```rust pub fn new() -> Self impl Default for SessionConfig ``` -------------------------------- ### Custom Type Serialization and Deserialization Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/types.md Shows how to store and retrieve custom Rust types from the session, provided they implement `serde::Serialize` and `serde::Deserialize`. This enables flexible data storage within the session. ```rust #[derive(Serialize, Deserialize)] struct User { id: u64, name: String, } session.set("current_user", User { id: 1, name: "Alice".into() }); let user: Option = session.get("current_user"); ``` -------------------------------- ### Set Session Mode Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/configuration.md Configures the session creation behavior (Manual, OptIn, or Persistent). ```rust pub fn with_mode(mut self, mode: SessionMode) -> Self ``` ```rust let config = SessionConfig::default() .with_mode(SessionMode::OptIn); ``` -------------------------------- ### Enable Key Store Feature with Bloom Filter Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/features-and-integration.md Enable the 'key-store' feature to use a Bloom filter for session ID deduplication during generation, improving performance and reducing database load. ```toml [dependencies] axum_session = { version = "0.20", features = ["key-store"] } ``` -------------------------------- ### Add axum_session_redispool to Cargo.toml Source: https://github.com/ascendingcreations/axumsession/blob/main/databases/redispool/README.md Add the axum_session and axum_session_redispool crates to your Cargo.toml file to include them in your project. ```toml # Cargo.toml [dependencies] axum_session = { version = "0.19.0" } axum_session_redispool = { version = "0.10.0" } ``` -------------------------------- ### Add axum_session_surreal Dependency Source: https://github.com/ascendingcreations/axumsession/blob/main/databases/surreal/README.md Add the axum_session and axum_session_surreal crates to your Cargo.toml file to include the SurrealDB persistent store for AxumSession. ```toml # Cargo.toml [dependencies] axum_session = { version = "0.19.0" } axum_session_surreal = { version = "0.7.0" } ``` -------------------------------- ### High-Performance Session Configuration Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/quick-start.md Configure session for high performance with extended lifetimes and optimized saving intervals. Suitable for applications prioritizing speed and availability over immediate persistence. ```rust let config = SessionConfig::default() .with_lifetime(Duration::hours(24)) .with_memory_lifetime(Duration::hours(6)) .with_always_save(false) .with_db_update_interval(Duration::seconds(30)) .with_purge_update(Duration::hours(24)) .with_bloom_filter(true) .with_filter_expected_elements(1_000_000); ``` -------------------------------- ### with_key Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/configuration.md Enables cookie signing for integrity and authenticity. ```APIDOC ## with_key ### Description Enables cookie signing using a provided key to ensure the integrity and authenticity of session cookies. ### Method `with_key(key: Key) -> Self` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **key** (Key) - Required - The signing key used for cookie integrity. **Important:** Regenerate annually; a new key invalidates all old sessions. ### Request Example ```rust use axum_session::Key; let config = SessionConfig::default() .with_key(Key::generate()); ``` ### Response #### Success Response (200) N/A #### Response Example N/A ``` -------------------------------- ### Enable Database Encryption Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/security.md Configure session management to use a generated key for encrypting session data stored in the database. ```rust use axum_session::Key; use axum_session::SessionConfig; let config = SessionConfig::default() .with_database_key(Key::generate()); ``` -------------------------------- ### Enable __Host- Cookie Prefix Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/security.md Use `with_prefix_with_host(true)` to restrict cookies to HTTPS and prevent subdomain usage. Ensure the secure flag is true and the cookie path is '/'. ```rust let config = SessionConfig::default() .with_key(Key::generate()) .with_secure(true) .with_prefix_with_host(true); ``` -------------------------------- ### Enable Cookie Signing Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/configuration.md Configures a signing key for session cookies to ensure integrity and authenticity. The key should be regenerated annually. ```rust use axum_session::Key; let config = SessionConfig::default() .with_key(Key::generate()); ``` -------------------------------- ### SessionLayer Constructor Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/layer-and-middleware.md Initializes a new SessionLayer with a configured session store. This layer integrates session management into Axum's request handling pipeline. ```APIDOC ## SessionLayer::new ### Description Creates a new `SessionLayer` instance. ### Method `SessionLayer::new(session_store: SessionStore) -> Self` ### Parameters #### Path Parameters - **session_store** (SessionStore) - Required - Configured session store ### Request Example ```rust use axum_session::{SessionStore, SessionLayer, SessionNullPool}; // Assuming session_store is already initialized let session_store = SessionStore::::new(None, SessionConfig::default()).await.unwrap(); let layer = SessionLayer::new(session_store); ``` ### Response #### Success Response (SessionLayer) - **Self** - Returns a new `SessionLayer` instance. ``` -------------------------------- ### Add axum_session_sqlx to Cargo.toml Source: https://github.com/ascendingcreations/axumsession/blob/main/databases/sqlx/README.md Include axum_session and axum_session_sqlx in your Cargo.toml. Specify features for database and TLS support. Defaults to postgres and rustls. ```toml # Cargo.toml [dependencies] axum_session = { version = "0.20.0" } # Postgres + rustls axum_session_sqlx = { version = "0.10.0", features = [ "postgres", "tls-rustls"] } ``` -------------------------------- ### SessionData Construction Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/types.md Constructor for SessionData. Initializes expiration, autoremove times, and sets initial state based on provided configuration and parameters. ```rust impl SessionData { pub(crate) fn new( id: String, storable: bool, config: &SessionConfig ) -> Self } ``` -------------------------------- ### Configure AxumSession for High Throughput Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/index.md Use these settings to optimize AxumSession for scenarios requiring high throughput. This configuration batches writes and reduces database lookups. ```rust let config = SessionConfig::default() .with_always_save(false) // Skip update checks .with_db_update_interval(Duration::seconds(30)) // Batch writes .with_purge_update(Duration::hours(24)) // Less frequent cleanup .with_memory_lifetime(Duration::hours(6)) // Keep in memory longer .with_bloom_filter(true) // Reduce DB lookups .with_filter_expected_elements(10_000_000); ``` -------------------------------- ### Add AxumSession Dependency Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/quick-start.md Add the necessary dependencies to your Cargo.toml file to use AxumSession. ```toml [dependencies] axum = "0.8" axum_session = "0.20" tokio = { version = "1", features = ["full"] } chrono = { version = "0.4", features = ["serde"] } ``` -------------------------------- ### Configuring Cookie Domain and Path Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/quick-start.md Set the cookie domain and path to ensure cookies persist correctly across your application. Adjust these values to match your domain and URL structure to prevent 'Cookies Not Persisting' errors. ```rust let config = SessionConfig::default() .with_cookie_domain("example.com") .with_cookie_path("/"); ``` -------------------------------- ### get_store Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/session.md Returns an immutable reference to the session store. ```APIDOC ## get_store ### Description Returns a reference to the session store. ### Method `get_store` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```rust let store = session.get_store(); let is_persistent = store.is_persistent(); ``` ### Response #### Success Response - **Return Type:** `&SessionStore` - Immutable reference to the store #### Response Example None ``` -------------------------------- ### with_ip_and_user_agent Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/configuration.md Includes the client's IP address and user agent in the cookie signing process. This helps prevent session hijacking by ensuring the session is tied to a specific client context. ```APIDOC ## with_ip_and_user_agent ### Description Enables IP/user agent inclusion in cookie signing. ### Method ```rust pub fn with_ip_and_user_agent(mut self, enable: bool) -> Self ``` ### Parameters #### Path Parameters - **enable** (bool) - Required - Include IP/UA in signature. Default: true. **Purpose:** Prevents cookie spoofing across different client contexts ``` -------------------------------- ### Configure Opt-In Session Mode Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/quick-start.md Set the session mode to OptIn to store sessions only when explicitly requested by the user, for features like 'Remember Me'. ```rust use axum_session::SessionMode; let config = SessionConfig::default() .with_mode(SessionMode::OptIn); ``` -------------------------------- ### Generate or Load Session Key Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/quick-start.md Generate a new cryptographic key for signing sessions or load an existing one from configuration. ```rust use axum_session::Key; // Generate once (invalidates all sessions on restart) let key = Key::generate(); // Or load from configuration let key = Key::from([/* 32 bytes */]); ``` -------------------------------- ### Set Cookie Domain Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/configuration.md Configures the domain for the cookie. Defaults to None. ```rust pub fn with_cookie_domain(mut self, name: impl Into>) -> Self ``` ```rust let config = SessionConfig::default() .with_cookie_domain("example.com"); ``` -------------------------------- ### Default CookieAndHeaderConfig Implementation Source: https://github.com/ascendingcreations/axumsession/blob/main/_autodocs/types.md Provides default values for `CookieAndHeaderConfig`, setting common configurations like session name, cookie path, max age, and security flags. ```rust impl Default for CookieAndHeaderConfig { fn default() -> Self { Self { session_name: "session".into(), cookie_path: "/".into(), cookie_max_age: Some(Duration::days(100)), cookie_http_only: true, cookie_secure: false, cookie_domain: None, cookie_same_site: SameSite::Lax, store_name: "store".into(), key: None, prefix_with_host: false, with_ip_and_user_agent: true, } } } ```