-
Notifications
You must be signed in to change notification settings - Fork 0
Accounts and Security
Iain Smith edited this page Sep 2, 2026
·
2 revisions
Email + display name → a short-lived verification link is emailed (or logged,
with console) → on verify you're prompted to add a passkey. A password is
optional; if you set one it's checked for length and against Have I Been Pwned
(k-anonymity range query — the password never leaves your server).
-
Passkeys first — WebAuthn, via browser autofill where supported. Passkeys
need HTTPS or a
localhostorigin; if the RP-ID / origin is misconfigured the error says so plainly. See Reverse Proxy and HTTPS. - Password fallback — Argon2id, then a TOTP step if 2FA is enabled.
- Enumeration-resistant responses, lockout with exponential backoff, every attempt audit-logged.
Settings → Two-factor — TOTP with a QR enrolment and 10 single-use recovery codes.
- The access token lives in the SPA's memory for 15 minutes.
- The refresh token is an opaque value in an
HttpOnly; Secure; SameSite=Laxcookie scoped to/api/auth, 60-day sliding, rotated on every use with replay detection — a reused token revokes the whole chain. - Settings → Sessions lists your devices (one row per sign-in) and lets you revoke any of them, or all others at once.
- The app sends its own security response headers — CSP,
X-Content-Type-Options,Referrer-Policy,X-Frame-Options, and HSTS on anhttps://origin inenv=prod(see Reverse Proxy and HTTPS). - User-supplied source/EPG URLs go through an SSRF guard that resolves the host,
rejects private / loopback / link-local / CGNAT addresses, and pins the
connection to the validated IP (no DNS-rebinding). Widen it deliberately with
TVTIMES_FETCH_ALLOWLIST(Configuration). - XMLTV is parsed with entity expansion disabled (no billion-laughs / XXE), and a gzip feed's decompressed size is capped.
One account is one tenant today, but tenant is modelled separately, so
shared/household accounts are an additive change — not a migration. The
watchlist is already per user for this reason.