@otplib/core
Core types, interfaces, and utilities for the otplib OTP library suite.
Overview
@otplib/core provides the foundational abstractions for all otplib packages. It includes:
- Type Definitions: TypeScript interfaces for OTP operations
- Error Classes: Hierarchical error types for validation and crypto operations
- Validation Utilities: Input validation for secrets, counters, time, and tokens
- Crypto Abstraction: Pluggable crypto backend via
CryptoContext
- Base32 Abstraction: Pluggable Base32 encoding/decoding via
Base32Context
Installation
npm install @otplib/core
pnpm add @otplib/core
yarn add @otplib/core
Core Concepts
Plugin Architecture
otplib uses a plugin architecture for both cryptographic operations and Base32 encoding:
import type { CryptoPlugin, Base32Plugin } from "@otplib/core";
interface CryptoPlugin {
name: string;
hmac(
algorithm: HashAlgorithm,
key: Uint8Array,
data: Uint8Array,
): Uint8Array | Promise<Uint8Array>;
randomBytes(length: number): Uint8Array;
}
interface Base32Plugin {
name: string;
encode(data: Uint8Array, options?: Base32EncodeOptions): string;
decode(str: string): Uint8Array;
}
CryptoContext
The CryptoContext class provides a unified interface for crypto operations:
import { createCryptoContext } from "@otplib/core";
import { NodeCryptoPlugin } from "@otplib/plugin-crypto-node";
const crypto = createCryptoContext(new NodeCryptoPlugin());
const digest = await crypto.hmac("sha1", key, data);
const digest = crypto.hmacSync("sha1", key, data);
const secret = crypto.randomBytes(20);
Base32Context
The Base32Context class provides a unified interface for Base32 operations:
import { createBase32Context } from "@otplib/core";
import { ScureBase32Plugin } from "@otplib/plugin-base32-scure";
const base32 = createBase32Context(new ScureBase32Plugin());
const encoded = base32.encode(new Uint8Array([1, 2, 3]), { padding: false });
const decoded = base32.decode("MFRGGZDFMZTWQ");
Validation Utilities
Secret Validation
import { validateSecret, MIN_SECRET_BYTES, RECOMMENDED_SECRET_BYTES } from "@otplib/core";
try {
validateSecret(secretBytes);
} catch (error) {
if (error instanceof SecretTooShortError) {
console.error(`Secret must be at least ${MIN_SECRET_BYTES} bytes`);
} else if (error instanceof SecretTooLongError) {
console.error(`Secret must not exceed ${RECOMMENDED_SECRET_BYTES} bytes`);
}
}
Counter Validation
import { validateCounter, MAX_COUNTER } from "@otplib/core";
try {
validateCounter(123n);
validateCounter(0);
} catch (error) {
if (error instanceof CounterNegativeError) {
console.error("Counter cannot be negative");
} else if (error instanceof CounterOverflowError) {
console.error(`Counter exceeds maximum (${MAX_COUNTER})`);
}
}
Time and Period Validation
import { validateTime, validatePeriod, MIN_PERIOD, MAX_PERIOD } from "@otplib/core";
validateTime(Math.floor(Date.now() / 1000));
validatePeriod(30);
Token Validation
import { validateToken } from "@otplib/core";
try {
validateToken("123456", 6);
} catch (error) {
if (error instanceof TokenLengthError) {
console.error("Token has incorrect length");
} else if (error instanceof TokenFormatError) {
console.error("Token must contain only digits");
}
}
Utility Functions
Counter Conversion
import { counterToBytes } from "@otplib/core";
const counterBytes = counterToBytes(42n);
Dynamic Truncation (RFC 4226)
import { dynamicTruncate } from '@otplib/core';
const hmacResult = new Uint8Array([...]);
const truncated = dynamicTruncate(hmacResult);
OTP Generation
import { truncateDigits } from "@otplib/core";
const otp = truncateDigits(123456789, 6);
Constant-Time Comparison
import { constantTimeEqual } from "@otplib/core";
const isValid = constantTimeEqual("123456", "123456");
const isValid = constantTimeEqual(uint8Array1, uint8Array2);
Error Handling
All errors extend from OTPError:
import {
OTPError,
SecretError,
SecretTooShortError,
SecretTooLongError,
CounterError,
CounterNegativeError,
CounterOverflowError,
TimeError,
PeriodError,
TokenError,
TokenLengthError,
TokenFormatError,
CryptoError,
HMACError,
RandomBytesError,
} from "@otplib/core";
try {
} catch (error) {
if (error instanceof SecretTooShortError) {
} else if (error instanceof CryptoError) {
}
}
Type Definitions
Hash Algorithms
type HashAlgorithm = "sha1" | "sha256" | "sha512";
OTP Digits
type Digits = 6 | 7 | 8;
HOTP Options
interface HOTPOptions {
secret: Uint8Array;
counter: number | bigint;
algorithm?: HashAlgorithm;
digits?: Digits;
}
TOTP Options
interface TOTPOptions {
secret: Uint8Array;
epoch?: number;
algorithm?: HashAlgorithm;
digits?: Digits;
period?: number;
}
Verification Options
interface HOTPVerifyOptions extends HOTPOptions {
token: string;
counterTolerance?: number | number[];
}
interface TOTPVerifyOptions extends TOTPOptions {
token: string;
epochTolerance?: number | [number, number];
}
interface VerifyResult {
valid: boolean;
delta?: number;
}
Related Packages
@otplib/hotp - HOTP implementation
@otplib/totp - TOTP implementation
@otplib/plugin-crypto-node - Node.js crypto plugin
@otplib/plugin-crypto-web - Web Crypto API plugin
@otplib/plugin-base32-scure - Base32 plugin using @scure/base
Documentation
Full documentation available at otplib.yeojz.dev:
License
MIT © 2026 Gerald Yeo