speakeasy

A Node.js library for generating and verifying RFC 4226 (HOTP) and RFC 6238 (TOTP) one-time passcodes for two-factor authentication.

Library
npm
v2.0.0
2,757stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
45/100Fair
Development Activity0
Maintenance20
Community60
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
51/100Fair
Architecture55
Code Quality65
Innovation40
Learning Curve45

Speakeasy implements the HMAC-based (HOTP, RFC 4226) and time-based (TOTP, RFC 6238) one-time passcode algorithms used by Google Authenticator and compatible two-factor authentication apps. It exposes a small functional API — generate a shared secret, produce a passcode from it, and verify a user-submitted token against a counter or time window — with support for SHA1, SHA256, and SHA512 HMAC digests and configurable token length.

Beyond raw passcode generation, it builds otpauth:// URLs suitable for rendering into a QR code that authenticator apps can scan, and its verify functions return a delta value so callers can resynchronize a client’s counter or clock drift rather than just getting a pass/fail boolean. The project has not been actively maintained since 2016 and is explicitly marked NOT MAINTAINED by its authors, but its RFC test vectors and API shape are still widely referenced by newer 2FA libraries in the Node ecosystem.

What You Get

  • generateSecret() to create a random shared secret in ASCII, hex, and base32 encodings, plus a ready-to-use otpauth:// URL
  • hotp()/totp() to compute a one-time passcode from a secret and counter or timestamp, with configurable digit length and hash algorithm
  • hotp.verify()/totp.verify() and their verifyDelta() counterparts to check a user-submitted token against a window of acceptable counters or time steps
  • otpauthURL() to build a Google Authenticator-compatible URL for QR-code enrollment, with issuer/label/algorithm validation baked in
  • Support for SHA1, SHA256, and SHA512 HMAC digests and both 6- and 8-digit codes, matching the RFC test vectors in its own test suite

Common Use Cases

  • Adding app-based two-factor authentication (2FA) to a login flow, verifying codes from Google Authenticator or Authy
  • Generating enrollment secrets and QR-code URLs when a user first sets up 2FA on their account
  • Validating a submitted TOTP token with a time-drift window to tolerate clock skew between server and device
  • Implementing HOTP-based hardware tokens or counter-based one-time codes where a shared counter (not time) drives the passcode

Under The Hood

Architecture Speakeasy is a single flat module (index.js) exposing a handful of top-level functions (digest, hotp, totp, generateSecret, otpauthURL) rather than any class hierarchy or plugin system. totp and totp.verifyDelta compute a counter from the current (or supplied) time and a configurable step, then delegate straight into hotp and hotp.verifyDelta, which in turn call the shared digest function that pads the secret and runs Node’s built-in crypto.createHmac. There is no dependency injection, no internal state, and no data flow beyond the options object passed into each call — every function is effectively pure given its inputs, which keeps the surface easy to reason about but means the whole library lives or dies by that one digest primitive.

Tech Stack The only runtime dependency is base32.js for base32 encode/decode; everything else is Node’s own crypto, url, and util modules, and the code targets very old Node (engines: >= 0.10.0) with ES5-style var declarations and manual Buffer construction rather than modern typed APIs. There is no build step, bundler, or TypeScript — it ships the CommonJS source as-is. Development tooling is limited to Mocha/Chai for tests, Istanbul for coverage, JSDoc for documentation generation, and semistandard for linting, wired up via Travis CI in .travis.yml.

Code Quality The test/ directory has 7 files covering HOTP and TOTP against the official RFC 4226 and RFC 6238 test vectors, plus dedicated suites for otpauthURL and legacy/deprecated option names, giving the core algorithms extensive coverage even though the project predates modern test-runner conventions. Error handling is explicit: missing secrets, tokens, or counters throw descriptive Errors prefixed with the function name (e.g. "Speakeasy - hotp - Missing secret"), and deprecated parameters (key, length, initial_time) emit console.warn deprecation notices rather than failing silently. There are no type annotations or static types anywhere in the codebase, and naming is consistent snake_case-meets-camelCase JavaScript typical of pre-2016 npm packages.

API Design The public API is small and mirrors the RFC terminology directly (hotp, totp, verify, verifyDelta), which is a plus for anyone already familiar with the OATH spec, and generateSecret() conveniently returns the secret in three encodings plus an enrollment URL in a single call. Boilerplate to get started is minimal — three or four lines to generate a secret, display a QR code, and verify a token — but the options-object calling convention (no chaining, no fluent builder) is dated, deprecated parameter names are retained rather than removed, and the library offers no promise/async API, no TypeScript types, and no WebAuthn/passkey support, all of which newer competing 2FA packages provide.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search