1

I would like to authenticate my users with the Authy Mobile App and TOTP.

I created these two test cases, besed on this guide https://www.twilio.com/docs/verify/quickstarts/totp#verify-a-user

I can create a Factor. But no matter what I do, I cannot verify that factor.

Step 1: Create a new factor for a new user

    @Test
    public void testCreateTotpFactor() {
        log.info("Twilio ACCOUNT_SID=" + ACCOUNT_SID);
        long now = new Date().getTime();
        String userUUID = UUID.randomUUID().toString();
        String username = "TwilioUser" + now;

        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);

        // 1. Create a new TOTP Factor  https://www.twilio.com/docs/verify/quickstarts/totp#create-a-new-totp-factor
        NewFactor newFactor = NewFactor.creator(
                        SERVICE_SID,
                        userUUID,
                        username,
                        NewFactor.FactorTypes.TOTP)
                .setConfigAppId("org.liquido")
                //.setConfigCodeLength(6)
                //.setConfigSkew(1)
                //.setConfigTimeStep(60)
                .create();

        System.out.println("========================");
        System.out.println(newFactor);
        System.out.println("========================");
        System.out.println("TOTP URL           " + newFactor.getBinding().get("uri"));
        System.out.println("Twilio Username:   " + username);
        System.out.println("Twilio userUUID:   " + userUUID);
        System.out.println("Twilio Factor_SID: " + newFactor.getSid());
        System.out.println("========================");
    }

Step 2 - Create QR code from TOTP URL

This step work, I can scan the QR code in the authy app. But for example the ConfigTimeStep is not adapted if I set it to 60 by uncommenting the line above. It is always 30. <= I am not absolutely sure if this step works correctly. What can I check/test/debug??

Step 3 - Validate this Factor by entering the first TOTP

Of course the data in this test case needs to be manually adapted from the returned values from above. And the authToken must be entered from the authy app

    @Test  // <==== This CANNOT be tested automatically. (That's the whole reason for 2FA in the first place! :-) I adapt the values and run this manually.
    public void testVerifyTotpFactor() {
        // Manually set these parameters as returned by the previous test:  testCreateTotpFactor()
        String userUUID    = "<userUUID from above>";
        String FACTOR_SID  = "<factorSID from above>";
        String authToken   = "123456";    // <==== the current token as shown in the Authy App

        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);

        System.out.println("===========================");
        System.out.println("Available TOTP Factors (FACTOR_SID) for Twilio authentication:");
        // List available factors
        ResourceSet<Factor> factors = Factor.reader(
                    SERVICE_SID,
                    userUUID)
            //.limit(20)
          .read();
        for(Factor record : factors) {
            System.out.println(record);    // <== this works. I see my one factor
        }
        System.out.println("===========================");

        // Update a factor
        Factor factor = Factor.updater(
                        SERVICE_SID,
                        userUUID,
                        FACTOR_SID)
                .setAuthPayload(authToken).update();
        System.out.println(factor);

        assertEquals(Factor.FactorStatuses.VERIFIED, factor.getStatus(), "Factor should  now be verified");   // <============ THIS ALWAYS FAILS!!!

        log.info("Successfully verified TOTP factor");
    }

The factor is always returned as "unverified". What am I missing? Are my parameters for all methods correct?

Robert
  • 1,579
  • 1
  • 21
  • 36
  • I have exactly the same issue. No matter how fast I am, its always unverified... Tried to downgrade twilio-java library but to no avail... Getting a little bit frustrated at this point, answer would be nice – Michal Heneš Apr 27 '23 at 11:19

2 Answers2

1

So I had the same exact issue and I was in contact with the devs. You need to keep the default values in the Twilio console in the Verify Service settings of the TOTP. The defaults seems to be:

Code length = 6
Time step = 30
Skew = 1

I have changed these values in my case, and everything started working again. Also keep in mind, some authentication apps like google have in the settings possibility to "Sync" time and that was really needed in my case in order to have working solution.

Hope it will work for you aswell.

Michal Heneš
  • 353
  • 2
  • 4
  • 19
  • I can confirm that it's "something in this direction". I also reverted everything back to defaults. And now it works. I even saw, that when you change the TimeStep to 60 in Java code, it actually stays 30secs in the Authenticator App on the mobile. So yes, seems to be necessary to leave these defaults. – Robert Apr 28 '23 at 14:51
0

One way to debug this is to check the creation date when working with the API and compare that to your local time. If there's a difference between the client and server time, you're most likely only going to produce unverified results (kind of like an immediate timeout). Change your phone's time to the server time and test it again. If it works, you've found your issue.

The core of the problem still most likely lies in the default values messing with the API like @MichalHeneš mentioned, but I wanted to provide another way of debugging this.

It might look like you can change the timezone in your user settings, but that's only for the console and it won't affect your API responses as all dates are given in RFC 2822 format.

Lenymm
  • 879
  • 1
  • 6
  • 27