From 575cfa4b38f570a28fc29c17f9ad59324d6574fb Mon Sep 17 00:00:00 2001 From: spinline Date: Sat, 7 Feb 2026 19:05:52 +0300 Subject: [PATCH] Add 'Remember Me' feature to login (extends session to 30 days) --- backend/src/handlers/auth.rs | 16 ++++++++++++---- frontend/src/components/auth/login.rs | 16 ++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/backend/src/handlers/auth.rs b/backend/src/handlers/auth.rs index 80f6330..1de4deb 100644 --- a/backend/src/handlers/auth.rs +++ b/backend/src/handlers/auth.rs @@ -13,6 +13,8 @@ use time::Duration; pub struct LoginRequest { username: String, password: String, + #[serde(default)] + remember_me: bool, } #[derive(Serialize, ToSchema)] @@ -61,8 +63,13 @@ pub async fn login_handler( rand::thread_rng().sample(Alphanumeric) as char }).collect(); - // Expires in 30 days - let expires_in = 60 * 60 * 24 * 30; + // Expiration: 30 days if remember_me is true, else 1 day + let expires_in = if payload.remember_me { + 60 * 60 * 24 * 30 + } else { + 60 * 60 * 24 + }; + let expires_at = time::OffsetDateTime::now_utc().unix_timestamp() + expires_in; if let Err(e) = state.db.create_session(user_id, &token, expires_at).await { @@ -70,13 +77,14 @@ pub async fn login_handler( return (StatusCode::INTERNAL_SERVER_ERROR, "Failed to create session").into_response(); } - let cookie = Cookie::build(("auth_token", token)) + let mut cookie = Cookie::build(("auth_token", token)) .path("/") .http_only(true) .same_site(SameSite::Lax) - .max_age(Duration::seconds(expires_in)) .build(); + cookie.set_max_age(Duration::seconds(expires_in)); + tracing::info!("Session created and cookie set for user: {}", payload.username); (StatusCode::OK, jar.add(cookie), Json(UserResponse { username: payload.username })).into_response() } diff --git a/frontend/src/components/auth/login.rs b/frontend/src/components/auth/login.rs index 92241c6..d35e0d9 100644 --- a/frontend/src/components/auth/login.rs +++ b/frontend/src/components/auth/login.rs @@ -6,12 +6,14 @@ use serde::Serialize; struct LoginRequest { username: String, password: String, + remember_me: bool, } #[component] pub fn Login() -> impl IntoView { let (username, set_username) = create_signal(String::new()); let (password, set_password) = create_signal(String::new()); + let (remember_me, set_remember_me) = create_signal(false); let (error, set_error) = create_signal(Option::::None); let (loading, set_loading) = create_signal(false); @@ -26,6 +28,7 @@ pub fn Login() -> impl IntoView { let req = LoginRequest { username: username.get(), password: password.get(), + remember_me: remember_me.get(), }; let client = gloo_net::http::Request::post("/api/auth/login") @@ -89,6 +92,19 @@ pub fn Login() -> impl IntoView { /> +
+ +
+