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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@punikonta/node-otp

v0.1.0

Published

Simple and dependency free OTP implementation (HOTP, TOTP) for Node.js written in TypeScript. Passes RFC test vectors and works with most common authenticator apps.

Readme

Dependency free OTP implementation

Simple and dependency free OTP implementation (HOTP, TOTP) for Node.js written in TypeScript. Passes RFC test vectors and works with common authenticator apps.

Features

  • HOTP
  • TOTP (builds on top of HOTP)
  • otpauth:// URL generation

Generating QR codes for otpauth:// URLs is not within the scope of this library. There are plenty of good QR code libraries out there. Just run your URL through one of them and you're good to go. There's an example QR code that works in conjunction with the example code below if you want to test it with your own authenticator app, though.

Installation

npm install @punikonta/node-otp

Example

Example usage for TOTP in plain JavaScript:

import Otp from '@punikonta/node-otp'

// example 128 bit secret for demonstration only! don't use this in your application.
// this must be random, stored securely and be unique for each user.
const secret = Buffer.from('8eddb53e05fa936c2530c8045a58f81b', 'hex')

const token = Otp.Totp.generate(secret)
const remaining = Otp.Totp.remaining()
const url = Otp.Url.getTotpUrl('example.com', 'foobar', secret)
const valid = Otp.Totp.validate('123456', secret)

console.log(`token: ${token}`)
console.log(`valid for ${remaining.toFixed(2)} seconds`)
console.log(url)
console.log(`is 123456 valid? ${valid ? 'yes' : 'no'}`)

If you want to verify the example right away with an authenticator app, you can use the following QR code without having to generate one yourself:

example QR code

otpauth://totp/example.com:foobar?secret=R3O3KPQF7KJWYJJQZACFUWHYDM&algorithm=SHA1&digits=6&period=30&issuer=example.com

Motivation

I wanted a project with a small scope to get my hands dirty with TypeScript and NPM packaging. Also I've been looking for a TOTP library at the same time. I couldn't find one that I liked, so I decided to create my own. TOTP builds on top of HOTP, so I implemented that as well.

Remarks

I've successfully tested the TOTP functionality with the following authenticator apps:

  • Authy
  • Google Authenticator
  • Microsoft Authenticator
  • Proton Authenticator
  • Bitwarden Authenticator

Double check if you want to use anything but SHA1 as your hash algorithm. Some popular authenticator apps don't support anything else and even go as far as completely ignoring that parameter, silently giving the user wrong tokens. To catch this and other issues early, your onboarding flow should implement a successful token readback while setting up 2FA anyway.

Also don't use a window value other than 0 for HOTP unless you know what you're doing. Managing the HOTP counter is up to you.

The default window value of 1 for TOTP generally is fine and common practice to mitigate small clock drifts between the server and the user.

Don't use the Base32 class as a generic base32 encoder/decoder. Its behavior is tailored to the needs of this library and may not be suitable for other purposes than OTP secrets in URLs, mainly because it strips and ignores padding. See Google Authenticator's Key Uri Format.

API

The API uses the following types and enums:

enum HashAlgorithm {
    SHA1 = 'sha1',
    SHA256 = 'sha256',
    SHA384 = 'sha384',
    SHA512 = 'sha512',
}

type HotpOptions = {
    algorithm: HashAlgorithm
    digits: number
}

type TotpOptions = {
    algorithm: HashAlgorithm
    digits: number
    period: number
}

HOTP

Hotp.generate(
    secret: Buffer,
    counter: number,
    options?: Partial<HotpOptions>
): string

Hotp.validate(
    token: string,
    secret: Buffer,
    counter: number,
    window?: number = 0,
    options?: Partial<HotpOptions>
): boolean

// default values for option parameters that are omitted
static readonly DEFAULTS: HotpOptions = {
    algorithm: HashAlgorithm.SHA1,
    digits: 6,
}

TOTP

Totp.generate(
    secret: Buffer,
    options?: Partial<TotpOptions>,
    time?: number
): string

Totp.validate(
    token: string,
    secret: Buffer,
    options?: Partial<TotpOptions>,
    window?: number,
    time?: number
): boolean;

// remaining time until next token (seconds, fractional)
Totp.remaining(
    period: number = 30,
    time?: number = Date.now()
): number

// default values for option parameters that are omitted
static readonly DEFAULTS: TotpOptions = {
    algorithm: HashAlgorithm.SHA1,
    digits: 6,
    period: 30,
}

URL

// HOTP
Url.getHotpUrl(
    issuer: string, // usually a domain or application name
    label: string, // usually the username or email of the user
    secret: Buffer,
    counter: number,
    options?: Partial<HotpOptions>
): string

// TOTP
Url.getTotpUrl(
    issuer: string, // usually a domain or application name
    label: string, // usually the username or email of the user
    secret: Buffer,
    options?: Partial<TotpOptions>
): string

TODO

Probably a good idea to add some sanity checks in the future, e.g. for nonsensical stuff like negative periods, windows or missing mandatory parameters.

Currently the API mixes milliseconds and seconds in a few places. This needs to be addressed without making it too weird for the caller, e.g. by having them to do manual conversion of Date.now() timestamps.