refactor(auth): rip the sessionGateEnabled flag — gate is always on #537
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks#537
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
User story
As an operator, I want session gating to be unconditional, so that misconfiguring
public_base_urlcannot leave the dashboard fully exposed and silent (loads → API returns nothing → empty screen, no login link).Why
Today the gate has three logic layers fighting each other:
sessionGateEnableddefaults topublicBaseUrl !== null(webhook-config.ts:1916) — so withoutpublic_base_urlset, the gate auto-disablesauth.session_gate_enabledboolean override exists for explicit on/offsession-middleware.ts:207short-circuits withif (!enabled) return next()Combined effect on a desktop deployment with no
public_base_urland no override: every request bypasses auth, the SPA mounts the dashboard, API calls return empty, the user sees a blank screen with no path to log in. Operator caught this on 2026-04-28 —/loginwas unreachable in practice because nothing redirected there.The intended logic is plain: logged in → app, not logged in → login. No flag, no inference from
public_base_url, noif (!enabled)skip.Acceptance criteria
Code
apps/server/src/http/session-middleware.ts: drop theenabledparameter frommakeSessionGateMiddleware. Middleware always enforces (exempt list still applies for/login,/oauth/*,/webhooks/*,/app/assets/*, etc.)apps/server/src/shared/config/webhook-config.ts: remove thesessionGateEnabledfield fromWebhookConfig, theauth.session_gate_enabledschema entry, and the inference frompublicBaseUrlapps/server/src/main.ts: drop thecfg?.sessionGateEnabled === truebranch; mount the gate unconditionallyapps/web/src/routes/__root.tsx(defense in depth): on mount call/auth/me(or whatever the canonical session-probe endpoint is); on 401 navigate to/login. Avoids reliance on server-side redirect aloneConfig migration
auth.session_gate_enabledis present in any deployedconfig/agents.json, the loader logs a deprecation warning at boot and ignores itdocs/specs/forge-auth-repo-selection.md(or whichever spec authored the flag) updated to remove the optionTests
session-middleware.test.ts: drop the disabled-mode tests; add tests asserting that without a session cookie, every non-exempt path returns 302 to/loginincluding/,/app,/agents,/board, etc.__rootnavigates to/loginwhen/auth/mereturns 401Local dev escape hatch (optional, only if needed)
CLAUDE_HOOKS_DISABLE_AUTH=1— never via config file. Default is always on.Out of scope
References
apps/server/src/http/session-middleware.ts:207apps/server/src/shared/config/webhook-config.ts:1916apps/web/src/routes/__root.tsx(no client-side check today)