From 33268b38ae86eb4e0be9a3f0e1123f9b860d2121 Mon Sep 17 00:00:00 2001 From: BOHA Date: Mon, 23 Mar 2026 20:28:54 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20TOTP=20login=20flow=20loses=20remember?= =?UTF-8?q?=5Fme=20=E2=80=94=20sessions=20expire=20after=201=20hour?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TOTP verification endpoint always created refresh tokens with remember_me=false and 1-hour expiry, regardless of what the user selected at login. Fix: - Frontend now sends remember_me in the TOTP verify request body - Backend reads remember_me and uses it for token expiry (30 days) and cookie maxAge Users with 2FA who checked "remember me" will now stay logged in for 30 days instead of being kicked out after 1 hour. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/admin/context/AuthContext.tsx | 2 +- src/routes/admin/auth.ts | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/admin/context/AuthContext.tsx b/src/admin/context/AuthContext.tsx index e558db7..f9e718f 100644 --- a/src/admin/context/AuthContext.tsx +++ b/src/admin/context/AuthContext.tsx @@ -198,7 +198,7 @@ export function AuthProvider({ children }: { children: ReactNode }) { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', - body: JSON.stringify({ login_token: loginToken, totp_code: code }), + body: JSON.stringify({ login_token: loginToken, totp_code: code, remember_me: remember }), }) const data = await response.json() if (data.success) { diff --git a/src/routes/admin/auth.ts b/src/routes/admin/auth.ts index 499a631..295b0f5 100644 --- a/src/routes/admin/auth.ts +++ b/src/routes/admin/auth.ts @@ -76,6 +76,8 @@ export default async function authRoutes(fastify: FastifyInstance): Promise; + const rememberMe = rawBody.remember_me === true || rawBody.remember_me === 'true'; const tokenHash = crypto.createHash('sha256').update(login_token).digest('hex'); @@ -127,18 +129,22 @@ export default async function authRoutes(fastify: FastifyInstance): Promise