speakeasyjs / speakeasy

**NOT MAINTAINED** Two-factor authentication for Node.js. One-time passcode generator (HOTP/TOTP) with support for Google Authenticator.
MIT License
2.68k stars 229 forks source link

How to generate a token that is valid only 15 minutes? #124

Open MacgyverMartins opened 5 years ago

MacgyverMartins commented 5 years ago

Hi all! I'm tring to implement this logic: User types his email and the API send him a token by email (without use Google Authenticator) . This token has to be valid only for 15 minutes. But all my tentatives after generate token return false.

First question: Can I do this with speakeasy without use Google Auth.. ? Second question: If yes, do you guys can help me, by showing what I am doing wrong in this code below?

    // generate token
    const secret = speakeasy.generateSecret();
    const base32secret = secret.base32;

    const access = await Access.findOne({ where: { email: email } });
    access.base32secret = secret.base32;
    await access.save();

    return speakeasy.totp({
      secret: base32secret,
      encoding: 'base32',
      step: 900
    });
  // validate
  const access = await Access.findOne({ where: { email: email } });
  return speakeasy.totp.verify({
    secret: access.base32secret,
    encoding: 'base32',
    token: token
  });

If I remove step it works, but just for 30 seconds How can I change this? Thanks a lot

railsstudent commented 5 years ago

use window delta There is example in https://github.com/speakeasyjs/speakeasy/wiki/General-Usage-for-Time-Based-Token that uses custom time Test the delta of the token at a custom time is between 0 and 30.

MacgyverMartins commented 5 years ago

Thanks @railsstudent Sorry, but I still don't understanding very well.

I try this:

token = speakeasy.totp({ secret: secret.base32, encoding: 'base32', step: 60 });

// return true
speakeasy.totp.verify({ secret: secret.base32, encoding: 'base32', token: token, window: 6, step: 60});

// returns {delta: -8}
speakeasy.totp.verifyDelta({ secret: secret.base32, encoding: 'base32', token: token, window: 15, step: 60});

Is that right? Is this the right way ensure that token is valid only 15 minutes from now?

railsstudent commented 5 years ago

Sorry, my previous reply is incorrect.

if the token is valid for 15 minutes, step is 60 * 15 = 900. Therefore,

// token expires every 15 minutes token = speakeasy.totp({ secret: secret.base32, encoding: 'base32', step: 900 });

// validate token against the current time // return true speakeasy.totp.verify({ secret: secret.base32, encoding: 'base32', token: token, step: 900});

// compute the delta against the current time // return {delta: 0} speakeasy.totp.verify({ secret: secret.base32, encoding: 'base32', token: token, step: 900});

Thanks @railsstudent Sorry, but I still don't understanding very well.

I try this:

token = speakeasy.totp({ secret: secret.base32, encoding: 'base32', step: 60 });

// return true
speakeasy.totp.verify({ secret: secret.base32, encoding: 'base32', token: token, window: 6, step: 60});

// returns {delta: -8}
speakeasy.totp.verifyDelta({ secret: secret.base32, encoding: 'base32', token: token, window: 15, step: 60});

Is that right? Is this the right way ensure that token is valid only 15 minutes from now?