npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@merzin/otp

v0.4.1

Published

One-Time Password (OTP) generator and validator with support for algorithms SHA1, SHA256, SHA512 and MD5.

Readme

This is a utility to generate OTP (One-Time Password) codes. It can be used for two-factor authentication (2FA) or any other purpose where a one-time password is needed.

  • HOTP (HMAC-Based One-Time Password Algorithm): RFC 4226
  • TOTP (Time-Based One-Time Password Algorithm): RFC 6238

Features

  • Generate HOTP and TOTP codes.
  • Validate HOTP and TOTP codes.
  • Generate and parse OTP URIs.
  • Generate and parse OTP migration URIs.
  • Generate Base32 encoded secret.
  • Support for SHA1, SHA256 (SHA2), SHA512 (SHA2) and MD5 algorithms.
  • Support for custom code length and time step.
  • Support for Base32 encoded secret with padding or without padding.

Note: When implementing 2FA in your service, it is recommended to use TOTP with default options: secret with length of 20 bytes (32 characters of Base32), algorithm SHA1, digits 6 and period 30, as not all authenticator apps support other algorithms and options.

Note: When implementing an authenticator client, it is recommended to support both HOTP and TOTP and all algorithms and options to maximize compatibility with other services.

Usage

Library index @merzin/otp exports two (2) functions hotp and totp to generate HOTP and TOTP codes respectively. Rest of the package is divided into submodules for better bundle size and tree-shaking.

  • @merzin/otp
    • hotp function
    • totp function
  • @merzin/otp/types
    • OtpType type
    • OtpAlgorithm type
    • OtpParameters interface
  • @merzin/otp/generate
    • generateSecret function
  • @merzin/otp/validate
    • validateHotp function
    • validateTotp function
  • @merzin/otp/uri
    • encodeOtpUri function
    • parseOtpUri function
  • @merzin/otp/migration
    • encodeOtpMigrationUri function
    • parseOtpMigrationUri function

Generating HOTP code

Function hotp takes one (1) argument which is an object with the following properties:

  • secret: Base32 encoded secret (string)
  • algorithm: Algorithm to use (string?). Default is SHA1.
  • digits: Code length (number?). Default is 6.
  • counter: Counter (number?). Default is 0.
import { hotp } from "@merzin/otp";

const code: string = hotp({
  secret: "QRRQ4G3ZW6UY6EFODRKFLMO24POUFNKA",
  algorithm: "SHA1",
  digits: 6,
  counter: 0,
});

Generating TOTP code

Function totp takes two (2) arguments. The first argument is an object with the following properties:

  • secret: Base32 encoded secret (string)
  • algorithm: Algorithm to use (string?). Default is SHA1.
  • digits: Code length (number?). Default is 6.
  • period: Time step in seconds (number?). Default is 30.

The second argument is the time to use in milliseconds from epoch (number). Default is current time.

import { totp } from "@merzin/otp";

const code: string = totp(
  {
    secret: "QRRQ4G3ZW6UY6EFODRKFLMO24POUFNKA",
    algorithm: "SHA1",
    digits: 6,
    period: 30,
  },
  Date.now(),
);

Note: totp is a wrapper around hotp and uses the current time to calculate the counter counter = Math.floor(Date.now() / 1000 / period).

To calculate the next code, simply add the period to the current time Date.now() + period * 1000. Similarly, to calculate the previous code, subtract the period from the current time Date.now() - period * 1000. This is useful for verifying the code with a time window larger than given period.

Generate Secret

Function generateSecret takes two (2) optional arguments. The first argument is the length of the secret in bytes (number?). Default is 20 bytes (32 characters in Base32). The second argument is whether to pad the secret with "=" (boolean?). Default is false. The function returns a Base32 encoded secret.

import { generateSecret } from "@merzin/otp/generate";

const secret: string = generateSecret(20, false);

Validate HOTP

Function validateHotp takes three (3) arguments. The first argument is the HOTP parameters object (the same as in hotp function). The second argument is the code to validate (string). The third argument is an optional options object with the following properties:

  • acceptPrevious: Accept previous code(s) (boolean|number?). Default is false.
  • acceptNext: Accept next code(s) (boolean|number?). Default is true.

Function returns either null if the code is invalid or the updated counter (number) if the code is valid.

import { validateHotp } from "@merzin/otp/validate";

const updatedCounter: number | null = validateHotp(
  {
    secret: "QRRQ4G3ZW6UY6EFODRKFLMO24POUFNKA",
    algorithm: "SHA1",
    digits: 6,
    counter: 0,
  },
  "022694",
);

Validate TOTP

Function validateTotp takes three (3) arguments. The first argument is the TOTP parameters object (the same as in totp function). The second argument is the code to validate (string). The third argument is an optional options object with the following properties:

  • now: Time to use in milliseconds from epoch (number?). Default is current time.
  • acceptPrevious: Accept previous code(s) (boolean|number?). Default is true.
  • acceptNext: Accept next code(s) (boolean|number?). Default is true.

