Security
Fix open redirect via backslash URL normalization
Browsers normalize \ to / in Location headers, allowing a URL like /\evil.com to be interpreted as //evil.com (protocol-relative) and redirect to an external domain, bypassing the host-only check. Redirect validation is now handled by SafeRedirectURL, which explicitly rejects backslash paths and protocol-relative URLs.
New: external redirect allowlist (ACKIFY_ALLOWED_REDIRECT_HOSTS)
Optional comma-separated list of hostnames (with optional port) accepted as post-auth redirect targets. Absolute URLs pointing to unlisted hosts fall back to /. Defaults to empty (same-origin only), preserving existing behaviour.
Features
Better UX for unauthenticated visitors on shared document links
Shared /?doc=<id> links gave no clear indication that login was required. The "Confirm reading" button silently triggered an OAuth redirect on click, which was non-obvious and failed entirely when MagicLink was the only enabled method.
- Login prompt banner with a "Sign in" CTA shown when a document is loaded without an active session.
SignButtonnow redirects to/auth(chooser page) instead of forcing OAuth, so all enabled auth methods are offered.- Button label adapts to "Sign in to confirm" while the user is logged out.
- New
sign.loginPrompt.*i18n keys added (en / fr / de / es / it).
Bug Fixes
Reminder auth links work regardless of MagicLink feature flag
Reminder tokens (issued by admins when sending signature reminders) were gated on IsMagicLinkEnabled(), causing a 503 "Magic Link not enabled" error on click in OAuth-only setups. The reminder token system is conceptually independent from the user-facing MagicLink feature (different purpose, route, lifetime, and trigger) — the gate is removed.