TOTP code not synced to the right time

I’ve had some problems using Duo-generated TOTP tokens and it looks like Duo Mobile isn’t properly considering the time when calculating how much time is left for the TOTP token.

To test, I took a TOTP seed for one service and added it to Duo Mobile, 1Password, and Google Authenticator. All three showed the same TOTP value initially, but if I generate a TOTP code in the middle of a time interval (the standard is 30 seconds, so wait until say 15 or 45 seconds past the minute) 1Password and Google Authenticator show I have just a few seconds left while Duo Mobile says I have the full 30 seconds.

I waited until 1Password and Google Authenticator changed the displayed TOTP code, tried to use the code shown in Duo (which matches the code previously shown by 1Password and Google Authenticator), and it failed as an incorrect token. Log in with the 1Password/Google Authenticator code and it works. And when Duo Mobile gets to the end of its 30-second countdown the TOTP code changes to match 1Password and Google Authenticator.

So it seems like Duo Mobile is correctly generating the TOTP code based on the current time, but it’s incorrectly determining how much time is left before that code needs to be regenerated. Is there perhaps something I’ve done wrong?

Howdy @jgoguen!

You are correct that in most implementations of TOTP organizations choose to only show a passcode as valid until the 0 or 30 second mark before showing a new one. It’s the case that in practice passcodes are actually valid for the window before, during, and after they’re generated to account for time drift. Because of this, we choose to display the passcode for a full 30 seconds, to alleviate the rushed feeling when a TOTP is nearing the end of its generation window. It should always be the case that passcodes shown in Duo Mobile are valid. I’d be curious to know which service you were authenticating against where this wasn’t the case.

The official TOTP spec can be found here (in case you’re up for some “light reading”): https://tools.ietf.org/html/rfc6238#section-5.2

Hope this clears some things up.

1 Like

I’d be curious to know which service you were authenticating against where this wasn’t the case.

Relatively few services, but they’re also the services I have to use TOTP frequently for and don’t have a better alternative, like Duo integration or WebAuthN. :slight_smile:

So far I’ve been able to reproduce this with high reliability (not 100%, likely due to accounting for time drift, but quite often) on:

  • AirTable
  • Microsoft (live.com)
  • Amazon
  • Gitlab (one service, but thanks to subdomains and hosting options is actually 3 instances for me)
  • IFTTT
  • Ubiquity (ubnt.com and ui.com)

But, reading that spec, it looks like Duo and all of those services are all following the spec:

We RECOMMEND that at most one time step is allowed as the network delay.

That language lets Duo decide that in the absence of any hinting (which I don’t see any way to provide without non-standard otpauth URI parameters) that a TOTP valid for a standard 30-second time window T will be displayed for T+20sec and allows me as a validator to decide that I’ll accept a TOTP code for time window T up to T+5sec. These are fundamentally incompatible choices, but as I read it both are completely adhering to the specification. I’m surprised they didn’t mandate a certain minimum acceptable time drift, which would make this an easy fix (“just go to the minimum drift instead of the full 30 seconds”).

There are a couple changes I see that could help though, but I’m not sure which (if any) would fit well in the admirably simple Duo app:

  • Add a config option for people who run into this a lot. Either a “strict TOTP window” toggle, default off, that displays the TOTP code strictly until the end of the time window; or a “maximum TOTP drift” integer option bounded by [5, window_size). I’d probably go for the toggle there.
  • When displaying the TOTP code, the counter colour (at least for me, on Android using the dark UI theme) is blue at first and then changes to yellow when it reaches 10 seconds and red at 5 seconds. Using some other colour (I’m not a UI person at all so I won’t even speculate at which colour might be a good option), indicate that the strict TOTP window has expired and allow tapping on the counter (not the TOTP code) to immediately show the TOTP code for the now-current time window.
1 Like

Thanks sharing those services and your suggestions. We’ll look into + try to replicate issues you’re having and follow up if we discover anything.

One possibly useful note: Force closing + relaunching Duo Mobile and generating a passcode is one workaround to any potential out of sync issues.

Thanks again for the feedback!