Skip to content

[2.x] feat: configurable session and token lifetimes - #4918

Draft
imorland wants to merge 4 commits into
2.xfrom
im/configurable-session-lifetimes
Draft

[2.x] feat: configurable session and token lifetimes#4918
imorland wants to merge 4 commits into
2.xfrom
im/configurable-session-lifetimes

Conversation

@imorland

@imorland imorland commented Aug 11, 2026

Copy link
Copy Markdown
Member

How long people stay signed in is currently fixed: one hour for a normal sign-in, five years for "remember me", and a two hour server-side session. The only way to change any of it is to redefine a core class, because the lifetime lives in a protected static property.

This makes all three configurable, in config.php or from the admin panel, with config.php taking precedence. Nothing changes for a forum that configures nothing.

Token lifetimes are resolved rather than fixed. AccessToken::lifetime() checks config.php, then the settings table, then the value the class declares. The two query scopes that decide validity and expiry use it. $lifetime stays as the default, so subclasses that set it keep working.

Every registered token type is configurable, not a fixed list of two. The admin panel builds its controls from AccessToken::getModels(), so a type added by an extension gets a lifetime control with no core change. A type can opt out with $configurableLifetime = falseDeveloperAccessToken does, since those are issued to scripts deliberately and an expiry set in the admin panel would break them quietly weeks later.

New Extend\AccessToken extender replaces calling AccessToken::setModel() from a service provider, which was undiscoverable and had no way to declare anything about the type.

OAuth is covered by this. Forum\Auth\ResponseFactory mints a RememberAccessToken, so every login through another service inherits the remember lifetime. Right now that means OAuth users get a five year session whether they wanted one or not, and a forum with a shorter session policy can't apply it to them at all.

Also adds a session-cookie option to expire on browser close, for shared computers. That's about the cookie only — the session stays valid server-side.

CollectGarbage now reads the same session lifetime as the cookie does. It previously used the hardcoded 120 minutes independently, so a shortened session would have been left on disk until the old default caught up.

RememberAccessToken::rememberCookieLifeTime() still works, delegating to lifetime(), and is marked deprecated.

Config

'session' => [
    'lifetime' => 120,
    'cookie_expires_on_close' => false,
    'tokens' => [
        'session' => 3600,
        'session_remember' => 157680000,
    ],
],

Anything set here is shown read-only in the admin panel, so session lengths can be pinned where an administrator can't loosen them.

image

Docs: flarum/docs#573

How long someone stays signed in was fixed: an hour for a normal sign-in,
five years for "remember me", two hours for the server-side session. The
values lived in a protected static property, so the only way to change any
of them was to redefine a core class.

They are now resolved rather than fixed — config.php first, then the
settings table, then the default the class declares — so a forum that
configures nothing keeps exactly the lengths it has today.

Every registered token type is offered, not a fixed pair: the admin panel
builds its controls from the type registry, so a type added by an
extension is configured alongside the ones core ships. A type can opt out
where an expiry would do more harm than good, which developer tokens do —
those are issued to scripts deliberately, and an expiry set in the admin
panel would break them quietly weeks later.

Logins through another service are covered by this without any work of
their own: ResponseFactory mints a remember token, so OAuth inherits the
remember lifetime. Until now that meant a five year session whether the
user wanted one or not, with no way for a forum to apply a shorter policy
to it.

Garbage collection now reads the same session lifetime the cookie does. It
had its own copy of the hardcoded two hours, which would have left
shortened sessions sitting on disk until the old default caught up.
The float came from the config array, which could hold one. SessionConfig
returns an int, so the union is dead.
Requiring a real boolean meant a value arriving from the environment as
the string "1" was ignored, where debug and the announcements switch
would have honoured it.
@imorland imorland modified the milestones: 2.0.0-rc.6, 2.1 Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant