medusajs/medusa · error · MedusaError

Only TOTP MFA factors can be verified with this method

Error message

Only TOTP MFA factors can be verified with this method

What it means

verifySetup on the TOTP provider only verifies factors whose provider is 'totp'. Passing the id of a factor created by a different MFA provider (e.g. another OTP method) throws INVALID_DATA.

Source

Thrown at packages/modules/auth/src/providers/mfa/totp.ts:132

        secret,
        digits: totpConfig.digits,
        period: totpConfig.period,
      }),
    }
  }

  async verifySetup(
    data: AuthTypes.AuthMfaVerifyDTO,
    sharedContext: Context = {}
  ): Promise<AuthTypes.AuthMfaDTO> {
    const factor = await this.authMfaFactorService_.retrieve(
      data.id,
      {},
      sharedContext
    )

    if (factor.provider !== this.method) {
      throw new MedusaError(
        MedusaError.Types.INVALID_DATA,
        "Only TOTP MFA factors can be verified with this method"
      )
    }

    if (factor.status === "disabled") {
      throw new MedusaError(
        MedusaError.Types.NOT_ALLOWED,
        "Disabled MFA factors cannot be verified"
      )
    }

    const valid = this.verifyCode_(factor, data.code)

    if (!valid) {
      throw new MedusaError(MedusaError.Types.NOT_ALLOWED, "Invalid TOTP code")
    }

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Fetch the factor and route verification to the provider stored on it (factor.provider)
  2. Check that the factor id passed corresponds to a TOTP setup

Example fix

// before
await totpProvider.verifySetup({ id: factorId, code })
// after
const [factor] = await authModuleService.listAuthMfaFactors(identityId)
const provider = factor.provider // route to matching provider
await mfaProviderService.verifySetup(factor.provider, { id: factor.id, code })
Defensive patterns

Strategy: type-guard

Validate before calling

const [factor] = await authModuleService.listAuthMfaFactors(identityId)
if (factor.provider !== 'totp') throw new Error('route to the correct provider')

Type guard

const isTotpFactor = (f: { provider: string }) => f.provider === 'totp'

Prevention

When it happens

Trigger: confirmAuthMfaFactor / verifySetup({ id }) where the factor row's provider column is not 'totp' — e.g. ids mixed up between provider setups or a generic confirm route hardcoded to the totp provider.

Common situations: Frontend sends a factor id from the wrong provider after multiple MFA methods are enabled; copy-pasted factor ids between environments.

Related errors


AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27). Data as JSON: /api/errors/2224eebbe056b879. Report an issue: GitHub.