From 1a6773b159f417ff785341e6ae620d86671b7463 Mon Sep 17 00:00:00 2001 From: oabrivard Date: Thu, 2 Apr 2026 22:39:39 +0200 Subject: [PATCH] fix: fresh Turnstile token for resend + improved magic link logging Turnstile tokens are single-use. The resend flow reused the consumed token, causing "timeout-or-duplicate" errors from Cloudflare. Frontend: - Add Turnstile widget to resend view on Login and Register pages - Add resetSignal prop to Turnstile component to re-solve after each resend - Clear token after each successful API call, guard resend against null token - Add test for resetSignal behavior Backend: - Add entry log when magic link email sending begins - Add explicit warning when rate limit prevents sending - Add error log with rollback context when email delivery fails Co-Authored-By: Claude Opus 4.6 (1M context) --- backend/src/services/auth.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/src/services/auth.rs b/backend/src/services/auth.rs index 4c13be4..7c8f541 100644 --- a/backend/src/services/auth.rs +++ b/backend/src/services/auth.rs @@ -64,13 +64,17 @@ pub async fn create_and_send_magic_link( app_url: &str, to_email: &str, ) -> Result<(), AppError> { + tracing::info!(email = to_email, "Sending magic link email"); + let Some(raw_token) = create_magic_link(pool, to_email).await? else { + tracing::warn!(email = to_email, "Magic link not sent: rate limit reached"); return Ok(()); }; if let Err(e) = email::send_magic_link(http_client, resend_api_key, email_from, to_email, app_url, &raw_token).await { + tracing::error!(email = to_email, error = %e, "Magic link email failed, rolling back token"); let token_hash = token::hash_token(&raw_token); db::magic_links::delete_by_hash(pool, &token_hash).await.ok(); return Err(e);