Authentication
Authentication failures
The app chooses what Hearth does when a load or mutation is unauthorized. Set the policy on the schema written to #hearth-boot. The function generated by routes! returns the same ClientSchema as hearth::client_schema.
let schema = client_schema(viewer_scope)
.on_unauthorized(hearth::OnUnauthorized::Redirect(sign_in_url));
let boot = serde_json::json!({ "schema": schema, "snapshot": {} });
Resolve internal sign-in URLs with href!(sign_in_page).resolve(cx). The tracker sets this policy in examples/hearth-tracker/src/app/issues.rs. If no policy is set, Hearth redirects to /login. Boot JSON from older servers without on_unauthorized uses the same default.
Both loads and mutations recognize HTTP 401. They also recognize a followed redirect whose final origin and path match the configured sign-in URL. Path prefixes do not match. Query parameters and fragments are ignored for detection so a server can add return-to information. Navigation uses the configured URL, including its query parameters, rather than the response URL. A 403 remains an ordinary request failure.
For a public or read-only app without a sign-in page, use error-only behavior:
let schema = client_schema(viewer_scope)
.on_unauthorized(hearth::OnUnauthorized::Error);
This policy never navigates. Return HTTP 401 for unauthorized requests in this mode. There is no configured endpoint to recognize a followed sign-in redirect, and HTML is not a valid table response. Failed loads are logged and added to window.__hearthErrors; failed mutations roll back and show the normal error toast. An unauthorized response never becomes a successful mutation or a persisted load checkpoint.
Clearing persisted rows
Authentication failure handling does not delete cached rows. Place data-hearth-clear on a page that should explicitly clear the IndexedDB cache, such as the app's logout or sign-in page. The runtime checks for this marker on a page without #hearth-boot, independently of its URL. Unrelated pages and errors do not clear storage. See persistence for viewer scopes and cache lifetime.