fix(security): require CSRF-protected POST to consume a registration link
GET /register/{token} consumed the magic-link token and created a session, so
a side-effecting state change happened on a safe method — link prefetchers,
email scanners, or a cross-site GET could trigger account setup/login.
Split the flow: GET validates the token (without consuming) and renders a
confirmation form; POST /register/{token} consumes the token, runs the
existing checks, and establishes the session. The POST carries a CSRF token
and the session is reset on login as for other auth paths.
Refs: porchlight-9k0
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
efb265a68b
commit
baef5e0e2e
6 changed files with 96 additions and 10 deletions
|
|
@ -61,6 +61,11 @@ async def test_inactive_user_cannot_register_magic_link(client: AsyncClient) ->
|
|||
|
||||
link = await magic_link_service.create(username="deactivated", created_by="admin", note="test")
|
||||
|
||||
response = await client.get(f"/register/{link.token}", follow_redirects=False)
|
||||
csrf = await get_csrf_token(client)
|
||||
response = await client.post(
|
||||
f"/register/{link.token}",
|
||||
headers={"X-CSRF-Token": csrf},
|
||||
follow_redirects=False,
|
||||
)
|
||||
|
||||
assert response.status_code == 400 or "deactivated" in response.text.lower() or "Invalid" in response.text
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue