Skip to content

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

Description

@sherrmann

Is your feature request related to a problem? Please describe.
Running Spoolman behind a forward-auth reverse proxy (Authelia in my case, same applies to Authentik / oauth2-proxy / Caddy forward_auth). When the auth session expires while a tab is open, every API call from the SPA gets a 401 from the proxy. The frontend has no handler, so it retries forever and the UI is stuck on "Loading…" in the top-left until I manually navigate away and back. Reproduces every time by leaving a tab idle past the proxy's inactivity timeout.

Top-level navigation works fine — the proxy returns 302 to the auth portal because Accept: text/html. The 401 is only on XHR/fetch, by design, so the SPA can decide what to do.

Describe the solution you'd like
On any 401 response from the API, do a top-level page reload. The reload is a top-level GET, the proxy returns 302 to its login portal with ?rd back to the original URL, the user re-auths, and lands on the same page.

The frontend uses three transports — the Refine data provider's shared axios instance, direct fetch() in several places (info, fields, settings, external DB, i18next-http-backend), and raw WebSockets in the live provider — so a complete fix needs to cover all three. A small reload-debounce avoids loops if the reload itself doesn't recover auth.

No effect for users without a forward-auth proxy in front, since Spoolman itself never emits 401 today.

If/when native auth lands (#229, #852), responses from the future login endpoint should be excluded so a wrong-password 401 doesn't reload-loop. Easy to gate on URL once that endpoint exists.

Describe alternatives you've considered

  • Bumping the proxy's inactivity timeout — works but pushes the problem onto every Spoolman user with a forward-auth setup, and trades security for convenience.
  • Injecting a 401 handler via a content-rewrite plugin in the reverse proxy — fragile, fights with Spoolman's service worker, and every user has to set it up themselves.
  • Patching it in a private fork — what I'm running locally, but it's the kind of small UX fix that belongs upstream.

Additional context
PR coming.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions