Skip to content

Vibe coded PR: Reload page on 401 to recover from forward-auth session expiry#924

Open
sherrmann wants to merge 1 commit into
Donkie:masterfrom
sherrmann:feat/reload-on-401-forwardauth
Open

Vibe coded PR: Reload page on 401 to recover from forward-auth session expiry#924
sherrmann wants to merge 1 commit into
Donkie:masterfrom
sherrmann:feat/reload-on-401-forwardauth

Conversation

@sherrmann
Copy link
Copy Markdown

Fixes #923

Problem

Behind a forward-auth proxy (Authelia, oauth2-proxy, Authentik, etc.), the proxy returns 401 Unauthorized to XHR once the user's session expires. The SPA shell renders fine, but every backend call fails and a "Loading…" indicator hangs in the corner indefinitely. Recovery today requires manually logging into the auth portal in another tab.

Fix

Axios response interceptor triggers window.location.reload() on 401. The reload is a top-level GET, so the proxy returns its 302 to the login portal with ?rd= set, and the user lands back on the original URL after auth.

  • Auto-reload fires only on GET/HEAD. Mutation 401s pass through to the existing notification provider so unsaved form data isn't destroyed.
  • The service worker is unregistered first because vite-plugin-pwa's default NavigationRoute serves the precached index.html and would prevent the reload from reaching the proxy. vite-plugin-pwa re-registers via registerType: "autoUpdate" on next load.
  • 30s localStorage cooldown bounds the loop if recovery fails.

Scope

Two files (~45 lines). No behavior change for users without forward-auth: Spoolman v0.23.1 emits no 401s natively, so the interceptor stays dormant.

If/when native auth lands (#229, #852), the future login endpoint should be excluded here so a wrong-password 401 doesn't reload-loop — one-line guard, left for whoever ships that feature.

When Spoolman is deployed behind a forward-auth reverse proxy (Authelia,
oauth2-proxy, Authentik, Caddy forward_auth, etc.) the proxy returns 401
to XHR/fetch requests once the user's session expires. The SPA had no
handler -- every query loops on 401, the UI hangs on "Loading..."
indefinitely.

Add an axios response interceptor that triggers a top-level reload on
401 from idempotent (GET/HEAD) requests so the proxy can redirect
through its login portal and back. Mutation 401s fall through to the
existing notification provider so unsaved form data is preserved. A
30-second localStorage cooldown bounds the loop if auth recovery fails.

The service worker is unregistered before the reload because
vite-plugin-pwa's default NavigationRoute serves the precached
index.html for navigation requests, which would otherwise prevent the
reload from reaching the proxy. vite-plugin-pwa re-registers it on the
next page load via registerType: "autoUpdate".

No behavior change for users without forward-auth in front: Spoolman
v0.23.1 emits no 401s natively, so the interceptor stays dormant.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 28, 2026 20:12
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a client-side recovery mechanism for forward-auth session expiry by reloading the SPA when API calls receive a 401, allowing the proxy to redirect the user through its login flow and back.

Changes:

  • Introduces an Axios response interceptor that triggers a reload on 401 for idempotent (GET/HEAD) requests.
  • Adds a reload cooldown (localStorage-based) and unregisters service workers before reloading to avoid PWA navigation caching.
  • Imports the handler from the app entrypoint to install the interceptor at startup.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
client/src/utils/authReloadHandler.ts Adds 401-handling interceptor, cooldown, and service-worker unregistration prior to reload.
client/src/index.tsx Imports the new handler module to activate the interceptor globally.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread client/src/utils/authReloadHandler.ts
Comment thread client/src/utils/authReloadHandler.ts
Comment thread client/src/utils/authReloadHandler.ts
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.

Reload on 401 so the SPA recovers when forward-auth session expires

2 participants