Use Cookies to Store session information, see Response from FhGenie #9

Open
opened 2025-10-09 06:02:23 +00:00 by adrien · 0 comments
Owner

Do you want server-side sessions (e.g., auth) with Leptos + Axum, or just client-side persistence in the browser?

If server-side (recommended):

  • Use cookies to carry a session ID, and a session store (memory/Redis).
  • In Leptos server functions, read/write cookies via CookieJar (or SignedCookieJar) and look up data in your store.

Axum setup with cookies:

use axum::{Router};
use axum_extra::extract::cookie::CookieManagerLayer;
use leptos_axum::{handle_server_fn};

#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/api/*fn", handle_server_fn())
        .layer(CookieManagerLayer::new()); // enables CookieJar
    axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
        .serve(app.into_make_service())
        .await
        .unwrap();
}

Read/write a session cookie in a Leptos server function:

use leptos::*;
use leptos_axum::extract::CookieJar;
use axum_extra::extract::cookie::{Cookie, SameSite};

#[server(SetSession, "/api")]
async fn set_session(cx: Scope, jar: CookieJar) -> Result<(), ServerFnError> {
    jar.add(
        Cookie::build("sid", "abc123")
            .http_only(true)
            .secure(true)
            .same_site(SameSite::Lax)
            .path("/")
            .finish(),
    );
    Ok(())
}

#[server(GetSession, "/api")]
async fn get_session(cx: Scope, jar: CookieJar) -> Result<Option<String>, ServerFnError> {
    Ok(jar.get("sid").map(|c| c.value().to_string()))
}

Signed cookies (recommended):

use axum::{Router};
use axum_extra::extract::cookie::{CookieManagerLayer, Key};
use leptos_axum::extract::SignedCookieJar;

#[tokio::main]
async fn main() {
    let key = Key::generate();
    let app = Router::new()
        .route("/api/*fn", leptos_axum::handle_server_fn())
        .layer(CookieManagerLayer::new())
        .with_state(key); // provide Key for SignedCookieJar
    // start server...
}

// In server fn:
#[server(WriteSigned, "/api")]
async fn write_signed(cx: Scope, jar: SignedCookieJar) -> Result<(), ServerFnError> {
    use axum_extra::extract::cookie::Cookie;
    jar.add(Cookie::new("sid", "abc123"));
    Ok(())
}

Server-side session store (e.g., memory/Redis) with axum-session:

use axum::{Router};
use axum_session::{Session, SessionLayer};
use async_session::MemoryStore;

#[tokio::main]
async fn main() {
    let store = MemoryStore::new();
    let layer = SessionLayer::new(store, b"super-secret-and-64-bytes".to_vec());
    let app = Router::new()
        .route("/api/*fn", leptos_axum::handle_server_fn())
        .layer(layer);
    // start server...
}

#[server(SetUser, "/api")]
async fn set_user(cx: leptos::Scope, session: Session) -> Result<(), ServerFnError> {
    session.insert("user_id", 123_u64).map_err(ServerFnError::new)?;
    Ok(())
}

#[server(GetUser, "/api")]
async fn get_user(cx: leptos::Scope, session: Session) -> Result<Option<u64>, ServerFnError> {
    Ok(session.get::<u64>("user_id").unwrap_or(None))
}

If client-side only:

  • Use browser storage for non-sensitive data (preferences). With leptos-use:
use leptos_use::use_session_storage;

let (sid, set_sid) = use_session_storage::<String>("sid");
// set_sid("abc123".to_string());

Best practices:

  • Prefer httpOnly, secure, SameSite cookies.
  • Don’t store sensitive data in the browser; store only a session ID and keep user data server-side.
  • Use SignedCookieJar or encrypted cookies if you must store small trusted data.

Tell me your setup (Axum SSR vs client-only, and whether you need Redis/etc.), and I can tailor a minimal example.

Do you want server-side sessions (e.g., auth) with Leptos + Axum, or just client-side persistence in the browser? If server-side (recommended): - Use cookies to carry a session ID, and a session store (memory/Redis). - In Leptos server functions, read/write cookies via CookieJar (or SignedCookieJar) and look up data in your store. Axum setup with cookies: ```rust use axum::{Router}; use axum_extra::extract::cookie::CookieManagerLayer; use leptos_axum::{handle_server_fn}; #[tokio::main] async fn main() { let app = Router::new() .route("/api/*fn", handle_server_fn()) .layer(CookieManagerLayer::new()); // enables CookieJar axum::Server::bind(&"0.0.0.0:3000".parse().unwrap()) .serve(app.into_make_service()) .await .unwrap(); } ``` Read/write a session cookie in a Leptos server function: ```rust use leptos::*; use leptos_axum::extract::CookieJar; use axum_extra::extract::cookie::{Cookie, SameSite}; #[server(SetSession, "/api")] async fn set_session(cx: Scope, jar: CookieJar) -> Result<(), ServerFnError> { jar.add( Cookie::build("sid", "abc123") .http_only(true) .secure(true) .same_site(SameSite::Lax) .path("/") .finish(), ); Ok(()) } #[server(GetSession, "/api")] async fn get_session(cx: Scope, jar: CookieJar) -> Result<Option<String>, ServerFnError> { Ok(jar.get("sid").map(|c| c.value().to_string())) } ``` Signed cookies (recommended): ```rust use axum::{Router}; use axum_extra::extract::cookie::{CookieManagerLayer, Key}; use leptos_axum::extract::SignedCookieJar; #[tokio::main] async fn main() { let key = Key::generate(); let app = Router::new() .route("/api/*fn", leptos_axum::handle_server_fn()) .layer(CookieManagerLayer::new()) .with_state(key); // provide Key for SignedCookieJar // start server... } // In server fn: #[server(WriteSigned, "/api")] async fn write_signed(cx: Scope, jar: SignedCookieJar) -> Result<(), ServerFnError> { use axum_extra::extract::cookie::Cookie; jar.add(Cookie::new("sid", "abc123")); Ok(()) } ``` Server-side session store (e.g., memory/Redis) with axum-session: ```rust use axum::{Router}; use axum_session::{Session, SessionLayer}; use async_session::MemoryStore; #[tokio::main] async fn main() { let store = MemoryStore::new(); let layer = SessionLayer::new(store, b"super-secret-and-64-bytes".to_vec()); let app = Router::new() .route("/api/*fn", leptos_axum::handle_server_fn()) .layer(layer); // start server... } #[server(SetUser, "/api")] async fn set_user(cx: leptos::Scope, session: Session) -> Result<(), ServerFnError> { session.insert("user_id", 123_u64).map_err(ServerFnError::new)?; Ok(()) } #[server(GetUser, "/api")] async fn get_user(cx: leptos::Scope, session: Session) -> Result<Option<u64>, ServerFnError> { Ok(session.get::<u64>("user_id").unwrap_or(None)) } ``` If client-side only: - Use browser storage for non-sensitive data (preferences). With leptos-use: ```rust use leptos_use::use_session_storage; let (sid, set_sid) = use_session_storage::<String>("sid"); // set_sid("abc123".to_string()); ``` Best practices: - Prefer httpOnly, secure, SameSite cookies. - Don’t store sensitive data in the browser; store only a session ID and keep user data server-side. - Use SignedCookieJar or encrypted cookies if you must store small trusted data. Tell me your setup (Axum SSR vs client-only, and whether you need Redis/etc.), and I can tailor a minimal example.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: adrien/Stage-master#9
No description provided.