Skip to content

fix: discover a shared dex host from the login redirect; clearer error when a search backend is unavailable - #80

Merged
krynju merged 4 commits into
mainfrom
kr/shared-auth-host-discovery
Nov 3, 2026
Merged

krynju merged 4 commits into
mainfrom
kr/shared-auth-host-discovery

Conversation

@krynju

@krynju krynju commented Nov 3, 2026 •

Copy link
Copy Markdown
Member

Summary

Login on installs with a shared auth host

jh auth login (and token refresh) assumed the dex OIDC endpoints live at either <server>/dex or auth.<server>/dex. Some installs authenticate through a dex hosted on a different, shared auth domain. On those, both probes fail and login falls back to <server>/dex. That path returns an HTML error page, and login fails with:

Login failed: failed to parse device code response: invalid character '<' looking for beginning of value

The fix: when neither candidate answers OIDC discovery, discoverAuthServer now checks where the server's own web login redirects. It sends GET https://<server>/login without following the redirect, and if the Location is an https /dex/auth URL, it uses that host. The host is accepted only if it serves its own discovery document (issuer https://<host>/dex), the same check the existing candidates go through. The server already decides where its own users log in, so this trusts nothing new. Installs that were already discovered pick the same host as before. The /login read runs alongside the existing probes, so the shared-host case pays no extra round trip, and its result is used only when both probes fail. It never follows the redirect; the existing discovery probes keep following redirects as before.

Refresh and jh run setup (the refresh_url written to auth.toml) go through the same authServerFor, so they pick up the discovered host too.

Search when the backend is unavailable

When a search backend can't be reached (it is down, or the install doesn't run it), the web server answers 502/503 with an HTML page. jh search used to print only HTTP 502: Bad Gateway. Unstructured 502/503 errors now become search_unavailable with a readable message:

search_unavailable: this search is not available on the server (HTTP 502 Bad Gateway): its backend is down or not enabled there

An unstructured 504 (the backend took longer than the gateway waits, usually an expensive query) becomes search_timeout, with a hint to narrow the pattern or filter by --package/--registry. A structured {code, message} body from the search API is still reported unchanged. The e2e suite already treats search_unavailable as a backend gap, so these runs now skip instead of failing.

Tests

  • Unit: dexAuthHost (status, scheme, path and relative-URL cases), loginRedirectAuthServer against an httptest TLS server (including that it never follows the redirect, whatever the client's policy), probeAuthServer, and gateway handling in decodeSearchError
  • go vet ./..., go vet -tags e2e ./e2e/..., go test ./... pass
  • Manually checked against an install with a shared auth host: device-flow login, auth status, auth refresh, run setup, and the full live e2e suite (go test -tags e2e ./e2e/...): all pass. The only skips are endpoints that are unavailable or need admin rights on that instance.

🤖 Generated with Claude Code

krynju and others added 2 commits November 3, 2026 11:36
…arch backend clearly

Login (and token refresh) failed with "failed to parse device code
response: invalid character '<'" on installs whose dex is served from an
auth host shared with another install, i.e. neither <server>/dex nor
auth.<server>/dex. When neither candidate answers OIDC discovery, read
where the server's web login (GET /login, not followed) redirects for
/dex/auth and use that host, provided it serves its own discovery
document.

A search backend that is down made the web server answer 502/503/504
with an HTML page, surfaced as a bare "HTTP 502: Bad Gateway". Such
unstructured gateway errors now become search_unavailable with a
readable message, which the e2e suite already treats as a backend gap
(skip) rather than a CLI failure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… enabled

A 502/503/504 from the web server can mean the search backend is down,
or that the install does not run it at all. Drop "try again later".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@krynju krynju changed the title fix: discover a shared dex host from the login redirect; clearer error when the search backend is down fix: discover a shared dex host from the login redirect; clearer error when a search backend is unavailable Nov 3, 2026
@krynju
krynju marked this pull request as draft November 3, 2026 10:46
krynju and others added 2 commits November 3, 2026 11:49
- Discovery probes follow redirects again; only the /login read is
  no-follow, on a copy of the client.
- Read /login alongside the probes instead of after both fail, and do
  not re-probe a redirect to a candidate that just failed.
- Fold the test-only pickAuthServer wrapper into probeAuthServer.
- A gateway 504 is reported as search_timeout with a hint to narrow the
  query, not as an unavailable backend.
- Update the searchError and CLAUDE.md docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, comments)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@krynju
krynju marked this pull request as ready for review November 3, 2026 10:52
@krynju
krynju requested a review from pankgeorg November 3, 2026 10:52
@krynju
krynju merged commit 4af024b into main Nov 3, 2026
1 check passed
@krynju
krynju deleted the kr/shared-auth-host-discovery branch November 3, 2026 10:55
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.

2 participants