Skip to content

Pin session cookie name, stop deriving it from APP_NAME - #1585

Open
pilotso11 wants to merge 1 commit into
linuxserver:2.xfrom
pilotso11:fix/session-cookie-appname-dot
Open

Pin session cookie name, stop deriving it from APP_NAME#1585
pilotso11 wants to merge 1 commit into
linuxserver:2.xfrom
pilotso11:fix/session-cookie-appname-dot

Conversation

@pilotso11

Copy link
Copy Markdown

Heimdall doesn't ship a config/session.php, so the session cookie name falls back to Laravel's framework default:

Str::snake((string) env('APP_NAME', 'laravel')) . '_session'

Str::snake() only inserts underscores before capital letters — it does not strip characters like . or spaces. PHP mangles dots in incoming cookie/GET/POST variable names to underscores when parsing a request, so an APP_NAME containing a dot (e.g. example.com) produces a cookie the app can never read back: it looks for example.com_session, but PHP only ever hands it example_com_session in $_COOKIE.

That desyncs the session on every single request, so the CSRF token embedded in any page never matches the token generated on submit, producing a 419 Page Expired on every POST. Reproduced this with a bare curl round-trip (fetch page, extract token+cookie, POST back immediately) with no browser involved at all, which rules out any browser-specific cause like cookie caching or extensions — this is a server-side PHP request-parsing behavior, not a browser quirk.

Root cause and fix were worked out with Claude Code: it decrypted the session cookie server-side and confirmed the mismatch with a $_COOKIE probe against config('session.cookie') on a live instance where this was happening.

This matches the symptoms in several previously-reported, unresolved 419 issues:

Setting SESSION_COOKIE explicitly in .env already works around this today (the framework default respects it), but nothing points users at that until they've already hit the bug. Adding config/session.php pins the cookie name to a fixed value by default (still overridable via SESSION_COOKIE) so it no longer depends on APP_NAME at all — fixing it out of the box for new installs and, since it ships with the code, for existing broken installs on upgrade too.

Heimdall doesn't ship a config/session.php, so the cookie name falls
back to Laravel's framework default:

    Str::snake((string) env('APP_NAME', 'laravel')) . '_session'

Str::snake() only inserts underscores before capital letters; it does
not strip characters like "." or spaces. PHP mangles dots in incoming
cookie/GET/POST variable names to underscores when parsing a request,
so an APP_NAME containing a dot (e.g. "example.com") produces a cookie
the app can never read back: it looks for "example.com_session" but
PHP only ever hands it "example_com_session" in $_COOKIE.

That desyncs the session on every single request, so the CSRF token
embedded in any page never matches the token generated on submit,
producing a 419 Page Expired on every POST. Reproduced this with a
bare curl round-trip (fetch page, extract token+cookie, POST back
immediately) with no browser involved at all, which rules out any
browser-specific cause like cookie caching or extensions - this is a
server-side PHP request-parsing behavior, not a browser quirk.

Root cause and fix were worked out with Claude Code: it decrypted the
session cookie server-side and confirmed the mismatch with a $_COOKIE
probe against config('session.cookie') on a live instance where this
was happening.

This matches the symptoms in several previously-reported, unresolved
419 issues:

- linuxserver#398 - Getting 419 error code when trying to add apps
- linuxserver#443 - 419 "Sorry, your session has expired" when submitting new app
- linuxserver#590 - 419 error when hitting save
- linuxserver#873 - 419 Page Expired doing any POST requests

Setting SESSION_COOKIE explicitly in .env already works around this
today (the framework default respects it), but nothing points users
at that until they've already hit the bug. Adding config/session.php
pins the cookie name to a fixed value by default (still overridable
via SESSION_COOKIE) so it no longer depends on APP_NAME at all, fixing
it out of the box for new and existing installs alike.

App-level config files merge over the framework's defaults key by key
(Illuminate\Foundation\Bootstrap\LoadConfiguration), so this only
needs to override the one key - verified the rest of session.* still
resolves from the framework defaults unchanged.
@pilotso11
pilotso11 force-pushed the fix/session-cookie-appname-dot branch from 58da435 to 0620ec2 Compare August 8, 2026 21:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

2 participants