From 2d82b2b27822e15d06ad7b2427c86d6158aab9fe Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 8 Sep 2026 22:43:20 +0000 Subject: [PATCH] Fix Authelia remember_me not actually keeping sessions alive inactivity (idle timeout) was independent of remember_me and stayed at a much shorter default (2h), so a long remember_me got silently overridden by ordinary daily gaps between visits. install_authelia()'s template now defaults inactivity to match remember_me, and the "Change remember me duration" menu option now writes both keys together instead of just one. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_0148pWopbt3tEKZWHYuHTb3c --- CLAUDE.md | 21 ++++++++++++++++++++- services/authelia.sh | 42 +++++++++++++++++++++++++++++++++++------- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index cdc80e8..da3bf23 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -623,6 +623,25 @@ in `services/authelia.sh`) — prompts for a new duration (`12h`, `7d`, Sessions persist through reboots regardless of duration (Redis stores session state in a volume). +**`inactivity` must track `remember_me`, or a long remember_me is a lie.** +`inactivity` is a separate session field — how long a session can sit idle +before Authelia ends it — and it is NOT extended or bypassed by the +"Remember me" checkbox; the two are independent. Confirmed live: a user +set `remember_me: 1y` expecting "won't be asked to log in again for a +year," but the install default left `inactivity` at a much shorter value +(2h at the time), so ordinary daily gaps between visits (overnight, a +workday) ended the session on inactivity grounds well before remember_me +ever came into play — the 1y setting was doing nothing. Fixed at both ends +so this can't recur silently: `install_authelia()`'s own template now sets +`inactivity: 7d`, matching its `remember_me: 7d` default instead of a +shorter one, and `_authelia_set_remember_me()` now writes the SAME new +duration into both keys on every change, not just `remember_me` alone. If +you ever hand-edit `session:` instead of using the menu option, keep +`inactivity` and `remember_me` equal — a mismatch here is exactly the bug +above, not a valid intentional configuration. `expiration` (the cap for a +session that never checked "Remember me") is a legitimately different, +shorter-by-design setting and is untouched by any of this. + **The config key is `remember_me`, not `remember_me_duration`.** Authelia renamed it in 4.38; this repo pins `4.39.20`. A stale `remember_me_duration` key doesn't error, Authelia just silently ignores it — confirmed against @@ -635,7 +654,7 @@ touch this by hand instead of the menu option, the current schema is: session: secret: 'your-existing-secret' expiration: 1h - inactivity: 5m + inactivity: 1y remember_me: 1y cookies: - domain: 'example.com' diff --git a/services/authelia.sh b/services/authelia.sh index f4ed201..caf37f5 100644 --- a/services/authelia.sh +++ b/services/authelia.sh @@ -242,7 +242,8 @@ install_authelia() { echo " 7) Reconfigure from scratch (regenerates secrets/users — breaks" echo " existing sessions for every domain already on this instance)" echo " 8) Show who has universal vs. service-scoped access" - echo " 9) Change \"Remember me\" session duration (stay logged in longer)" + echo " 9) Change \"Remember me\" session duration (stay logged in longer — also" + echo " raises the inactivity timeout to match, so it can't cut it short)" echo " 10) Protect an existing site with this instance (pick a local Caddy site," echo " or type one on a different box — gates it with a login, same as any" echo " other service already protected this way)" @@ -501,7 +502,12 @@ access_control: session: name: authelia_session expiration: 12h - inactivity: 2h + # Matches remember_me below, not a shorter default — an idle timeout + # shorter than remember_me silently cuts a "remembered" session short + # regardless of its own duration. See _authelia_set_remember_me()'s + # comment for the live case this caused. Change both together (that + # function does exactly this) rather than one at a time. + inactivity: 7d remember_me: 7d cookies: - domain: ${AUTHELIA_DOMAIN} @@ -2383,6 +2389,19 @@ _authelia_report_access_scope() { # earlier version of this very file's own README section) uses the old # name, which Authelia would just silently ignore rather than error on. # +# Also writes the SAME value into `inactivity` — a separate session field +# (default 2h, set alongside remember_me in install_authelia()'s own +# template) that ends a session after that much idle time regardless of +# remember_me, since it isn't disabled or extended by the "Remember me" +# checkbox. Confirmed live: a user who'd set remember_me to 1y still got +# logged out after ordinary daily gaps (overnight, a workday) because +# inactivity was still sitting at its 2h default — remember_me alone does +# NOT deliver "won't be asked to log in again for the duration I set" +# without this. Tying the two together is what actually delivers that. +# `expiration` (the session cap when "Remember me" is NOT checked) is left +# alone — a shorter default there for an un-remembered session is correct, +# separate behavior, not the same gap. +# # This only controls AUTHELIA's own session — it does not touch how long # a native-OIDC app's (Gitea/Mealie/ActualBudget) own session/token lasts # after logging in via Authelia. A long remember_me makes re-authenticating @@ -2398,7 +2417,10 @@ _authelia_set_remember_me() { echo "" echo " Current \"remember me\" duration: ${current:-not set}" echo " How long a session lasts when someone checks \"Remember me\" at login —" - echo " applies to every domain this Authelia instance protects." + echo " applies to every domain this Authelia instance protects. Also sets" + echo " \"inactivity\" (idle timeout) to the same value, so a gap between visits" + echo " shorter than this can't log you out early — otherwise inactivity's own" + echo " separate, much shorter default cuts a long remember_me short." echo " Examples: 12h, 7d, 1M (month), 1y. Set to -1 to disable Remember Me entirely." local new_duration="" prompt_text " New duration [${current:-7d}]:" "${current:-7d}" new_duration @@ -2412,8 +2434,13 @@ _authelia_set_remember_me() { else sed -i "/^session:\$/a\\ remember_me: '${new_duration}'" "$config_file" fi + if grep -qE '^ inactivity:' "$config_file"; then + sed -i "s/^ inactivity:.*/ inactivity: '${new_duration}'/" "$config_file" + else + sed -i "/^ remember_me:/a\\ inactivity: '${new_duration}'" "$config_file" + fi chown 1000:1000 "$config_file" 2>/dev/null || true - log_success "\"Remember me\" duration set to ${new_duration}." + log_success "\"Remember me\" duration and inactivity timeout both set to ${new_duration}." local restart_auth="" prompt_yn " Restart Authelia to apply? (y/n):" "y" restart_auth @@ -2425,9 +2452,10 @@ _authelia_set_remember_me() { echo "" log_info "Takes effect for NEW logins where \"Remember me\" is checked at Authelia's" - log_info "login page — existing sessions keep whatever expiration they already had." - log_info "The checkbox itself is already on the login form by default; this only" - log_info "changes how long checking it actually keeps you signed in." + log_info "login page — existing sessions keep whatever expiration/inactivity they" + log_info "already had. The checkbox itself is already on the login form by default;" + log_info "this only changes how long checking it actually keeps you signed in, and" + log_info "stops the separate inactivity timeout from cutting that short." } # Export/import accounts (+ optionally 2FA/session state) — for migrating to