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
Blinko
Knowledge Management · Note Taking
A self-hosted, AI-powered card note-taking tool that lets you capture fleeting thoughts instantly and retrieve them with natural language search.
Cal.diy
Scheduling
The 100% MIT-licensed, community-driven scheduling platform — self-host your own booking infrastructure with no enterprise strings attached.
Countly
Analytics · Marketing
Privacy-first, self-hosted analytics and customer engagement platform with full data ownership, GDPR compliance, and AI-powered insights across mobile, web, desktop, and IoT.
Directus
CMS · Low Code Platforms
Connect any SQL database and get instant REST and GraphQL APIs, a visual management Studio, and a native MCP server for AI agents — free for most organizations.
Formbricks
Forms Surveys · Marketing · Analytics
Open-source experience management platform for in-app, website, email, and link surveys — privacy-first and fully self-hostable.
Ghost
CMS · Blogging
Open source headless Node.js CMS for professional publishing, paid memberships, and newsletters with a fully owned audience.
Grist
Databases · No Code Platforms
A modern relational spreadsheet that combines Python-powered formulas, drag-and-drop dashboards, and granular access controls in a self-hostable, SQLite-backed data platform.
hoodik
File Storage · Security
Self-hosted, end-to-end encrypted cloud storage with browser-based encryption and S3-compatible storage support
Huly Platform
Project Management · Team Chat · Collaboration
Open-source all-in-one workspace that replaces Linear, Jira, Slack, and Notion for product and engineering teams.