Context
Solid-OIDC bearer tokens live in IndexedDB. When a browser does a plain navigation to a private resource (clicking a link, typing a URL, opening a bookmark), it doesn't automatically attach the bearer or DPoP headers. JSS receives an unauthenticated request, returns 401 with an empty body, and the user sees a completely blank page with no indication of what happened or what to do.
Repro
- Start any single-user JSS instance (e.g. via jspod)
- Sign in via the OIDC flow — tokens now live in browser IndexedDB
- Visit `http://localhost:5444/private/\` in the address bar (browser nav, no app)
Expected: some indication that this resource requires sign-in / which app to use.
Actual: completely blank page, HTTP 401 with Content-Length: 0.
```
$ curl -i http://localhost:5444/private/
HTTP/1.1 401 Unauthorized
Content-Length: 0
...
```
The same issue affects:
- Bookmarked private resources
- Solid app deep-links that send the user to a pod URL before initiating OIDC
- Welcome-page directory tiles in jspod (which appear lit when signed in because the page-side probe uses session.authFetch, but the click triggers an unauthenticated browser nav)
What other servers do
Community Solid Server returns an HTML response on 401 that includes the IdP URL and a "you need to sign in" message. NSS renders a server-side HTML page when a private resource is requested unauthenticated. JSS currently is the odd-one-out with an empty 401.
Proposed fix options
A. Always return an HTML auth-required page on 401 for Accept: text/html
Simplest. When the request accepts HTML and auth is required, return a small server-rendered page:
🔒 This resource requires sign-in
[Sign in →]
Pros: works everywhere a browser navigates. No client-side changes anywhere.
Cons: chooses one auth surface (where does "Sign in" go?). Could be configurable.
B. Honor a --auth-page <url> config option
Operator points JSS at any URL — JSS redirects to it on 401 (with the original resource URL as a query param). Downstream wrappers like jspod could point this at their /signin.html.
Pros: composable. Each deployment chooses its own auth surface.
Cons: more configuration.
C. Combine: default to a built-in HTML page, allow override via flag
Sensible default for stock JSS deployments, customizable for wrappers.
Recommendation
A or C. Either eliminates blank-401 pages with no downstream change required.
Related
- jspod#1 — friction-removal arc; this is the last visible gap in the first-run flow
- JavaScriptSolidServer#459 — separate issue about a downstream-customization hook for the root index.html. Both fall under the same theme: JSS surfaces that should be either rendered helpfully or customizable.
Context
Solid-OIDC bearer tokens live in IndexedDB. When a browser does a plain navigation to a private resource (clicking a link, typing a URL, opening a bookmark), it doesn't automatically attach the bearer or DPoP headers. JSS receives an unauthenticated request, returns 401 with an empty body, and the user sees a completely blank page with no indication of what happened or what to do.
Repro
Expected: some indication that this resource requires sign-in / which app to use.
Actual: completely blank page, HTTP 401 with
Content-Length: 0.```
$ curl -i http://localhost:5444/private/
HTTP/1.1 401 Unauthorized
Content-Length: 0
...
```
The same issue affects:
What other servers do
Community Solid Server returns an HTML response on 401 that includes the IdP URL and a "you need to sign in" message. NSS renders a server-side HTML page when a private resource is requested unauthenticated. JSS currently is the odd-one-out with an empty 401.
Proposed fix options
A. Always return an HTML auth-required page on 401 for
Accept: text/htmlSimplest. When the request accepts HTML and auth is required, return a small server-rendered page:
Pros: works everywhere a browser navigates. No client-side changes anywhere.
Cons: chooses one auth surface (where does "Sign in" go?). Could be configurable.
B. Honor a
--auth-page <url>config optionOperator points JSS at any URL — JSS redirects to it on 401 (with the original resource URL as a query param). Downstream wrappers like jspod could point this at their /signin.html.
Pros: composable. Each deployment chooses its own auth surface.
Cons: more configuration.
C. Combine: default to a built-in HTML page, allow override via flag
Sensible default for stock JSS deployments, customizable for wrappers.
Recommendation
A or C. Either eliminates blank-401 pages with no downstream change required.
Related