Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Any workaround for "top of the minute" & "bottom of the minute" boundaries? #48

Open
nabeel-servcorp opened this issue Jul 20, 2023 · 3 comments

Comments

@nabeel-servcorp
Copy link

nabeel-servcorp commented Jul 20, 2023

Previously I added this question as a comment in #43 but I believe this merits a new post of its own because it is a different question.

The following problem assume a default expiry duration of 30 seconds is used.

If I create a new token at 10:15:00 current time, it gets expired at 10:15:30 current time, which is as expected, but when I create a new token at let's say 10:15:28 current time, it is expired after 2 seconds at 10:15:30 time mark, instead of expiring after 30 seconds.

I want my tokens to expire after exact 30 (or N) seconds, no matter I generate them at "top of the minute" or "bottom of the minute" boundaries. Is it possible?

@damiarnold
Copy link

The "boundaries" as you describe them are explicitly tied to the TOTP algorithm. When registering a client with a TOTP service endpoint, there is an initial agreement that should be established for both the "initial counter time" and the "step time" which is the interval in seconds.

The initial time (T0) is generally start of Epoch (midnight, Jan 1, 1970 UTC) and I believe is a fixed initial time used in Otp.NET (and basically every other TOTP app or implementation I've ever run across).

The step time is almost always 30 seconds (some TOTP apps just assume this and don't even provide negotiation of the time step as I seem to recall) but can be negotiated when registering a TOTP service endpoint on a client.

Since the initial time (T0) is fixed and the time step (usually 30 seconds) is fixed relative to T0, you cannot simply ask for a "relative-from-now" window at any arbitrary time. The window is explicitly tied to the initial time T0, always.

So, what this means for most TOTP implementations is that a new code is available at precisely the top and bottom of each minute at 0 seconds and 30 seconds. By having the window always tied relative to a fixed initial counter is what allows disconnected apps to even work, and why time sync is so important.

If you want to read the gory details in the RFC, look particularly at section 4.2 of RFC 6238 (https://datatracker.ietf.org/doc/html/rfc6238#section-4.2).

Hope this helps.

@nabeel-servcorp
Copy link
Author

@damiarnold Does your answer stay the same if I replace TOTP with HOTP in my question?

@damiarnold
Copy link

Not sure I'm following the question. HOTP is counter based whereas TOTP is time based.
If I'm understanding your original post, you are asking about time increments which TOTP deals with – HOTP does not.

In the case of HOTP there is no "window of time" between changes to the next valid value - it's derived from the original secret plus a counter that increments by one (1) each time the validation is performed. With TOTP, the counter is simply replaced by time steps. So in terms of RFC 4226 HOTP usage, the need for clock synchronization and time steps/windows is not even present. See https://datatracker.ietf.org/doc/html/rfc4226#section-5 for the specifics on how standard HOTP is calculated and https://www.yubico.com/resources/glossary/oath-hotp/ from Yubico that also calls this out.

Note that HOTP in many cases is paired with a specific hardware client token such as a Yubikey, whereas TOTP is provided by many standard "authentication" apps available on every major mobile device today.

Hope this helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants