Skip to content

fix(auth): Sync CSRF token on form submit for multi-tab scenarios#107389

Merged
JoshFerge merged 1 commit intomasterfrom
jferg/csrf-token-submit-intercept
Feb 3, 2026
Merged

fix(auth): Sync CSRF token on form submit for multi-tab scenarios#107389
JoshFerge merged 1 commit intomasterfrom
jferg/csrf-token-submit-intercept

Conversation

@JoshFerge
Copy link
Member

@JoshFerge JoshFerge commented Jan 31, 2026

Summary

When users have multiple tabs open on auth pages and one tab logs in (rotating the CSRF token), other tabs can fail with "CSRF token from POST incorrect" if they submit before the 200ms polling interval syncs the new token.

This PR adds a form submit event listener that syncs the CSRF token from cookie to form field right before submission, eliminating the race condition.

Changes:

  • auth.html: Add submit event listener (capture phase) to sync CSRF tokens before form POST
  • webAuthnAssert.tsx: Use requestSubmit() instead of submit() so the global submit listener fires (includes Safari 15 fallback)

@github-actions github-actions bot added Scope: Frontend Automatically applied to PRs that change frontend components Scope: Backend Automatically applied to PRs that change backend components labels Jan 31, 2026
@JoshFerge
Copy link
Member Author

@sentry review

@JoshFerge
Copy link
Member Author

bugbot review

Add form submit event listener (capture phase) to sync CSRF token from
cookie to form field right before submission. Use requestSubmit() in
WebAuthnAssert to trigger this listener (form.submit() doesn't fire events).
Copy link
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

// CSRF sync listener in auth.html to update the token for multi-tab scenarios.
// Falls back to submit() for Safari 15 (requestSubmit added in Safari 16).
if (form.requestSubmit) {
form.requestSubmit();
Copy link
Member Author

@JoshFerge JoshFerge Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i've checked and i don't believe this change should cause any problems w/ respect to validation or event listeners.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(also validated that this works locally)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JoshFerge JoshFerge requested review from a team February 2, 2026 23:34
@getsentry getsentry deleted a comment from github-actions bot Feb 2, 2026
}, 200);
}

// Periodic sync for visual consistency (user sees correct token in DevTools)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i should remove this comment, not helpful.

}

// Periodic sync for visual consistency (user sees correct token in DevTools)
setInterval(syncCsrfTokens, 200);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can probably remove the setInterval after deployment of this PR and confirming dropoff of remaining errors

Comment on lines +76 to +78
// Sync on form submit to guarantee fresh token even if submit happens
// within the 200ms polling window. Capture phase ensures this runs
// before the form's default submit action.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a fast race, 200ms things get out of whack? Is that because of many requests, and the order is the problem? or a few requests that are quick i wonder.

Either way, the change in this file can't be worse.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

monitoring here. they still happen a decent amount, even after my change, and some of the logs do look like it's folks with multiple tabs quickly (albiet not 200ms quick) logging in successively.

@JoshFerge JoshFerge merged commit 1310f27 into master Feb 3, 2026
97 of 138 checks passed
@JoshFerge JoshFerge deleted the jferg/csrf-token-submit-intercept branch February 3, 2026 14:00
jaydgoss pushed a commit that referenced this pull request Feb 12, 2026
…07389)

## Summary

When users have multiple tabs open on auth pages and one tab logs in
(rotating the CSRF token), other tabs can fail with "CSRF token from
POST incorrect" if they submit before the 200ms polling interval syncs
the new token.

This PR adds a form submit event listener that syncs the CSRF token from
cookie to form field right before submission, eliminating the race
condition.

**Changes:**
- `auth.html`: Add submit event listener (capture phase) to sync CSRF
tokens before form POST
- `webAuthnAssert.tsx`: Use `requestSubmit()` instead of `submit()` so
the global submit listener fires (includes Safari 15 fallback)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants