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)
This commit is contained in:
Edouard Vanbelle
2026-06-02 23:12:41 +02:00
parent ac2bdef96e
commit 8fc9a50681
11 changed files with 424 additions and 48 deletions
+24 -4
View File
@@ -70,6 +70,12 @@ Content-Type: application/json
}
HTTP 200
[Captures]
# PR 22 — capture the browser-binding cookie so the redemption can
# replay it. Hurl's automatic cookie jar doesn't reliably attach
# Path-scoped cookies in this test setup, so we wire it through
# explicitly via the Set-Cookie header.
pr18_magic_cookie: header "set-cookie" regex "oxicloud_magic_request=([^;]+)"
[Asserts]
jsonpath "$.message" contains "request received"
@@ -89,13 +95,27 @@ pr18_magic_url: jsonpath "$.text_body" regex "(https?://[^\\s]+/magic/v1/[A-Za-z
# ─────────────────────────────────────────────────────────────
# Step 5 — Redeem the welcome link. Internal user with no
# resource target → lands on `/#/files` (NOT
# `/#/sharedwithme`, which is the external-user
# landing).
# Step 5a — Redeem the welcome link WITHOUT the browser-binding
# cookie. PR 22 shows the cross-browser confirmation
# page (HTTP 200, HTML) rather than redeeming.
# ─────────────────────────────────────────────────────────────
GET {{pr18_magic_url}}
HTTP 200
[Asserts]
header "content-type" startsWith "text/html"
body contains "different browser"
# ─────────────────────────────────────────────────────────────
# Step 5b — Same link, this time with the matching cookie.
# PR 22 binds the magic-link to the requesting browser;
# a matching cookie redeems instantly. Internal user
# with no resource target → lands on `/#/files`.
# ─────────────────────────────────────────────────────────────
GET {{pr18_magic_url}}
Cookie: oxicloud_magic_request={{pr18_magic_cookie}}
HTTP 302
[Asserts]
header "Location" == "/#/files"