AUTH4D-112 branded error and landing pages on the auth origin
Browsers that reach a bad link on the auth origin get a hosted-login screen with the right HTTP
status instead of JSON or the plain text Not found. API and fetch callers get exactly the
responses they got before.
Which requests get a page
A request is a browser navigation only when it is a GET and either sends
Sec-Fetch-Mode: navigate or has an Accept header containing text/html. POST, HEAD and
fetch calls with Accept: application/json are never navigations.
| Request (navigation) | Status | Screen |
|---|---|---|
GET /oauth/authorize error that cannot redirect |
400 | This sign-in link is not valid |
GET /oauth/authorize when sign-in is unavailable |
503 | Sign-in is temporarily unavailable |
GET /oauth/logout (logout is a JSON POST) |
400 | This sign-out link is not valid |
Any other path with no route, including /login/<x> |
404 | Page not found |
Authorize errors that cannot redirect are an unknown or disabled client or tenant, an unregistered
redirect_uri, a missing or invalid state, and unknown or repeated parameters. The status of the
JSON error is kept. Errors that redirect to the client (invalid_scope, unauthorized_client,
malformed PKCE) and the normal 302 to /login are unchanged.
Never changed, whatever the headers: management paths (401 JSON without a bearer token), token,
revocation, UserInfo, discovery and JWKS responses, every POST, and JSON clients on
authentication paths, which still get {"error":"invalid_request"} with 404 for an unknown path.
Response
GET {AUTH_ORIGIN}/oauth/authorize?tenant_id=ten_...&client_id=cli_unknown...
Accept: text/html
HTTP/1.1 400 Bad Request
Content-Type: text/html; charset=utf-8
Cache-Control: no-store, max-age=0
The body is the hosted-login shell (/login/error, built from apps/login) with one extra tag in
<head>: <meta name="auth4-error" content="<code>" />. The code is one of invalid_link,
invalid_logout_link, not_found or temporarily_unavailable, chosen by the API from a fixed list.
The screen shows fixed copy for that code; no server-provided description is rendered. The page keeps
the strict hosted-login CSP. If the hosted-login build cannot be read, the API answers with a short
plain-text message and the same status.
GET {AUTH_ORIGIN}/login/error?error=<code> shows the same screen directly. Unknown codes show a
generic “Something went wrong” screen.
Landing page
GET {AUTH_ORIGIN}/ shows a card with the auth4.dev logo, a short description of the sign-in
service and links to the public site and the developer console. On auth.<domain> the links go to
https://<domain> and https://app.<domain>; elsewhere (local development) they go to production.
Tests
tests/integration/auth4d-112.browser-error-pages.test.ts: HTML and JSON variants for authorize (unknown client, unregistered redirect URI, missing tenant), logout and unknown paths, plus the management, discovery and JWKS paths that never change.
Source: docs/api-spec/auth4d-112.md