Protect a login page you host
If your domain serves the page where a person types a password, your response headers and every script on that page are part of the authentication boundary. Authreads cannot add headers to a response your server owns.
Choose the smaller security boundary
Prefer authreads-hosted OpenID Connect unless your product genuinely needs to own the credential UI. On the hosted page, Authreads owns the HTML, cookies, no-store policy, CSP, and script inventory. Your application receives the authorization result and never has to secure a password form.
If you self-host, your page, reverse proxy, framework bootstrap, browser session, and CSP reporting are yours to operate. Keep app login credentials and returned Authreads session bearers on your server; never ship them in browser JavaScript. The generated API reference remains the source of truth for request and response shapes.
The response-header baseline
| Control | Required outcome |
|---|---|
Content-Security-Policy | Allow only the code, connections, forms, and assets the credential page needs. |
frame-ancestors 'none' | Prevent another site framing the login page. Keep X-Frame-Options: DENY for older clients. |
Cache-Control: no-store, max-age=0 | Keep credentials, one-time links, and user-specific HTML out of browser and intermediary caches. |
Referrer-Policy: no-referrer | Do not send credential-page URLs to another origin in the Referer header. |
X-Content-Type-Options: nosniff | Stop browsers guessing an executable type for a mislabeled response. |
The starter below mirrors Authreads' credential-page posture. Replace the collector URL; narrow or extend sources only for assets your page actually owns. If browser calls go through your same-origin backend-for-frontend, keep connect-src 'self'. Do not add a broad wildcard to make a violation disappear.
Content-Security-Policy-Report-Only:
default-src 'self';
script-src 'self' 'nonce-<fresh-random-value>';
style-src 'self' 'unsafe-inline';
img-src 'self' data:;
font-src 'self' data:;
connect-src 'self';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
object-src 'none';
report-to credential-csp;
report-uri https://<your-report-collector>/csp
Reporting-Endpoints: credential-csp="https://<your-report-collector>/csp"
Cache-Control: no-store, max-age=0
Referrer-Policy: no-referrer
X-Content-Type-Options: nosniff
X-Frame-Options: DENY'unsafe-inline' when generation fails. If your page has no inline scripts, omit the nonce and use script-src 'self'.Report first, enforce after evidence
- Start with one report-only policyKeep the current enforcing policy unchanged. Send the stricter candidate once as
Content-Security-Policy-Report-Only; do not emit two fields. - Exercise every credential routeTest login, password reset, invitation, one-time-code, validation, 404, and error pages. Confirm the page remains interactive and reports contain no first-party violation.
- Observe real trafficConfirm reports actually reach your collector. Separate your own resources from browser extension injection; zero reports is not proof if delivery is broken.
- Make enforcement a reviewed releaseAfter an agreed clean window, promote the measured policy to
Content-Security-Policy. Keep a rollback and alert on first-party violations.
Do not put upgrade-insecure-requests in the report-only rehearsal: browsers do not upgrade there and warn about the ineffective directive. Configure HSTS at your HTTPS edge for the whole hostname only after confirming every subdomain it covers is HTTPS-ready.
Your boundary and ours
| Surface | Who owns the page security |
|---|---|
| Authreads-hosted sign-in | Authreads owns the HTML, security headers, no-store behavior, scripts, and CSP reporting. |
| Your self-hosted login/reset page | You own the response, headers, dependencies, browser session, monitoring, and enforcement decision. |
| Authreads API | Authreads owns API authentication, validation, rate limits, token issuance, and the published API/OIDC contracts. |
Resolve issuer, endpoints, and jwks_uri from /.well-known/openid-configuration, and use the generated API reference for exact fields and errors. Those machine-readable contracts outrank copied prose when the API evolves.
Pre-release check
- No third-party script executes on the credential origin.
- Secrets and Authreads session bearers never enter browser storage or client bundles.
- Every credential document is non-cacheable, including error and not-found responses.
- Each inline script has the current response nonce; two responses never share one.
- Framing is denied, referrers are suppressed, and content sniffing is disabled.
- Report delivery is proven before the measured policy becomes enforcing.
- Login, reset, invitation, and failure routes work with the enforcing candidate.