trackslash
TRACK-50 P2

Login redirect uses a plain 303 for htmx requests, nesting the login page inside the app shell

0
All issues

Description

When a session expires, any htmx-driven control renders the login page inside the app shell instead of navigating to it. This is a confirmed instance of the layout-nesting mechanism suspected in the duplicate-sidebar report.

The code

internal/server/ui_access.go:433-436:

func redirectUILogin(w http.ResponseWriter, r *http.Request) {
	next := url.QueryEscape(safeUINext(r.URL.RequestURI()))
	http.Redirect(w, r, "/login?next="+next, http.StatusSeeOther)
}

It never consults isHTMXRequest, even though that helper is defined immediately below at ui_access.go:438. grep -rn "HX-Redirect\|HX-Location\|HX-Refresh" internal/server/ matches only the bundled htmx.min.js — the app never sends any of these headers.

Call sites are internal/server/ui_auth_pages.go:196 and :207, inside uiAuthMiddleware, which wraps every authenticated UI route (ui_routes.go:28).

Steps to reproduce

  1. Sign in, then let the session cookie expire (or sign out in another tab).
  2. Click any sidebar entry — e.g. Me, which is hx-get="/me/panel" hx-target="#main" (templates/shell_sidebar.html:23).

Actual

The XHR transparently follows the 303 to GET /login, which returns a standalone full document (templates/login.html:2). htmx extracts its body and swaps it into #main. The login card renders inside the app shell, beside the still-present sidebar and mobile app bar, while the URL bar still shows the old app URL.

Because #main (templates/shell_main.html:2) is a sibling of the sidebar inside .app-shell (templates/shell.html:24-27), any full-page response swapped into #main produces a nested layout. There are ~170 hx-target="#main" controls, so this is reachable from nearly every interactive element.

Expected

A real browser navigation to /login?next=....

Fix

if isHTMXRequest(r) {
	w.Header().Set("HX-Redirect", "/login?next="+next)
	w.WriteHeader(http.StatusNoContent)
	return
}

Test both the htmx and plain-navigation branches.

Sub-issues

0

Linked issues

0

GitHub

0

No branches or pull requests linked.

Comments

0
No comments.