Skip to content

Austex/otplib

 
 

Repository files navigation

otplib

Time-based (TOTP) and HMAC-based (HOTP) One-Time Password library

npm Build Status Coverage Status npm downloads TypeScript Support


About

otplib is a JavaScript One Time Password (OTP) library. It provides both functional and class based interfaces for dealing with OTP generation and verification.

It implements both HOTP - RFC 4226 and TOTP - RFC 6238, and are tested against the test vectors provided in their respective RFC specifications. These datasets can be found in the packages/tests folder.

This library is also compatible with Google Authenticator, and includes additional methods to allow you to work with Google Authenticator.

Demo and Documentation

Installation

Install the library via:

$ npm install otplib --save

# To install the Release Candidates:
$ npm install otplib@next --save
Release Type Version
Current / Stable npm
Release Candidate npm

Type Definitions

TypeScript support was introduced in v10.0.0

# Additional dependencies needed for TypeScript
$ npm install @types/node

Upgrading

This library follows semver. As such, major version bumps usually mean API changes or behavior changes. Please check upgrade notes for more information, especially before making any major upgrades.

You might also want to check out the release notes associated with each tagged versions in the releases page.

Getting Started

In node

import otplib from 'otplib';

const secret = 'KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD';
// Alternatively: const secret = otplib.authenticator.generateSecret();

const token = otplib.authenticator.generate(secret);

try {
    const isValid = otplib.authenticator.check(token, secret);
    // or
    const isValid = otplib.authenticator.verify({ token, secret });
} catch (err) {
    // Error possibly thrown by the thirty-two package
    // 'Invalid input - it is not base32 encoded string'
    console.error(err);
}

Using specific OTP implementations

If you want to include a specific OTP specification, you can import it directly:

import hotp from 'otplib/hotp';
import totp from 'otplib/totp';
import authenticator from 'otplib/authenticator';

Important: If you import the libraries directly, you will have to provide a crypto solution (this is to allow custom crypto solutions), as long as they implement createHmac and randomBytes. Take a look at the browser implementation of this package as an example.

For example:

import authenticator from 'otplib/authenticator';
import crypto from 'crypto';

authenticator.options = { crypto };

// Or if you're using the other OTP methods
// hotp.options = { crypto }
// totp.options = { crypto }

const secret = 'KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD'
const token = authenticator.generate(secret); // 556443

Using classes

For ease of use, the default exports are all instantiated instances of their respective classes. You can access the original classes via it's same name property of the instantiated class.

i.e

import hotp from 'otplib/hotp';
const HOTP = hotp.HOTP;
// const inst = new HOTP();

import totp from 'otplib/totp';
const TOTP = totp.TOTP;
// const inst = new TOTP();

import authenticator from 'otplib/authenticator';
const Authenticator = authenticator.Authenticator;
// const inst = new Authenticator();

// Alternatively, you can get it from the default module as well
import otplib from 'otplib';
const HOTP = otplib.hotp.HOTP
const TOTP = otplib.totp.TOTP
const Authenticator = otplib.authenticator.Authenticator

Using with Expo.io

Expo does not contain a randomBytes implementation within the platform-provided crypto. As such, you should avoid using otplib.authenticator.generateSecret(); and generate your own secrets instead.

In browser

A browser-targeted version has been compiled. You'll need to add the following scripts to your code:

<script src="otplib-browser.js"></script>

<script type="text/javascript">
   // window.otplib
</script>

You can find it in node_modules/otplib after you install.

Alternatively you can

<script src="https://unpkg.com/otplib@^10.0.0/otplib-browser.js"></script>

For a live example, the project site has been built using otplib-browser.js. The source code can be found here.

Browser Compatibility

In order to reduce the size of the browser package, the crypto package has been replaced with an alternative implementation. The current implementation depends on Uint8Array and the browser's native crypto methods, which may only be available in recent browser versions.

To find out more about the replacements, you can take a look at packages/otplib-browser/crypto.js

The approximate output sizes are as follows:

  • with node crypto: ~311Kb
  • with alternative crypto: ~106Kb

Advanced Usage

Ihis library been split and classified into 6 core files with other specific environment based bundles provided.

Core

file description
authenticator.js Google Authenticator bindings
core.js Functions for various steps in the OTP generation process
hotp.js Wraps core functions into an instantiated HOTP class
otplib.js Library entry file, containing all instances with crypto set up
totp.js Wraps core functions into an instantiated TOTP class
utils.js Helper utilities

