Skip to content

General Usage for Time Based Token

Rish edited this page Apr 26, 2018 · 10 revisions

◄ Back (Verify The Token)     Next (General Usage for Counter-Based Token) ►

General Usage for Time-Based Token

var speakeasy = require("speakeasy");

Generating a key

// Generate a secret key.
var secret = speakeasy.generateSecret({length: 20});
// secret key is 20 characters long
// Access using secret.ascii, secret.hex, or secret.base32.

Getting a time-based token for the current time

// Generate a time-based token based on the base-32 key.
// HOTP (counter-based tokens) can also be used if `totp` is replaced by
// `hotp` (i.e. speakeasy.hotp()) and a `counter` is given in the options.
var token = speakeasy.totp({
  secret: secret.base32,
  encoding: 'base32'
});

// Returns token for the secret at the current time
// Compare this to user input

Verifying a time-based token

// Verify a given token
var tokenValidates = speakeasy.totp.verify({
  secret: secret.base32,
  encoding: 'base32',
  token: '123456',
  window: 6
});
// Returns true if the token matches

Verifying a time-based token and calculating a delta

A TOTP is incremented every step time-step seconds. By default, the time-step is 30 seconds. You may change the time-step using the step option, with units in seconds.

// Verify a given token is within 3 time-steps (+/- 2 minutes) from the server
// time-step.
var tokenDelta = speakeasy.totp.verifyDelta({
  secret: secret.base32,
  encoding: 'base32',
  token: '123456',
  window: 2,
  step: 60
});
// Returns {delta: 0} where the delta is the time step difference
// between the given token and the current time

Getting a time-based token for a custom time

var token = speakeasy.totp({
  secret: secret.base32,
  encoding: 'base32',
  time: 1453667708 // specified in seconds
});

// Verify a time-based token for a custom time
var tokenValidates = speakeasy.totp.verify({
  secret: secret.base32,
  encoding: 'base32',
  token: token,
  time: 1453667708
});

Using other encodings

The default encoding (when encoding is not specified) is ascii.

// Specifying an ASCII token for TOTP
// (encoding is 'ascii' by default)
var token = speakeasy.totp({
  secret: secret.ascii
});
// Specifying a hex token for TOTP
var token = speakeasy.totp({
  secret: secret.hex,
  encoding: 'hex'
});

Using other hash algorithms

The default hash algorithm is SHA1.

// Specifying SHA256
var token = speakeasy.totp({
  secret: secret.ascii,
  algorithm: 'sha256'
});
// Specifying SHA512
var token = speakeasy.totp({
  secret: secret.ascii,
  algorithm: 'sha512'
});

Getting an otpauth:// URL and QR code for non-SHA1 hash algorithms

// Generate a secret, if needed
var secret = speakeasy.generateSecret();
// By default, generateSecret() returns an otpauth_url for totp, SHA1 and
// 'SecretKey' label
// otpauth://totp/SecretKey?secret=<secret>

// Use otpauthURL() to get a custom authentication URL for SHA512
var url = speakeasy.otpauthURL({ secret: secret.ascii, label: 'Name of Secret',
  algorithm: 'sha512' });
// otpauth://totp/Name%20of%20Secret?secret=<secret>&algorithm=SHA512

// Use otpauthURL() to get a custom authentication URL for SHA512, issuer
// and digits
var url = speakeasy.otpauthURL({ secret: secret.base32, label: 'Name of Secret',
  algorithm: 'sha512', issuer:'Company', digits: 6, encoding: 'base32' });
// otpauth://totp/Name%20of%20Secret?secret=<secret>&issuer=Company&algorithm=SHA512&digits=6

// Pass URL into a QR code generator

Specifying a window for verifying TOTP

How this works:

Verify a TOTP token at the current time with a window of 2. Since the default time step is 30 seconds, and TOTP has a two-sided window, this will check tokens between [current time minus two tokens before] and [current time plus two tokens after]. In other words, with a time step of 30 seconds, it will check the token at the current time, plus the tokens at the current time minus 30 seconds, minus 60 seconds, plus 30 seconds, and plus 60 seconds – basically, it will check tokens between a minute ago and a minute from now. It will return a { delta: n } where n is the difference between the current time step and the counter position at which the token was found, or undefined if it was not found within the window. See the totp․verifyDelta(options) documentation for more info.

var verified = speakeasy.totp.verifyDelta({
  secret: secret.ascii,
  token: '123456',
  window: 2
});

The mechanics of TOTP windows are the same as for HOTP, as shown above, just with two-sided windows, meaning that the delta value can be negative if the token is found before the given time or counter.

var secret = 'rNONHRni6BAk7y2TiKrv';

// By way of example, we will force TOTP to return tokens at time 1453853945
// and at time 1453854005 (60 seconds ahead, or 2 steps ahead)
var token1 = speakeasy.totp({ secret: secret, time: 1453853945 }); // 625175
var token3 = speakeasy.totp({ secret: secret, time: 1453854005 }); // 222636
var token2 = speakeasy.totp({ secret: secret, time: 1453854065 }); // 013052

// We can check the time at token 3, 1453853975, with token 1, but use a window
// of 2 With a time step of 30 seconds, this will check all tokens from 60
// seconds before the time to 60 seconds after the time
speakeasy.totp.verifyDelta({ secret: secret, token: token1, window: 2,
  time: 1453854005 });
// => { delta: -2 }

// token is valid because because token is 60 seconds before time
speakeasy.totp.verify({ secret: secret, token: token1, window: 2, time: 1453854005 });
// => true

// token is valid because because token is 0 seconds before time
speakeasy.totp.verify({ secret: secret, token: token3, window: 2, time: 1453854005 });
// => true

// token is valid because because token is 60 seconds after time
speakeasy.totp.verify({ secret: secret, token: token2, window: 2, time: 1453854005 });

// This signifies that the given token, token1, is -2 steps away from
// the given time, which means that it is the token for the value at
// (-2 * time step) = (-2 * 30 seconds) = 60 seconds ago.

As shown previously, you can also change verifyDelta() to verify() to simply return a boolean if the given token is within the given window.