OTPAuth: Generate and Verify One-Time Passwords in JavaScript

Category: Form , Javascript , Recommended | November 5, 2026
Authorhectorm
Last UpdateNovember 5, 2026
LicenseMIT
Views0 views
OTPAuth: Generate and Verify One-Time Passwords in JavaScript

OTPAuth is a JavaScript library for generating and validating time-based (TOTP) and counter-based (HOTP) one-time passwords.

It allows you to handle authenticator-app enrollment URIs, shared secrets, and code validation for two-factor authentication in browsers and server-side JavaScript.

Features

  • Implements the HOTP and TOTP standards (RFC 4226 and RFC 6238).
  • Supports SHA-1, SHA-2, and SHA-3 hashing algorithms.
  • Generates random secrets with base32, hexadecimal, UTF-8, and Latin-1 representations.
  • Accepts configurable validation windows for clock drift and counter offsets.
  • Rejects previously accepted TOTP time steps using afterCounter.
  • Calculates the milliseconds remaining before a TOTP code expires.

How To Use It

Browser Setup

Use the UMD build for a plain script tag. This example generates a temporary secret and displays one TOTP code.

Keep account secrets and code verification on the server for production use.

<output id="otp-code"></output>
<script src="https://cdn.jsdelivr.net/npm/otpauth/dist/otpauth.umd.min.js"></script>
<script>
  const totp = new OTPAuth.TOTP({
    issuer: "Example App",
    label: "[email protected]"
  });
  document.querySelector("#otp-code").textContent = totp.generate();
</script>

Browser ES Modules

<script type="module">
  import * as OTPAuth from "https://cdn.jsdelivr.net/npm/otpauth/dist/otpauth.esm.min.js";
  const token = new OTPAuth.TOTP().generate();
  console.log(token);
</script>

Install with npm

Use the npm package with Node.js or Bun.

npm install otpauth
import * as OTPAuth from "otpauth";
const totp = new OTPAuth.TOTP({
  issuer: "Example App",
  label: "[email protected]",
  secret: new OTPAuth.Secret({ size: 20 })
});
console.log(totp.generate());
console.log(totp.remaining()); // Milliseconds until the next code

Create an Authenticator Enrollment URI

Generate an account secret on the server and encode its otpauth:// URI as a QR code for an authenticator app.

import * as OTPAuth from "otpauth";
const secret = new OTPAuth.Secret({ size: 20 });
const totp = new OTPAuth.TOTP({
  issuer: "Example App",
  label: "[email protected]",
  secret
});
const enrollmentUri = totp.toString();
const manualEntryKey = secret.base32;

Validate TOTP Codes and Prevent Replay

On the server, load the account secret and last accepted time-step counter (null for the first attempt). Implement saveCounter as an atomic compare-and-set operation that returns true only after saving the new counter.

import * as OTPAuth from "otpauth";
async function verifyTOTP({ secret, token, lastCounter, saveCounter }) {
  const totp = new OTPAuth.TOTP({ secret });
  const timestamp = Date.now();
  const delta = totp.validate({
    token,
    timestamp,
    window: 1,
    afterCounter: lastCounter
  });
  if (delta === null) return false;
  const matchedCounter = totp.counter({ timestamp }) + delta;
  return saveCounter(lastCounter, matchedCounter);
}

Generate and Validate HOTP Codes

HOTP uses a counter shared by the generator and verifier. Advance the stored counter past the accepted value after successful verification.

import * as OTPAuth from "otpauth";
const hotp = new OTPAuth.HOTP({
  secret: new OTPAuth.Secret({ size: 20 }),
  counter: 0
});
const token = hotp.generate();
const delta = hotp.validate({ token, counter: hotp.counter, window: 1 });
if (delta !== null) {
  hotp.counter += delta + 1;
}

Public API Reference

TOTP and HOTP Constructors

Both constructors accept an optional configuration object. Their options are public instance properties, and base32 secret strings become OTPAuth.Secret instances. OTPAuth.TOTP.defaults and OTPAuth.HOTP.defaults expose the default values, including window: 1 for validation.

new OTPAuth.TOTP({ /* options */ });
new OTPAuth.HOTP({ /* options */ });

Shared Constructor Options and Properties

