appwrite icon indicating copy to clipboard operation
appwrite copied to clipboard

🐛 Bug Report: Error attribute "Factor" must be an array when updating MFA

Open losfroger opened this issue 1 year ago • 6 comments

👟 Reproduction steps

  1. Log in with a user through a web app
  2. Generate MFA Recovery codes
  3. Add authenticator
  4. Use the updateMFA(true) function from the appwrite sdk store

👍 Expected behavior

A 200 response as indicated in the docs

👎 Actual Behavior

Giving the following htpp response:

{
  "message":"Invalid document structure: Attribute \"factors\" must be an array",
  "code":400,
  "type":"document_invalid_structure",
  "version":"1.5.7"
}

And the following inside the docker logs:

appwrite                           | [Error] Timestamp: 2024-07-18T18:46:03+00:00
appwrite                           | [Error] Method: PATCH
appwrite                           | [Error] URL: /v1/account/mfa
appwrite                           | [Error] Type: Utopia\Database\Exception\Structure
appwrite                           | [Error] Message: Invalid document structure: Attribute "factors" must be an array
appwrite                           | [Error] File:
appwrite                           | [Error] Line: 0

It seems to still activate MFA, but not sure if this error is something I should pay attention to, or ignore it

🎲 Appwrite version

Version 1.5.x

💻 Operating system

Linux

🧱 Your Environment

I'm using a self-hosted docker instance.

I've tried using docker compose down -v as a suggestion from the discord server. And it fixed it temporarily, but the issue popped up again

👀 Have you spent some time to check if this issue has been raised before?

  • [X] I checked and didn't find similar issue

🏢 Have you read the Code of Conduct?

losfroger avatar Jul 18 '24 19:07 losfroger

Hey @losfroger Thanks for opening the issue.

Is that an upgraded version of Appwrite? If so, did you ran migrations?

byawitz avatar Jul 18 '24 19:07 byawitz

This is a fresh installation of appwrite, 1.5.7. Still, I tried running the migrations anyway and the issue persists.

Not sure what other info I could give to track down what's happening

losfroger avatar Jul 18 '24 19:07 losfroger

@losfroger, we've been trying to troubleshoot this, but we're unable to reproduce the problem. Would you be able to go into your appwrite container and modify this to:

+ var_dump($factors);
$dbForProject->updateDocument('sessions', $session->getId(), $session);

If we can see what $factors is, maybe we can figure out why it isn't an array.

stnguyen90 avatar Aug 14 '24 18:08 stnguyen90

@stnguyen90 sorry for the late reply. Let me try out dumping the info as you suggested, and I'll report back

losfroger avatar Aug 27 '24 16:08 losfroger

I managed to add the var_dump($factors);

This is what it threw:

# I'm using a test user that already generated its recovery codes, not sure if that might be influencing something
2024-08-27 11:34:43 [Error] Timestamp: 2024-08-27T17:34:43+00:00
2024-08-27 11:34:43 [Error] Method: POST
2024-08-27 11:34:43 [Error] URL: /v1/account/mfa/recovery-codes
2024-08-27 11:34:43 [Error] Type: Appwrite\Extend\Exception
2024-08-27 11:34:43 [Error] Message: The current user already generated recovery codes and they can only be read once for security reasons.
2024-08-27 11:34:43 [Error] File: /usr/src/code/app/controllers/api/account.php
2024-08-27 11:34:43 [Error] Line: 3739
# Here's the var_dump
2024-08-27 11:35:05 array(3) {
2024-08-27 11:35:05   [0]=>
2024-08-27 11:35:05   string(8) "password"
2024-08-27 11:35:05   [1]=>
2024-08-27 11:35:05   string(4) "totp"
2024-08-27 11:35:05   [3]=>
2024-08-27 11:35:05   string(5) "email"
2024-08-27 11:35:05 }
2024-08-27 11:35:05 [Error] Timestamp: 2024-08-27T17:35:05+00:00
2024-08-27 11:35:05 [Error] Method: PATCH
2024-08-27 11:35:05 [Error] URL: /v1/account/mfa
2024-08-27 11:35:05 [Error] Type: Utopia\Database\Exception\Structure
2024-08-27 11:35:05 [Error] Message: Invalid document structure: Attribute "factors" must be an array
2024-08-27 11:35:05 [Error] File: 
2024-08-27 11:35:05 [Error] Line: 0

