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) <noreply@anthropic.com>
master
oabrivard 2 months ago
parent b08d65c53c
commit 1a6773b159

@ -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);

Loading…
Cancel
Save