Skip to content

fix: map concurrent MFA verify races to 4xx instead of 500 - #2791

Open
hsusul wants to merge 1 commit into
supabase:masterfrom
hsusul:fix/mfa-verify-session-conflict-2727
Open

fix: map concurrent MFA verify races to 4xx instead of 500#2791
hsusul wants to merge 1 commit into
supabase:masterfrom
hsusul:fix/mfa-verify-session-conflict-2727

Conversation

@hsusul

@hsusul hsusul commented Sep 7, 2026

Copy link
Copy Markdown

Summary

  • Fixes Concurrent MFA verify for the same user returns 500 (FK violation / deadlock) instead of a 4xx conflict #2727: concurrent POST /factors/{id}/verify for the same user could return 500 unexpected_failure (FK 23503 / deadlock 40P01) when one verify's InvalidateSessionsWithAALLessThan deleted another in-flight aal1 session mid-AddClaimToSession.
  • Lock the session with FindSessionByID(..., true) before inserting AMR claims, then reload associations so AAL calculation still sees the new claim.
  • Map session-not-found, foreign-key violations, and deadlocks from this path (including invalidate) to existing client errors (403 session_not_found / 409 conflict) instead of internal failures.
  • Keeps user-scoped aal1 invalidation after successful MFA verify (security behavior unchanged).

Test plan

  • go test ./internal/api -run TestMapMFASessionConflictError
  • go test ./internal/api -run 'TestMFA$' (includes new missing-session + concurrent verify regression tests)
  • CI on this PR

Lock the session before inserting AMR claims, and translate FK
violations/deadlocks from peer aal1 invalidation into conflict-style
client errors so same-user concurrent verifies stop looking like
internal failures.
@hsusul
hsusul requested a review from a team as a code owner September 7, 2026 06:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Concurrent MFA verify for the same user returns 500 (FK violation / deadlock) instead of a 4xx conflict

1 participant