losfroger avatar Aug 27 '24 17:08 losfroger

Have exactly the same problem with ‘const result = await account.updateMFA(true);’ in version 1.6.0.

Error response: {
  Message: ‘Invalid document structure: The attribute “factors” must be an array’,
  code: 400,
  Type: ‘Document_Invalid_Structure’,
  version: ‘1.6.0’
}

MFA is activated despite the error: Image

TheAndreDev avatar Oct 11 '24 10:10 TheAndreDev

I am encountering the same issue as others have reported. The confusion arises from the following statement in the documentation:

You will need to have added more than 1 factors of authentication to an account before the MFA is enforced. source: https://appwrite.io/docs/products/auth/mfa

When reading this, one would expect to implement MFA enforcement like this:

async verify(otp: string): Promise<void> {
	await account.updateMfaAuthenticator(AuthenticatorType.Totp, otp);
	await account.updateMFA(true);
}

However, this results in the following error: Failed to enable MFA: Invalid document structure: Attribute "factors" must be an array.

I am using the latest version of Appwrite (node-appwrite: ^14.1.0) while working with Appwrite Cloud. The documentation appears to be incorrect because, as of this version, MFA enforcement works even without adding multiple factors.

At this point, I am unsure whether the issue lies in the documentation or the implementation. However, here is a solution that avoids the error by reversing the order of execution:

Solution:

async verify(otp: string): Promise<void> {
	await account.updateMFA(true);
	await account.updateMfaAuthenticator(AuthenticatorType.Totp, otp);
}

It could be nice clarify whether the documentation or implementation needs to be updated to reflect the intended behavior

Mehdi-Verfaillie avatar Nov 17 '24 22:11 Mehdi-Verfaillie

I have the same issue on appwrite 1.6.1. If you enable MFA (account.updateMFA(true)) before the "Verify authenticator" (updateMfaAuthenticator(AuthenticatorType.Totp, otp)) step, you risk locking yourself out of the account if the provided code is not correct as you can't login if no TOTP has been configured.

Edit: The request fails with Attribute "factors" must be an array but when checking the console MFA has been activated for the account.

Edit 2: If you disable MFA before activating it it works without errors (even if it was disabled to begin with):

await account.updateMfaAuthenticator(AuthenticatorType.Totp, otp);
await account.updateMFA(false);
await account.updateMFA(true);

hej2010 avatar Apr 07 '25 09:04 hej2010

Im getting the same issue.

await account.updateMfaAuthenticator(
  AuthenticatorType.Totp,
  twoFactorInput.value
);
await account.updateMFA(enable);

Error

{
  "message":"Invalid document structure: Attribute \"factors\" must be an array",
  "code":400,
  "type":"document_invalid_structure",
  "version":"1.6.1"
}

felixrydberg avatar Apr 13 '25 20:04 felixrydberg

@Mehdi-Verfaillie That worked for me! Updating the MFA status before updating the Authenticator does the job, and I think it is the logical way to handle this!

await account.updateMFA(true);
await account.updateMfaAuthenticator(AuthenticatorType.Totp, verificationCode);

UPDATE

The main downside here is when the user provides a wrong MFA code for the first installtion, then the MFA is enabled for this user immediatly without any Authentication method availble!

And this is a downside when you check for the MFA status of the user, as it will be enabled while there is no Authentication method available to validate it!

So, I recommend NOT using it this way and wait for the next release from the Appwrite team.

salahineo avatar Aug 15 '25 07:08 salahineo