Back

2FA Code Generation in Appwrite Functions is always wrong

  • 0
  • General
  • Functions
ZachHandley
15 Dec, 2023, 18:23

@Drake @D5

TL;DR
The user is experiencing an issue with the 2FA code generation in an appwrite function. The problem seems to be with the handling of the secret code. The solution is to remove the extra `fromBase32` method when creating the `secret` and store it as a base32 string in the document. Additionally, the user suggests setting the `window` to 2 and checking if there is an extra `fromBase32` method in the verification part. There is no clear resolution provided in the thread.
ZachHandley
15 Dec, 2023, 18:24

there we go

ZachHandley
15 Dec, 2023, 18:25

it successfully works for the generation part

ZachHandley
15 Dec, 2023, 18:25

and it successfully gives me a key but

ZachHandley
15 Dec, 2023, 18:25

I can never get them to be the same

Drake
15 Dec, 2023, 18:38

Are you supposed to be generating a new secret every time? 🧐

ZachHandley
15 Dec, 2023, 18:39

Technically yes

ZachHandley
15 Dec, 2023, 18:39

it's time based authentication

Drake
15 Dec, 2023, 18:39

Never mind... misunderstood part of the code

Drake
15 Dec, 2023, 18:41

Do you have an extra fromBase32 in the verification part?

Drake
15 Dec, 2023, 18:51

maybe you can try setting the window to 2?

ZachHandley
15 Dec, 2023, 18:56

so it's this part of the code

ZachHandley
15 Dec, 2023, 18:56
TypeScript
log("MFA Setup -- Verify Code");
    const userId = req.body.userId;
      if (!req.body.mfacode && req.body.mfacode && req.body.mfacode.length != 6) {
        return res.status(500).json("Error!");
    }

    const user = await users.get(userId);
    const member = await db.getDocument("maindb", "member", userId);

    let status = 0;

    if (!user) {
        return res.status(500).json("Error!");
    }

    
    let secret = OTPAuth.Secret.fromBase32(member.mfaCode);
    let totp = new OTPAuth.TOTP({
      issuer: encodeURIComponent('PVA.ai'),
      label: encodeURIComponent(user.email),
      algorithm: 'SHA1',
      digits: 6,
      period: 30,
      secret: secret,
    }); //<----- here specifically
    let token = totp.generate();
    let tokenSame = totp.validate({ token: req.body.mfacode });

    log(`mfaToken: ${token} -- req.body.mfacode: ${req.body.mfacode} -- tokenSame: ${tokenSame}`);
    log(`Timestamp right now: ${Date.now().toFixed(4)} -- Timestamp sent: ${timestamp} -- Difference: ${Date.now().toFixed(4) - timestamp}`);

    if (tokenSame) {

        let data = {
            mfaSetup: true,
        };
        await db.updateDocument("maindb", "member", userId, data);
        status = 1;

        try {

            return res.json({
                type: "success",
                status: status,
            });

        } catch (error) {
            log(error);
            return res.json({ type: "error", message: error });
        }

    } else {
      return res.json({
        type: "error",
        message: "Token Mismatch",
        status: status,
      })
    }
ZachHandley
15 Dec, 2023, 18:57

the validate doesn't work, and I've tried setting window to 2, I've tried a lot of different things and for some reason it doesn't work

Drake
15 Dec, 2023, 19:01

Do you have an extra fromBase32 in the verification part?

I meant a few lines up when you're creating the secret from the member.mfaCode.

What you stored in mfaCode is already a result of Secret.fromBase32() but then you're running it through that again

ZachHandley
15 Dec, 2023, 19:12

what do you mean? Can you be more specific? I set up the totp as the instance to generate the token

ZachHandley
15 Dec, 2023, 19:12

but the token vs the code

ZachHandley
15 Dec, 2023, 19:13

the code is the users secret code, the token is the 6 digit token, so I'm generating the secret for that user and then storing the result and using it to generate the 6 digit code that it stores

ZachHandley
15 Dec, 2023, 19:13

that it returns"

Drake
15 Dec, 2023, 19:19
TypeScript
-let secret = OTPAuth.Secret.fromBase32(member.mfaCode);
+let secret = member.mfaCode;
Drake
15 Dec, 2023, 19:20

or something. i think there's mishandling of the secret

Drake
15 Dec, 2023, 19:21

I also think this is incorrect:

TypeScript
let secret = OTPAuth.Secret.fromBase32(crypto.randomBytes(20));
Drake
15 Dec, 2023, 19:22

the input of that is supposed to be a base32 string, but you're passing in a buffer

Drake
15 Dec, 2023, 19:24

When initializing, you should probably be doing:

TypeScript
let secret = new OTPAuth.Secret({buffer: crypto.randomBytes(20)});

and then store secret.base32 in the document.

Then, you can do:

TypeScript
let secret = OTPAuth.Secret.fromBase32(member.mfaCode);
ZachHandley
15 Dec, 2023, 19:25

hmm okay, gotcha, thank you, that makes sense that that could be it

Reply

Reply to this thread by joining our Discord

Reply on Discord

Need support?

Join our Discord

Get community support by joining our Discord server.

Join Discord

Get premium support

Join Appwrite Pro and get email support from our team.

Learn more