
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 codeCreate 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
| API | Description |
|---|---|
issuer | String. Account provider. Default: "". |
label | String. Account identifier. Default: "OTPAuth". |
issuerInLabel | Boolean. Prefixes the issuer to the account label in provisioning URIs. Default: true. |
secret | Base32 string or OTPAuth.Secret. Default: a newly generated 20-byte secret. |
algorithm | String. Default: "SHA1". Supported: SHA1, SHA224, SHA256, SHA384, SHA512, SHA3-224, SHA3-256, SHA3-384, SHA3-512. |
digits | Number. OTP code length. Default: 6. |
hmac | Optional 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
| API | Description |
|---|---|
totp.period | Number. Time step in seconds. Default: 30. Public TOTP instance property. |
hotp.counter | Number. Starting counter. Default: 0. Public HOTP instance property. |
TOTP Instance Methods
| API | Description |
|---|---|
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
| API | Description |
|---|---|
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
| API | Description |
|---|---|
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
| API | Description |
|---|---|
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 });| API | Description |
|---|---|
secret.bytes | Read-only Uint8Array containing the secret key bytes. |
secret.base32 | Base32-encoded secret string. |
secret.hex | Hex-encoded secret string. |
secret.latin1 | Latin-1 string representation. |
secret.utf8 | UTF-8 string representation. |
secret.buffer | Underlying 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
| API | Description |
|---|---|
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.version | Exported library version string. |
Distribution Builds
| API | Description |
|---|---|
otpauth | Main package entry point for Node.js, Bun, and bundlers. |
otpauth/slim | ES module build with external dependencies. |
otpauth/bare | ES module build requiring a custom hmac function. |
otpauth.umd.min.js | Browser script with global OTPAuth. |
otpauth.esm.min.js | Browser ES module distribution. |
jsr:@hectorm/otpauth | Deno import specifier. |
Related Resources
- One-time Password Input With Vanilla JavaScript – otp-input.js
- Unstyled One-time Password Input In JavaScript – OTP Input
- Easy One Time Password Input In JavaScript – vanilla-otp.js