APIDescription
issuerString. Account provider. Default: "".
labelString. Account identifier. Default: "OTPAuth".
issuerInLabelBoolean. Prefixes the issuer to the account label in provisioning URIs. Default: true.
secretBase32 string or OTPAuth.Secret. Default: a newly generated 20-byte secret.
algorithmString. Default: "SHA1". Supported: SHA1, SHA224, SHA256, SHA384, SHA512, SHA3-224, SHA3-256, SHA3-384, SHA3-512.
digitsNumber. OTP code length. Default: 6.
hmacOptional custom function (algorithm, key, message) => Uint8Array. Arguments are the algorithm name and key/message byte arrays. Required by the bare build.

TOTP and HOTP-Specific Options

APIDescription
totp.periodNumber. Time step in seconds. Default: 30. Public TOTP instance property.
hotp.counterNumber. Starting counter. Default: 0. Public HOTP instance property.

TOTP Instance Methods

APIDescription
totp.counter(config?)Returns the elapsed time-step counter. Optional timestamp is a millisecond timestamp (default: current time).
totp.generate(config?)Returns a TOTP code string. Optional timestamp is a millisecond timestamp (default: current time).
totp.remaining(config?)Returns milliseconds until the next code. Optional timestamp is in milliseconds (default: current time).
totp.validate(config)Required token; optional millisecond timestamp, window (default 1 time step each way), and afterCounter (rejects matched counters at or below this value). Returns a matching time-step offset or null.
totp.toString()Returns a Google Authenticator-compatible otpauth://totp/ key URI.

TOTP Static Methods

APIDescription
OTPAuth.TOTP.counter(config?)Optional period (default 30 seconds) and timestamp (milliseconds, default now). Returns the time-step counter.
OTPAuth.TOTP.generate(config)Generates a code. Required secret (base32 string or Secret); optional algorithm, digits, period, timestamp, hmac.
OTPAuth.TOTP.remaining(config?)Returns milliseconds remaining; optional period (default 30 seconds) and timestamp (milliseconds, default now).
OTPAuth.TOTP.validate(config)Returns a time-step offset or null. Required: secret, token. Optional: algorithm, digits, period, timestamp, window, afterCounter, hmac.

HOTP Instance Methods

APIDescription
hotp.generate(config?)Returns an HOTP code for optional counter or the instance counter.
hotp.validate(config)Required token; optional counter, window (default 1). Checks the specified counter and following counters; returns their offset or null.
hotp.toString()Returns an otpauth://hotp/ provisioning URI.

HOTP Static Methods

APIDescription
OTPAuth.HOTP.generate(config)Returns a code. Required secret (Secret instance); optional counter (default 0), algorithm, digits, hmac.
OTPAuth.HOTP.validate(config)Returns a matching counter offset or null. Required: secret (Secret), token. Optional: counter, window, algorithm, digits, hmac.

Secret Constructor, Properties, and Conversions

new OTPAuth.Secret() generates 20 random bytes by default. Specify size to change the length, or pass an ArrayBufferLike secret through buffer, which takes precedence over size. Use at least 16 bytes (128 bits) for authentication secrets.

const secret = new OTPAuth.Secret({ size: 20 });
const fromBuffer = new OTPAuth.Secret({ buffer: secret.bytes.slice().buffer });
APIDescription
secret.bytesRead-only Uint8Array containing the secret key bytes.
secret.base32Base32-encoded secret string.
secret.hexHex-encoded secret string.
secret.latin1Latin-1 string representation.
secret.utf8UTF-8 string representation.
secret.bufferUnderlying buffer. Deprecated; use secret.bytes for new integrations.
OTPAuth.Secret.fromBase32(str)Parses a base32 secret string and returns a Secret.
OTPAuth.Secret.fromHex(str)Parses a hexadecimal secret string.
OTPAuth.Secret.fromLatin1(str)Parses a Latin-1 string.
OTPAuth.Secret.fromUTF8(str)Parses a UTF-8 string.

URI Utilities and Library Version

APIDescription
OTPAuth.URI.parse(uri, config?)Parses an otpauth:// key URI into a TOTP or HOTP instance. Accepts an optional custom HMAC function.
OTPAuth.URI.stringify(otp)Converts a TOTP or HOTP instance into an authenticator key URI.
new OTPAuth.URI()Constructs the URI utility class; use its static methods for conversion.
OTPAuth.versionExported library version string.

Distribution Builds

APIDescription
otpauthMain package entry point for Node.js, Bun, and bundlers.
otpauth/slimES module build with external dependencies.
otpauth/bareES module build requiring a custom hmac function.
otpauth.umd.min.jsBrowser script with global OTPAuth.
otpauth.esm.min.jsBrowser ES module distribution.
jsr:@hectorm/otpauthDeno import specifier.

Related Resources

You Might Be Interested In:


Leave a Reply