otplib
TypeScript-first TOTP and HOTP library with a pluggable crypto/base32 architecture for Node, Bun, Deno, and browsers.
Repository Health
Technical Analysis
otplib is a TypeScript-first library for generating and verifying one-time passwords, covering both RFC 6238 (TOTP) time-based codes and RFC 4226 (HOTP) counter-based codes, and staying compatible with Google Authenticator, Authy, 1Password, and other authenticator apps. Version 13 is a ground-up rewrite around a plugin interface: cryptographic HMAC operations and Base32 encoding/decoding are each swapped in through a CryptoPlugin or Base32Plugin, with security-audited defaults (@noble/hashes, @scure/base) shipped out of the box so most consumers never touch the plugin layer directly.
The library is published as a monorepo of scoped packages — @otplib/core (shared types, crypto/base32 context wrappers, error hierarchy), @otplib/hotp and @otplib/totp (the RFC algorithms), @otplib/uri (otpauth:// URI generation for QR codes), several @otplib/plugin-* packages for alternate crypto/encoding backends, and migration adapters for older otplib majors — with the otplib package itself acting as a thin, zero-config facade that re-exports a functional API (generate, verify, generateSecret, generateURI) and an equivalent OTP class API. Both async and sync variants are available depending on whether the selected crypto plugin supports synchronous operations.
Security guardrails are a deliberate design feature rather than an afterthought: secrets shorter than RFC 4226’s recommended 16 bytes throw a SecretTooShortError unless a caller explicitly overrides MIN_SECRET_BYTES via createGuardrails(), and token comparison uses constant-time equality to avoid timing side-channels. The project ships a documented tradeoff (loosening the guardrail to interoperate with the shorter secrets found in many RFC test vectors and tutorials) instead of silently accepting insecure input.
What You Get
- Functional API (
generate,verify,generateSecret,generateURI) and an equivalentOTPclass API covering both usage styles - Both TOTP (time-based) and HOTP (counter-based) strategies from a single package, selected via a
strategyoption - A plugin interface for crypto (
@otplib/plugin-crypto-noble,-node,-web) and Base32 encoding (@otplib/plugin-base32-scure,-alt), with audited defaults preselected generateURIfor buildingotpauth://URIs consumable by QR-code generators for authenticator app enrollment- Sync and async variants of generate/verify (sync requires a sync-capable crypto plugin)
- Configurable guardrails (
createGuardrails) for secret length, period, and counter/window tolerances, with the defaults matching RFC recommendations - v11 and v12 compatibility adapter packages for migrating older otplib installations to v13’s rewritten API
- A dedicated
otplib-clipackage for managing encrypted OTP vaults from the command line
Common Use Cases
- Adding TOTP-based two-factor authentication (2FA) login to a web or mobile backend, generating QR-enrollment URIs and verifying user-submitted codes
- Building an authenticator-app-compatible secret provisioning flow (Base32 secret + otpauth:// URI) for a new account security feature
- Implementing HOTP for hardware tokens or counter-based one-time codes where a shared counter (not wall-clock time) drives the token
- Replacing the default Node-only crypto backend with a Web Crypto or pure-JS (noble) plugin to run the same OTP logic in a browser, Deno, or edge runtime
- Migrating an existing project off an older otplib major version using the provided v11/v12 adapter packages without rewriting call sites
Under The Hood
Architecture
The project is a Turborepo/pnpm monorepo where otplib is a thin facade composing independently versioned scoped packages: @otplib/core defines the CryptoPlugin/Base32Plugin interfaces plus CryptoContext/Base32Context wrapper classes that normalize algorithm names and delegate to whichever plugin is configured (packages/core/src/crypto-context.ts), @otplib/hotp and @otplib/totp implement the RFC algorithms against those contexts, @otplib/uri builds otpauth:// URIs, and a family of @otplib/plugin-crypto-*/@otplib/plugin-base32-* packages supply swappable backends (Noble/pure-JS, Node crypto, Web Crypto, scure Base32, alternate encodings). The otplib package’s functional.ts and class.ts both sit on top of the same generate/verify primitives, dispatching by strategy (totp/hotp) through an executeByStrategy helper, so the two public API surfaces stay behaviorally identical by construction rather than by convention.
Tech Stack
TypeScript throughout, built per-package with tsup into ESM, CJS, and a browser-ready IIFE global bundle; Turborepo orchestrates builds/lint/typecheck across the workspace and pnpm manages the monorepo’s internal workspace:* dependencies. Testing runs on Vitest with coverage, property-based testing via fast-check, and Stryker for mutation-testing the test suite itself; VitePress (with typedoc-generated API reference) powers the docs site, and lefthook wires pre-commit checks. Default runtime dependencies are @noble/hashes and @scure/base, both independently audited cryptography libraries.
Code Quality
The repo carries 44 test files, a typed error hierarchy rooted in OTPError (with SecretError, HMACError, AlgorithmError, AlgorithmUnsupportedError, ConfigurationError subclasses using ES2022 cause chaining), and constant-time token comparison to avoid timing side-channels during verification. Guardrail validation (secret length, period, counter/window bounds) is centralized and overridable rather than hardcoded, and the CI pipeline separately runs lint, typecheck, unit tests, and distribution tests against Node, Bun, and Deno consumption of the published package, plus a Docker-based smoke test.
API Design
The package favors zero-configuration defaults (generate({ secret }) works with no plugin wiring) while still exposing the full plugin surface for callers who need a different crypto or encoding backend, and it offers both a functional and class-based API rather than forcing one style. Guardrail overrides and hooks are opt-in escape hatches documented alongside their security tradeoffs (e.g. the MIN_SECRET_BYTES override needed to interoperate with common shorter RFC test-vector secrets), and separate v11/v12 adapter packages absorb the breaking-change migration cost of the v13 rewrite instead of leaving existing consumers stranded.
Used by 22 apps in this directory
Standard Notes
Note Taking
End-to-end encrypted notes and files — private by design, built to last, and fully self-hostable.
Swetrix
Analytics
Privacy-first, cookieless web analytics with error tracking, session replays, and performance monitoring — self-host or use Cloud.
twenty
CRM
The open-source CRM you build, ship, and version like the rest of your stack — with customizable objects, AI agents, and a TypeScript SDK.
Vikunja
Project Management
Self-hosted task management with natural-language quick-add, multiple views, and a fully documented REST API — your tasks, your infrastructure, zero lock-in.