# Supabase Auth: mfa_verification_failed

> Supabase MFA returns mfa_verification_failed when the TOTP code doesn’t match the factor. Retry with a new challenge, then check the factor ID and clock.

Canonical: https://app369.com/fix/supabase-mfa-verification-failed/
Last updated: 2026-11-09

mfa_verification_failed is the Supabase Auth error when mfa.verify gets a TOTP code that doesn’t match the factor. It shows up during enrollment and at sign-in for users who turned on an authenticator app.

**Short answer**

Let the user try again with a new challenge and the current code. If every code fails, check that the factorId belongs to the QR code the user scanned, that enroll ran only once, and that the phone clock is set automatically. Unverified factors from abandoned enrollments can be removed with unenroll.

Rather not fix it yourself? [**App Fix Ticket**](https://app369.com/fixed-price/flutter-firebase-bug-fix/) starts with a fixed-price diagnosis, then a fixed price for the fix before any fix work.

## **Why the code is rejected, and the fix**

1. 01 ### **The code was typed wrong or too late**
  > “If not, you should repeat steps 2 and 3.” [**Supabase docs, Multi-Factor Authentication (TOTP)**](https://supabase.com/docs/guides/auth/auth-mfa/totp) Authenticator codes change every few seconds. Show a short message, clear the field, and run challenge and verify again with the new code.```
const { data: challenge } = await supabase.auth.mfa.challenge({ factorId });
const { error } = await supabase.auth.mfa.verify({
  factorId,
  challengeId: challenge.id,
  code,
});
if (error?.code === 'mfa_verification_failed') {
  showMessage('That code didn’t work. Enter the newest code from the app.');
}
```
2. 02 ### **enroll ran twice during setup** A screen that calls mfa.enroll on every render can show one QR code and keep the factorId of another. Call enroll once and keep its QR code and ID together.
3. 03 ### **The phone clock is off** TOTP codes depend on the time. A phone with a manually set clock produces codes the server won’t accept. Ask the user to turn on automatic date and time.
4. 04 ### **The user has several factors** Also check: after a few abandoned setups, a user can have more than one TOTP factor. Use listFactors, verify against the one marked verified, and unenroll the rest.

Checked against the vendor’s docs on November 9, 2026: [Supabase docs: Auth error codes](https://supabase.com/docs/guides/auth/debugging/error-codes); [Supabase docs: Multi-Factor Authentication (TOTP)](https://supabase.com/docs/guides/auth/auth-mfa/totp).

## **Rather hand it over?**

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

- [from $450**App Fix Ticket**One reproducible bug in an existing mobile or web app, diagnosed and fixed.**See scope and start**](https://app369.com/fixed-price/flutter-firebase-bug-fix/)
- [from $450**AI-Built App Rescue**A Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.****No issues worth fixing, no charge.**** If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.**See scope and start**](https://app369.com/fixed-price/ai-app-rescue/)

[**All 127 Fiverr reviews**](https://app369.com/reviews/)

Related: [**Supabase captcha_failed**](https://app369.com/fix/supabase-captcha-failed/) · [**Supabase same_password**](https://app369.com/fix/supabase-same-password/) · [**Supabase AuthSessionMissingError**](https://app369.com/fix/supabase-auth-session-missing/) · [**Supabase sms_send_failed**](https://app369.com/fix/supabase-sms-send-failed/)

Questions

## **More on this error**

<details>

<summary>**What does a successful verify change? **+</summary>

The session moves from aal1 to aal2, and during enrollment the factor becomes active right away.

</details>

<details>

<summary>**What if the user lost the phone? **+</summary>

Give users a second factor or a recovery path in advance. Without one, an admin has to remove the factor from the server with the service role key.

</details>

<details>

<summary>**Can you fix it for me? **+</summary>

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

</details>

A different error?

## **Describe it and get a written quote**

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.

[**Describe your problem **→](https://app369.com/contact/) [**All fixes**](https://app369.com/fix/)