speakeasy
A Node.js library for generating and verifying RFC 4226 (HOTP) and RFC 6238 (TOTP) one-time passcodes for two-factor authentication.
Repository Health
Technical Analysis
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-useotpauth://URLhotp()/totp()to compute a one-time passcode from a secret and counter or timestamp, with configurable digit length and hash algorithmhotp.verify()/totp.verify()and theirverifyDelta()counterparts to check a user-submitted token against a window of acceptable counters or time stepsotpauthURL()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.
Used by 5 apps in this directory
MyApi
AI Agents
A privacy-first personal API gateway for AI agents — connect your services once, issue scoped tokens to agents like OpenClaw, Hermes, or Claude Code, and keep a full audit trail instead of scattering raw credentials across .env files.
OpenSign
Digital Signiture
Self-host a full-featured DocuSign alternative with unlimited e-signatures, multi-signer workflows, and cryptographic PDF signing.
Palmr.
File Storage · Security
Self-hosted, privacy-focused file sharing without limits
Rocket.Chat
Team Chat
The secure, self-hosted team communications platform for organizations that cannot compromise on data sovereignty.
Termix
Devops
Manage all your servers — SSH terminals, remote desktops, file transfers, and Docker containers — from a single self-hosted browser interface.