Skip to content

🚦 fix: Fail Fast on Missing SESSION_SECRET, Harden Session Read#85

Merged
danny-avila merged 1 commit into
mainfrom
fix/session-secret-failfast
Jun 22, 2026
Merged

🚦 fix: Fail Fast on Missing SESSION_SECRET, Harden Session Read#85
danny-avila merged 1 commit into
mainfrom
fix/session-secret-failfast

Conversation

@danny-avila

Copy link
Copy Markdown
Contributor

Problem

When the admin panel runs in production with a missing or empty SESSION_SECRET, the failure is extremely confusing. src/server/session.ts throws at module-evaluation time, but that module is only imported lazily by the auth server-function chunk. So:

  1. The container boots fine (Admin panel listening...).
  2. The first server-function call surfaces the real cause: SESSION_SECRET environment variable must be set.
  3. Every call after that throws a misleading Server function module export not resolved for serverFn ID: ..., because Bun returns the cached, half-evaluated auth module whose handler exports are all undefined:
fnModule Module { adminLoginFn_createServerFn_handler: undefined, getCurrentUserFn_createServerFn_handler: undefined, ... }
error: Server function module export not resolved for serverFn ID: eb89...

This reads like a build/bundler bug and sends you chasing the wrong thing. It works under bun dev only because development falls back to DEV_SECRET.

Changes

  • server.ts — fail fast at boot. Validate SESSION_SECRET (non-empty, ≥32 chars) before Bun.serve when not in development, and exit with a clear message instead of booting into the lazy-throw trap. This is the same constraint session.ts already enforces, just surfaced immediately and legibly.
  • src/server/auth.ts — harden getCurrentUserFn. It read the session with no error handling, so any session-read failure became an unhandled 500. It now mirrors verifyAdminTokenFn and returns a logged-out result ({ user: null, isAuthenticated: false }) on failure.

On graceful sign-out

A corrupt/undecryptable admin-session cookie is already handled well: h3 ignores the unseal error, starts a fresh session, and overwrites the bad cookie (verified — a garbage cookie yields a clean logged-out 200). The case where a stale session lingers is verifyAdminTokenFn intentionally keeping the cached session when the LibreChat backend is unreachable or returns a non-401/403 error, to avoid logging admins out on transient blips. I left that policy as-is on purpose; happy to revisit if you'd prefer it to sign out after a sustained revalidation failure.

Testing

  • bunx vitest run src/server/auth.oauth.test.ts src/server/session.test.ts → 9/9 pass.
  • Smoke: NODE_ENV=production SESSION_SECRET="" bun server.ts exits 1 with SESSION_SECRET must be set to at least 32 characters (got 0). Refusing to start.
  • Smoke: with a valid 40-char secret it boots normally (Admin panel listening...).
  • Reproduced the original module export not resolved cascade against the published image with an empty secret, and confirmed it disappears once a valid secret is set.

@danny-avila danny-avila merged commit 6768bde into main Jun 22, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants