Files
Oxicloud/migrations/20260621000000_magic_link_request_challenge.sql
T
Edouard Vanbelle 8fc9a50681 feat(passwordless): add cookie challenge + low TTL
magic-link as now 2 modes:

        - invitation: long TTL (24), no challenge
        - passwordless login: short TTL (10min), cookie challenge to ensure that
        user goes back to same browser (no man in the middle capturing email)
2026-06-03 00:35:25 +02:00

31 lines
1.8 KiB
SQL

-- ════════════════════════════════════════════════════════════════════════════
-- Device-bound magic-link redemption (PR 22)
-- ════════════════════════════════════════════════════════════════════════════
-- Login-via-email tokens (the ones the user requests themselves from their
-- own browser) now carry a per-request challenge that mirrors a cookie
-- set on the originating browser. On redemption the server compares the
-- inbound cookie against this column:
--
-- - Cookie present and matches → redeem instantly (common case, zero
-- UX change for the user clicking from the same browser).
-- - Cookie absent or mismatched → show a confirmation page; user
-- clicks Continue to redeem anyway. Audit-logged as
-- `cross_browser_confirmed`.
--
-- Invitation tokens (the ones a sharer mints for a recipient who has no
-- prior browser context with the server) leave this column NULL — they
-- are cross-device by design and bypass the cookie check entirely.
--
-- See docs/architecture/magic-link-auth.md and auth-simplification.md
-- (PR 22) for the threat model and full design.
ALTER TABLE auth.magic_link_tokens
ADD COLUMN request_challenge TEXT NULL;
COMMENT ON COLUMN auth.magic_link_tokens.request_challenge IS
'Random per-request value mirrored into the oxicloud_magic_request
cookie on the originating browser. NULL for invitation tokens
(cross-device by design); non-NULL for login-via-email tokens
(browser-bound). Compared on redemption to bind the magic-link to
the device that requested it.';