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

Why sometimes is invalid my token? #67

Closed
thEpisode opened this issue Jun 15, 2018 · 6 comments
Closed

Why sometimes is invalid my token? #67

thEpisode opened this issue Jun 15, 2018 · 6 comments
Labels
support The issue is more of a support query

Comments

@thEpisode
Copy link

Hi, this is an strange behavior because sometimes is invalid the code without any modification. I used check() and verify() functions for it.

How to reproduce:

  1. Run next snippet some many times
const otplib = require('otplib')

let step = 5
let timing

otplib.authenticator.options = {
  step: step
}

const secret = otplib.authenticator.utils.encodeKey('This is my own private key without length restrictions!!')
const singleToken = otplib.authenticator.generate(secret)

console.log(singleToken)

setTimeout(() => {
  const isValid = otplib.authenticator.check(singleToken, secret)
  console.log(`Is valid first token: ${isValid}`)
}, 1001)

Details:

  • SO: Windows 10
  • Node: v8.9.3
  • Otplib: 9.0.0
@thEpisode
Copy link
Author

With a bit debugging I notice that hotpToken() function calculate systemToken wrong (inside hotpCheck function) and when is called otplibUtils.isSameToken(token, systemToken) obviously is different.

@yeojz
Copy link
Owner

yeojz commented Jun 15, 2018

hi @thEpisode

I ran the snippet and could reproduce the issue. However it is not a problem with the function.
The issue came from a falling out of the time window.

In the above snippet, you're:

  1. Using a 5s window
  2. generating a token
  3. waiting 1s before checking the token

In Authenticator and TOTP which are time based, any tokens generated within a 5s time window is the same. As such, if you generate a token at 12:00:01 and 12:00:04, it will result in the same token. So checking anywhere within this block will result in true

In the snippet above, when you generate a token and wait for 1s, you cannot guarantee you're within this same window. So when running the code, there are chances that you're generating a token at 12:00:04 and waiting for 1s results in checking the token at 12:00:05 which will cause the system token to already fall into the next block.

Try doing this:

// instead of
otplib.authenticator.options = {
  step: step
}

// use
otplib.authenticator.options = {
  step: step,
  window: [1, 0]
}


// instead of 
const isValid = otplib.authenticator.check(singleToken, secret)

// use 
const isValid = otplib.authenticator.checkDelta(singleToken, secret)

You should see some values being returned as -1, which means it falls into 1 window behind.

Hope that helps :)

@yeojz yeojz added support The issue is more of a support query not a bug labels Jun 15, 2018
@thEpisode
Copy link
Author

oh yes thanks, I need to read more about this window in this moment is not very clear for me, meanwhile could you guide me to know what is the right way to generate an OTP every 5 seconds?

@yeojz
Copy link
Owner

yeojz commented Jun 15, 2018

The following is a sample terminal application.
You'll need to npm install ora

const otplib = require('otplib');
const ora = require('ora');

let step = 5;
let currToken = 'Generating...';

otplib.authenticator.options = {
  step: step
};

const spinner = ora(currToken).start();
const secret = otplib.authenticator.utils.encodeKey('your own private key');

function generator() {
  const epoch = Math.floor(new Date().getTime() / 1000);
  const count = epoch % step;

  if (count === 0) {
    currToken = otplib.authenticator.generate(secret);
  }

  spinner.text = `[${step - count}s] - ${currToken}`;
}

setInterval(generator, 1000);

@thEpisode
Copy link
Author

Woah, wonderful, thanks

@juanGoesElectric
Copy link

hi @thEpisode

I ran the snippet and could reproduce the issue. However it is not a problem with the function. The issue came from a falling out of the time window.

In the above snippet, you're:

  1. Using a 5s window
  2. generating a token
  3. waiting 1s before checking the token

In Authenticator and TOTP which are time based, any tokens generated within a 5s time window is the same. As such, if you generate a token at 12:00:01 and 12:00:04, it will result in the same token. So checking anywhere within this block will result in true

In the snippet above, when you generate a token and wait for 1s, you cannot guarantee you're within this same window. So when running the code, there are chances that you're generating a token at 12:00:04 and waiting for 1s results in checking the token at 12:00:05 which will cause the system token to already fall into the next block.

Try doing this:

// instead of
otplib.authenticator.options = {
  step: step
}

// use
otplib.authenticator.options = {
  step: step,
  window: [1, 0]
}


// instead of 
const isValid = otplib.authenticator.check(singleToken, secret)

// use 
const isValid = otplib.authenticator.checkDelta(singleToken, secret)

You should see some values being returned as -1, which means it falls into 1 window behind.

Hope that helps :)

Hey! Just wanted to ask about what does the window array mean exactly.
I'm using totp to generate tokens for 5 minutes, and using a combination of step and window on [1, 0] appears to work. But being honest I don't understand why.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
support The issue is more of a support query
Projects
None yet
Development

No branches or pull requests

3 participants