Time-based (TOTP) and HMAC-based (HOTP) One-Time Password library
- About
- Features
- Quick Start
- Migration Guide
- Getting Started
- Available Options
- Available Packages
- Notes
- License
otplib
is a JavaScript One Time Password (OTP) library for 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-data
folder.
This library is also compatible with Google Authenticator, and includes additional methods to allow you to work with Google Authenticator.
- Typescript support
- Class interfaces
- Function interfaces
- Pluggable modules (base32 / crypto)
crypto (node)
cryptojs
thirty-two
base32-encode
+base32-decode
- Presets provided
default (node)
browser
v11 (legacy/backport)
npm install otplib thirty-two
import { authenticator } from 'otplib/preset-default';
const secret = 'KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD';
// Alternative: const secret = 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) {
// Possible errors
// - options validation
// - "Invalid input - it is not base32 encoded string" (if thiry-two is used)
console.error(err);
}
The browser preset is a self contained umd
module with Buffer
split out as an external dependency.
As such, there are 2 scripts required: preset-browser/index.js
and preset-browser/buffer.js
.
<script src="https://unpkg.com/otplib@^12.0.0/preset-browser/buffer.js"></script>
<script src="https://unpkg.com/otplib@^12.0.0/preset-browser/index.js"></script>
<script type="text/javascript">
// window.otplib.authenticator
// window.otplib.hotp
// window.otplib.totp
</script>
The buffer.js
provided by this library is a cached copy
from https://www.npmjs.com/package/buffer.
You can also download and include the latest version via their project page.
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.
Check out the release notes associated with each tagged versions in the releases page.
If you're coming from v11.x
, a preset with available with classes wrapped to provide methods
that behave like v11.x
of otplib
.
// Update
import { authenticator } from 'otplib'; // v11.x
// to
import { authenticator } from 'otplib/preset-v11';
// There should be no changes to your current code.
// However, deprecated or modified class methods will have console.warn.
This is a more in-depth setup guide which includes steps for customising your dependencies. Check out the Quick Start if you do need or want to select your own dependencies.
Other References:
npm install otplib
The crypto modules are used to generate the digest used to derive the OTP tokens from.
By default, Node.js has inbuilt crypto
functionality, but you might want to replace it
for certain environments that do not support it.
Currently out-of-the-box, there are some Crypto Plugins included. Install the dependencies for one of them.
# Choose either
# Node.js crypto (you don't need to install anything else - http://nodejs.org/api/crypto.html)
# or
npm install crypto-js
If you're using Google Authenticator, you'll need a base32 module for encoding and decoding your secrets.
Currently out-of-the-box, there are some Base32 Plugins included. Install the dependencies for one of them.
# Choose either
npm install thirty-two
# or
npm install base32-encode base32-decode
import { HOTP, TOTP, Authenticator } from 'otplib';
// Base32 Plugin
// for thirty-two
import { keyDecoder, keyEncoder } from 'otplib/plugin-thirty-two';
// for base32-encode and base32-decode
import { keyDecoder, keyEncoder } from 'otplib/plugin-base32-enc-dec';
// Crypto Plugin
// for node crypto
import { createDigest, createRandomBytes } from 'otplib/plugin-crypto';
// for crypto-js
import { createDigest, createRandomBytes } from 'otplib/plugin-crypto-js';
// Setup an OTP instance which you need
const hotp = new HOTP({ createDigest });
const totp = new TOTP({ createDigest });
const authenticator = new Authenticator({
createDigest,
createRandomBytes,
keyDecoder,
keyEncoder
});
// Go forth and generate tokens
const token = hotp.generate(YOUR_SECRET, 0);
const token = totp.generate(YOUR_SECRET);
const token = authenticator.generate(YOUR_SECRET);
Alternatively, if you are using the functions directly instead of the classes, pass these as options into the functions.
import {
hotpOptions,
hotpToken,
totpOptions,
totpToken,
authenticatorOptions,
authenticatorToken
} from 'otplib/core';
// As with classes, import your desired Base32 Plugin and Crypto Plugin.
// import ...
// Go forth and generate tokens
const token = hotpToken(YOUR_SECRET, 0, hotpOptions({ createDigest));
const token = totpToken(YOUR_SECRET, totpOptions({ createDigest));
const token = authenticatorToken(YOUR_SECRET, authenticatorOptions({
createDigest,
createRandomBytes,
keyDecoder,
keyEncoder
));
Option | Type | Description |
---|---|---|
algorithm | string | The algorithm used for calculating the HMAC. |
createDigest | function | Creates the digest which token is derived from. |
createHmacKey | function | Formats the secret into a HMAC key, applying transformations (like padding) where needed. |
digits | integer | The length of the token. |
encoding | string | The encoding that was used on the secret. |
// HOTP defaults
{
algorithm: 'sha1'
createDigest: undefined, // to be provided via a otplib-plugin
createHmacKey: hotpCreateHmacKey,
digits: 6,
encoding: 'ascii',
}
Note: Includes all HOTP Options
Option | Type | Description |
---|---|---|
epoch | integer | Starting time since the UNIX epoch (seconds). epoch format is javascript. i.e. Date.now() or UNIX time * 1000 |
step | integer | Time step (seconds) |
window | integer, [number, number] |
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: [past, future] |
// TOTP defaults
{
// ...includes all HOTP defaults
createHmacKey: totpCreateHmacKey,
epoch: Date.now(),
step: 30,
window: 0,
}
Note: Includes all HOTP + TOTP Options
Option | Type | Description |
---|---|---|
createRandomBytes | function | Creates a random string containing the defined number of bytes to be used in generating a secret key. |
keyEncoder | function | Encodes a secret key into a Base32 string before it is sent to the user (in QR Code etc). |
keyDecoder | function | Decodes the Base32 string given by the user into a secret. |
// Authenticator defaults
{
// ...includes all HOTP + TOTP defaults
encoding: 'hex',
createRandomBytes: undefined, // to be provided via a otplib-plugin
keyEncoder: undefined, // to be provided via a otplib-plugin
keyDecoder: undefined, // to be provided via a otplib-plugin
}
This library has been split into 3 categories: core
, plugin
and preset
.
Provides the core functionality of the library. Parts of the logic has been separated out in order to provide flexibility to the library via available plugins.
file | description |
---|---|
otplib/hotp | HOTP functions + class |
otplib/hotp | TOTP functions + class |
otplib/authenticator | Google Authenticator functions + class |
otplib/core | Aggregates hotp/totp/authenticator functions + class |
plugin | depends on |
---|---|
otplib/plugin-crypto | crypto (included in Node.js) |
otplib/plugin-cryptojs | npm install crypto-js |
These crypto plugins provides:
{
createDigest, // used for token derivation
createRandomBytes, //used to generate random keys for Google Authenticator
}
plugin | depends on |
---|---|
otplib/plugin-thirty-two | npm install thirty-two |
otplib/plugin-base32-enc-dec | npm install base32-encode base32-decode |
These Base32 plugins provides:
{
keyDecoder, //for decoding Google Authenticator secrets
keyEncoder, // for encoding Google Authenticator secrets.
}
Presets are preconfigured HOTP, TOTP, Authenticator instances to allow you to get started with the library quickly.
Each presets would need the corresponding dependent npm modules to be installed.
file | depends on | description |
---|---|---|
otplib/preset-default | npm install thirty-two |
|
otplib/preset-browser | Buffer | Webpack bundle and is self contained. |
otplib/preset-v11 | npm install thirty-two |
Wrapper to adapt the APIs to v11.x compatible format |
otplib-preset-browser
is a umd
bundle with some node modules replaced to reduce the browser size.
The following defaults have been used:
- crypto:
crypto-js
- encoder:
base32-encode
- decoder:
base32-decode
To see what is included, you can take a look at packages/otplib-browser/index.ts
.
The approximate bundle sizes are as follows:
Bundle Type | Size |
---|---|
original | 324KB |
original, minified + gzipped | 102KB |
optimised | 29.3KB |
optimised, minified + gzipped | 9.42KB |
Paired with the gzipped browser buffer.js
module, it would be about 7.65KB + 9.42KB = 17.07KB
.
The default encoding option has been set to hex
(Authenticator) instead of ascii
(TOTP).
Note: RFC4648 obseletes RFC 3548. Any encoders following the newer specifications will work.
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 Base32) but it will NOT be compatible with Google Authenticator.
const secret = authenticator.generateSecret(); // base32 encoded hex secret key
const token = authenticator.generate(secret);
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 authenticator.keyuri
.
Google Authenticator will ignore the algorithm
, digits
, and step
options.
See the keyuri documentation
for more information.
If you are using a different authenticator app, check the documentation for that app to see if any options are ignored, which will result in invalid tokens.
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 { authenticator } from 'otplib/preset-default';
const user = 'A user name, possibly an email';
const service = 'A service name';
// v11.x.x and above
const otpauth = authenticator.keyuri(user, service, secret);
// v10.x.x and below
const otpauth = 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 encodeuser
andservice
. You'll need to do so before passing in the parameteres.
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)
otplib
is MIT licensed