Function returns a boolean indicating whether the code is valid or not.

import { validateTotp } from "@merzin/otp/validate";

const valid: boolean = validateTotp(
  {
    secret: "QRRQ4G3ZW6UY6EFODRKFLMO24POUFNKA",
    algorithm: "SHA1",
    digits: 6,
    period: 30,
  },
  "605949",
);

OTP Parameters

Interface OtpParameters is used for encoding and decoding OTP parameters. It extends the hotp and totp objects. It has the following properties:

  • type: Type of OTP ("HOTP"|"TOTP").
  • secret: Base32 encoded secret (string).
  • name: Name of the OTP (string?).
  • issuer: Issuer of the OTP (string?).
  • algorithm: Algorithm to use ("SHA1"|"SHA256"|"SHA512"|"MD5"?).
  • digits: Code length (number?).
  • counter: Counter (number?). Should be used only for HOTP.
  • period: Time step in seconds (number?). Should be used only for TOTP.

Encode OTP URI

Function encodeOtpUri takes two (2) arguments. The first argument is OtpParameters object. The second argument is an optional boolean indicating whether to include the default options in the URI which by default is false. The function returns the OTP URI (string).

import { encodeOtpUri } from "@merzin/otp/uri";

const hotpUri: string = encodeOtpUri({
  type: "HOTP",
  secret: "QRRQ4G3ZW6UY6EFODRKFLMO24POUFNKA",
  name: "[email protected]",
  issuer: "example.com",
  algorithm: "SHA1",
  digits: 6,
  counter: 0,
});

const totpUri: string = encodeOtpUri({
  type: "TOTP",
  secret: "QRRQ4G3ZW6UY6EFODRKFLMO24POUFNKA",
  name: "[email protected]",
  issuer: "example.com",
  algorithm: "SHA1",
  digits: 6,
  period: 30,
});

Parse OTP URI

Function parseOtpUri takes one (1) argument which is the OTP URI (string). The function returns OtpParameters object. The function throws an error in the following cases:

  • URI protocol is not otpauth.
  • Type is not HOTP or TOTP (case insensitive).
  • Secret is not present.
  • Algorithm is not "SHA1", "SHA256", "SHA512" or "MD5" (case insensitive, ignores dashes).
import { parseOtpUri } from "@merzin/otp/uri";

const uri =
  "otpauth://hotp/example.com%3Auser%40mail.tld?secret=QRRQ4G3ZW6UY6EFODRKFLMO24POUFNKA&issuer=example.com&algorithm=SHA1&digits=6&counter=0";
const otpParameters: OtpParameters = parseOtpUri(uri);

Encode OTP Migration URI

Function encodeOtpMigrationUri takes two (2) arguments. The first argument is an array of OtpParameters objects. The second argument is an optional options object with the following properties:

  • autoFillDefaults: Whether to auto-fill default values (boolean?). Default is true.
  • batchId: Batch ID (number?). Default is current time in milliseconds from epoch.
  • entriesPerUri: Number of entries per URI (number?). Default is 10.
  • pad: Whether to pad the data with "=" (boolean?). Default is false.

Function returns the OTP migration URI (string).

Note: TOTP entries with period other than 30 seconds are ignored.

import { encodeOtpMigrationUri } from "@merzin/otp/migration";

const uris: string[] = encodeOtpMigrationUri([
  {
    name: "[email protected]",
    issuer: "example.com",
    secret: "QRRQ4G3ZW6UY6EFODRKFLMO24POUFNKA",
    type: "HOTP",
    algorithm: "SHA1",
    digits: 6,
    counter: 4,
  },
]);

Parse OTP Migration URI

Function parseOtpMigrationUri takes one (1) argument which is the OTP migration URI (string). The function returns an array of OtpParameters objects. The function throws an error in the following cases:

  • URI protocol is not otpauth-migration.
  • Data is not present.
import { parseOtpMigrationUri } from "@merzin/otp/migration";

const migrationUri =
  "otpauth-migration://offline?data=Ck8KFIRjDht5t6mPEK4cVFWx2uPdQrVAEg11c2VyQG1haWwudGxkGgtleGFtcGxlLmNvbSABKAEwATgEQhM3YWI4ZTUxNzQ1MDY0MzcyOTEwEAIYASAA";
const otpParametersList: OtpParameters[] = parseOtpMigrationUri(migrationUri);

Dependencies

  • rfc4648 (license MIT): Base32 decoding and encoding the secret and Base64 encoding and decoding the OTP migration URI data.
  • @noble/hashes (license MIT): HMAC and hashing algorithms SHA1, SHA256, SHA512 and MD5.
  • protobufjs (license BSD-3-Clause): Encoding and decoding the OTP parameters to and from migration URIs.

Changelog

All notable changes to this project will be documented in CHANGELOG.md.

License

MIT license. See LICENSE for details.