/otpauth

One Time Password (HOTP/TOTP) library for Node.js, Deno, Bun and browsers.

Primary LanguageJavaScriptMIT LicenseMIT

Last version npm downloads

OTPAuth

OTPAuth

One Time Password library for Node.js, Deno, Bun and browsers.

It supports the generation and validation of HMAC-Based One-Time Passwords (HOTP) as specified in RFC 4226 and Time-Based One-Time Passwords (TOTP) as specified in RFC 6238. Frequently used in Multi-Factor Authentication (MFA) / Two-Factor Authentication (2FA) systems.

Tip

You can try the library with the demo application available at otpauth.molinero.dev.

If you wish to interact with the library in your browser console, the following snippet can be used:

const OTPAuth = await import("otpauth");

Usage

This section presents an overview of the most common usage patterns, along with some security recommendations.

import * as OTPAuth from "otpauth";

// Create a new TOTP object.
let totp = new OTPAuth.TOTP({
  // Provider or service the account is associated with.
  issuer: "ACME",
  // Account identifier.
  label: "Alice",
  // Algorithm used for the HMAC function, possible values are:
  //   "SHA1", "SHA224", "SHA256", "SHA384", "SHA512",
  //   "SHA3-224", "SHA3-256", "SHA3-384" and "SHA3-512".
  algorithm: "SHA1",
  // Length of the generated tokens.
  digits: 6,
  // Interval of time for which a token is valid, in seconds.
  period: 30,
  // Arbitrary key encoded in base32 or `OTPAuth.Secret` instance
  // (if omitted, a cryptographically secure random secret is generated).
  secret: "US3WHSG7X5KAPV27VANWKQHF3SH3HULL",
  //   or: `OTPAuth.Secret.fromBase32("US3WHSG7X5KAPV27VANWKQHF3SH3HULL")`
  //   or: `new OTPAuth.Secret()`
});

// Unless you know what you are doing, it is recommended to use the default
// values for the algorithm, digits, and period options, as these are the most
// common values used by most services.

// Generate a cryptographically secure random secret.
// It is NOT recommended to use less than 128 bits (16 bytes).
let secret = new OTPAuth.Secret({ size: 20 });

// Generate a token (returns the current token as a string).
let token = totp.generate();

// Validate a token (returns the token delta or null if it is not found in the
// search window, in which case it should be considered invalid).
//
// A search window is useful to account for clock drift between the client and
// server; however, it should be kept as small as possible to prevent brute
// force attacks. In most cases, a value of 1 is sufficient. Furthermore, it is
// essential to implement a throttling mechanism on the server.
//
// For further details on the security considerations, it is advised to refer
// to Section 7 of RFC 4226 and Section 5 of RFC 6238:
//   https://datatracker.ietf.org/doc/html/rfc4226#section-7
//   https://datatracker.ietf.org/doc/html/rfc6238#section-5
let delta = totp.validate({ token, window: 1 });

// Get the remaining seconds until the current token changes.
let seconds = totp.period - (Math.floor(Date.now() / 1000) % totp.period);

// Convert to Google Authenticator key URI format.
// Usually the URI is encoded in a QR code that can be scanned by the user.
// This functionality is outside the scope of the project, but there are many
// libraries that can be used for this purpose, such as `@paulmillr/qr`.
let uri = totp.toString();
//   or:      `OTPAuth.URI.stringify(totp)`
//   returns: `otpauth://totp/ACME:Alice?issuer=ACME&secret=US3WHSG7X5KAPV27VANWKQHF3SH3HULL&algorithm=SHA1&digits=6&period=30`

// Convert from Google Authenticator key URI format.
totp = OTPAuth.URI.parse(uri);
import * as OTPAuth from "jsr:@hectorm/otpauth";

// Same as above.
<script type="importmap">
  {
    "imports": { "otpauth": "https://cdn.jsdelivr.net/npm/otpauth@%VERSION%/dist/otpauth.esm.min.js" },
    "integrity": { "https://cdn.jsdelivr.net/npm/otpauth@%VERSION%/dist/otpauth.esm.min.js": "%HASH%" }
  }
</script>
<script type="module">
  import * as OTPAuth from "otpauth";

  // Same as above.
</script>
<script
  src="https://cdn.jsdelivr.net/npm/otpauth@%VERSION%/dist/otpauth.umd.min.js"
  integrity="%HASH%"
  crossorigin="anonymous"
  referrerpolicy="no-referrer"
></script>
<script>
  // Same as above.
</script>

Documentation

For additional information, please refer to the documentation page at hectorm.github.io/otpauth/.

License

MIT License © Héctor Molinero Fernández.