Other Bundles

file description
otplib-browser.js Browser compatible package built with webpack

For more information about the functions, check out the documentation.

Notes

Setting Custom Options

All instantiated classes will have their options inherited from their respective options generator. i.e. HOTP from hotpOptions and TOTP/Authenticator from totpOptions.

All OTP classes have an object setter and getter method to override these default options.

For example,

import otplib from 'otplib';

// setting
otplib.authenticator.options = {
  step: 30,
  window: 1
};

// getting
const opts = otplib.authenticator.options;

// reset to default
otplib.authenticator.resetOptions();

Available Options

Option Type Defaults Description
algorithm string 'sha1' Algorithm used for HMAC
createHmacSecret function hotpSecret, totpSecret Transforms the secret and applies any modifications like padding to it.
crypto object node crypto Crypto module to use.
digits integer 6 The length of the token
encoding string 'ascii' ('hex' for authenticator) The encoding of secret which is given to digest
epoch (totp, authenticator) integer null Starting time since the UNIX epoch (seconds).
epoch format is non-javascript. i.e. Date.now() / 1000
step (totp, authenticator) integer 30 Time step (seconds)
window (totp, authenticator) integer or array 0 Tokens in the previous and future x-windows that should be considered valid.
If integer, same value will be used for both.
Alternatively, define array: [previous, future]

Seed / secret length

In RFC 6238, the secret / seed length for different algorithms is predefined:

HMAC-SHA1 - 20 bytes
HMAC-SHA256 - 32 bytes
HMAC-SHA512 - 64 bytes

As such, the length of the secret is padded and sliced according to the expected length for respective algorithms.

Google Authenticator

Difference between Authenticator and TOTP

The default encoding option has been set to hex (Authenticator) instead of ascii (TOTP).

Base32 Keys and RFC3548

Google Authenticator requires keys to be base32 encoded. It also requires the base32 encoder to be RFC 3548 compliant.

OTP calculation will still work should you want to use other base32 encoding methods (like Crockford's Base 32) but it will NOT be compatible with Google Authenticator.

import authenticator from 'otplib/authenticator';

const secret = authenticator.generateSecret(); // base 32 encoded hex secret key
const token = authenticator.generate(secret);

Displaying a QR code

You may want to generate and display a QR Code so that users can scan instead of manually entering the secret. Google Authenticator and similar apps take in a QR code that holds a URL with the protocol otpauth://, which you get from otplib.authenticator.keyuri.

While this library provides the "otpauth" uri, you'll need a library to generate the QR Code image.

An example is shown below:

// npm install qrcode
import qrcode from 'qrcode';
import otplib from 'otplib';

const user = 'A user name, possibly an email';
const service = 'A service name';

// v11.x.x and above
const otpauth = otplib.authenticator.keyuri(user, service, secret);

// v10.x.x and below
const otpauth = otplib.authenticator.keyuri(
    encodeURIComponent(user), encodeURIComponent(service), secret);

qrcode.toDataURL(otpauth, (err, imageUrl) => {
  if (err) {
    console.log('Error with QR');
    return;
  }
  console.log(imageUrl);
});

Note: For versions v10.x.x and below, keyuri does not URI encode user and service and it's the developer's job to do it as show above.

Getting Time Remaining / Time Used

Helper methods for getting the remaining time and used time within a validity period of a totp or authenticator token were introduced in v10.0.0.

authenticator.timeUsed(); // or totp.timeUsed();
authenticator.timeRemaining(); // or totp.timeRemaining();

// The start of a new token would be when:
// - timeUsed() === 0
// - timeRemaining() === step

Exploring with local-repl

If you'll like to explore the library with local-repl you can do so as well.

$ npm install
$ npm run build

$ npx local-repl
# You should see something like:
# Node v8.9.4, local-repl 4.0.0
# otplib 10.0.0
# Context: otplib
# [otplib] >

$ [otplib] > secret = 'KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD'
$ [otplib] > otplib.authenticator.generate(secret)

Contributing

Check out: CONTRIBUTING.md

Support Project PRs Welcome

License

otplib is MIT licensed

About

🔑 One Time Password (OTP) / 2FA for Node.js and Browser - Supports HOTP, TOTP and Google Authenticator

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 87.6%
  • HTML 3.9%
  • CSS 3.7%
  • TypeScript 3.3%
  • Shell 1.5%