oidc: render HTML error pages for browser-facing failures

Add httpUserError() alongside httpError() for browser-facing error
paths. It renders a styled HTML page using the AuthError template
instead of returning plain text. Technical error details stay in
server logs; the HTML page shows actionable messages derived from
the HTTP status code:

  401/403 → "You are not authorized. Please contact your administrator."
  410     → "Your session has expired. Please try again."
  400-499 → "The request could not be processed. Please try again."
  500+    → "Something went wrong. Please try again later."

Convert all httpError calls in oidc.go (OIDC callback, SSH check,
registration confirm) to httpUserError. Machine-facing endpoints
(noise, verify, key, health, debug) are unchanged.

Fixes juanfont/headscale#3182
This commit is contained in:
Kristoffer Dalby 2026-04-13 08:46:00 +00:00
parent c15caff48c
commit 78990491da
5 changed files with 257 additions and 48 deletions

View file

@ -24,6 +24,14 @@ func TestTemplateHTMLConsistency(t *testing.T) {
Message: "You can now close this window.",
}).Render(),
},
{
name: "Auth Error",
html: templates.AuthError(templates.AuthErrorResult{
Title: "Headscale - Error",
Heading: "Forbidden",
Message: "You are not authorized. Please contact your administrator.",
}).Render(),
},
{
name: "Auth Web Register",
html: templates.AuthWeb(
@ -98,6 +106,14 @@ func TestTemplateModernHTMLFeatures(t *testing.T) {
Message: "You can now close this window.",
}).Render(),
},
{
name: "Auth Error",
html: templates.AuthError(templates.AuthErrorResult{
Title: "Headscale - Error",
Heading: "Forbidden",
Message: "You are not authorized. Please contact your administrator.",
}).Render(),
},
{
name: "Auth Web Register",
html: templates.AuthWeb(
@ -164,6 +180,15 @@ func TestTemplateExternalLinkSecurity(t *testing.T) {
"https://tailscale.com/kb/",
},
},
{
name: "Auth Error",
html: templates.AuthError(templates.AuthErrorResult{
Title: "Headscale - Error",
Heading: "Forbidden",
Message: "You are not authorized. Please contact your administrator.",
}).Render(),
externalURLs: []string{}, // No external links
},
{
name: "Auth Web Register",
html: templates.AuthWeb(
@ -248,6 +273,14 @@ func TestTemplateAccessibilityAttributes(t *testing.T) {
Message: "You can now close this window.",
}).Render(),
},
{
name: "Auth Error",
html: templates.AuthError(templates.AuthErrorResult{
Title: "Headscale - Error",
Heading: "Forbidden",
Message: "You are not authorized. Please contact your administrator.",
}).Render(),
},
{
name: "Auth Web Register",
html: templates.AuthWeb(