medusajs/medusa · error · MedusaError

Auth identity does not have any enabled MFA methods

Error message

Auth identity does not have any enabled MFA methods

What it means

Creating an MFA challenge requires at least one enabled MFA method on the auth identity. If getAvailableMfaChallengeMethods_ returns an empty list, challenge creation is refused with NOT_ALLOWED.

Source

Thrown at packages/modules/auth/src/services/auth-module.ts:443

  @InjectTransactionManager()
  protected async createAuthMfaChallenge_(
    data: AuthTypes.CreateAuthMfaChallengeDTO,
    @MedusaContext() sharedContext: Context = {}
  ): Promise<AuthTypes.AuthMfaChallengeDTO> {
    await this.authIdentityService_.retrieve(
      data.auth_identity_id,
      {},
      sharedContext
    )

    const methods = await this.getAvailableMfaChallengeMethods_(
      data.auth_identity_id,
      sharedContext
    )

    if (!methods.length) {
      throw new MedusaError(
        MedusaError.Types.NOT_ALLOWED,
        "Auth identity does not have any enabled MFA methods"
      )
    }

    const challengeConfig = this.getMfaChallengeConfig_()
    const challenge: AuthTypes.AuthMfaChallengeDTO = {
      id: generateEntityId(undefined, "authmfachal"),
      auth_identity_id: data.auth_identity_id,
      auth_provider: data.auth_provider ?? null,
      methods,
      expires_at: new Date(Date.now() + challengeConfig.ttlSeconds * 1000),
      attempts: 0,
      max_attempts: challengeConfig.maxAttempts,
      completed_at: null,
      metadata: data.metadata ?? null,
    }

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Skip the challenge step when no enabled factors exist — check listAuthMfaFactors and filter status === 'enabled'
  2. Have the user complete (or redo) their MFA setup so an enabled factor exists

Example fix

// before
const challenge = await authModuleService.createAuthMfaChallenge({ auth_identity_id: id })
// after
const enabled = (await authModuleService.listAuthMfaFactors(id))
  .filter((f) => f.status === 'enabled')
if (enabled.length) {
  const challenge = await authModuleService.createAuthMfaChallenge({
    auth_identity_id: id,
  })
}
Defensive patterns

Strategy: validation

Validate before calling

const enabled = (await authModuleService.listAuthMfaFactors(identityId)).filter((f) => f.status === 'enabled')
if (enabled.length) await authModuleService.createAuthMfaChallenge({ auth_identity_id: identityId })

Type guard

const hasEnabledFactor = (factors: { status: string }[]) => factors.some((f) => f.status === 'enabled')

Try / catch

try { await createAuthMfaChallenge(...) } catch (e) { if (e.message.includes('any enabled MFA')) { /* skip challenge, proceed without MFA */ } throw e }

Prevention

When it happens

Trigger: createAuthMfaChallenge for an identity that has no factors with status 'enabled' — e.g. only a pending (never confirmed) TOTP setup exists, or all factors were disabled.

Common situations: Login flow always tries to challenge; user abandoned MFA setup halfway so nothing is enabled; factors disabled by admin leaving the account without MFA.

Related errors


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