
Security News
Re-Enabled GitHub Actions Expose Thousands of Repositories to Mini Shai-Hulud
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.
@otplib/core
Advanced tools
Core types, interfaces, and utilities for the otplib OTP library suite.
@otplib/core provides the foundational abstractions for all otplib packages. It includes:
CryptoContextBase32Contextnpm install @otplib/core
pnpm add @otplib/core
yarn add @otplib/core
otplib uses a plugin architecture for both cryptographic operations and Base32 encoding:
import type { CryptoPlugin, Base32Plugin } from "@otplib/core";
// Crypto plugins implement HMAC and random byte generation
interface CryptoPlugin {
name: string;
hmac(
algorithm: HashAlgorithm,
key: Uint8Array,
data: Uint8Array,
): Uint8Array | Promise<Uint8Array>;
randomBytes(length: number): Uint8Array;
}
// Base32 plugins implement encoding and decoding
interface Base32Plugin {
name: string;
encode(data: Uint8Array, options?: Base32EncodeOptions): string;
decode(str: string): Uint8Array;
}
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());
// Async HMAC computation
const digest = await crypto.hmac("sha1", key, data);
// Sync HMAC computation
const digest = crypto.hmacSync("sha1", key, data);
// Random bytes
const secret = crypto.randomBytes(20);
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());
// Encode binary data to Base32
const encoded = base32.encode(new Uint8Array([1, 2, 3]), { padding: false });
// Decode Base32 string to binary
const decoded = base32.decode("MFRGGZDFMZTWQ");
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`);
}
}
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})`);
}
}
import { validateTime, validatePeriod, MIN_PERIOD, MAX_PERIOD } from "@otplib/core";
validateTime(Math.floor(Date.now() / 1000));
validatePeriod(30); // Default TOTP period
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");
}
}
import { counterToBytes } from "@otplib/core";
// Convert counter to 8-byte big-endian array
const counterBytes = counterToBytes(42n);
// Output: Uint8Array [0, 0, 0, 0, 0, 0, 0, 42]
import { dynamicTruncate } from '@otplib/core';
// Extract 31-bit integer from HMAC result
const hmacResult = new Uint8Array([...]); // 20 bytes for SHA-1
const truncated = dynamicTruncate(hmacResult);
import { truncateDigits } from "@otplib/core";
// Convert truncated value to OTP string
const otp = truncateDigits(123456789, 6);
// Output: "456789"
import { constantTimeEqual } from "@otplib/core";
// Timing-safe comparison to prevent timing attacks
const isValid = constantTimeEqual("123456", "123456");
const isValid = constantTimeEqual(uint8Array1, uint8Array2);
All errors extend from OTPError:
import {
OTPError,
SecretError,
SecretTooShortError,
SecretTooLongError,
CounterError,
CounterNegativeError,
CounterOverflowError,
TimeError,
PeriodError,
TokenError,
TokenLengthError,
TokenFormatError,
CryptoError,
HMACError,
RandomBytesError,
} from "@otplib/core";
// Check error types
try {
// ... OTP operation
} catch (error) {
if (error instanceof SecretTooShortError) {
// Handle short secret
} else if (error instanceof CryptoError) {
// Handle crypto failure
}
}
type HashAlgorithm = "sha1" | "sha256" | "sha512";
type Digits = 6 | 7 | 8;
interface HOTPOptions {
secret: Uint8Array;
counter: number | bigint;
algorithm?: HashAlgorithm;
digits?: Digits;
}
interface TOTPOptions {
secret: Uint8Array;
epoch?: number; // Unix time in seconds
algorithm?: HashAlgorithm;
digits?: Digits;
period?: number; // Time step in seconds (default: 30)
}
interface HOTPVerifyOptions extends HOTPOptions {
token: string;
counterTolerance?: number | [number, number]; // Number: [0, n] look-ahead; Tuple: [past, future]
}
interface TOTPVerifyOptions extends TOTPOptions {
token: string;
epochTolerance?: number | [number, number]; // Time tolerance in seconds
}
interface VerifyResult {
valid: boolean;
delta?: number; // Counter/time steps from expected value
}
@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/baseFull documentation available at otplib.yeojz.dev:
MIT © 2026 Gerald Yeo
Speakeasy is a library for generating and verifying one-time passwords (OTPs) using TOTP and HOTP algorithms. It offers similar functionalities to @otplib/core but also includes additional features like QR code generation for easier secret sharing.
Notp is a minimalistic library for generating and verifying TOTP and HOTP tokens. It is lightweight and easy to use, making it a good alternative to @otplib/core for simpler use cases.
OtpAuth is a library that provides a comprehensive set of tools for generating and validating OTPs, including support for TOTP and HOTP. It also offers additional features like URI generation for easy integration with OTP apps.
FAQs
Core interfaces, types, and crypto abstraction for otplib
The npm package @otplib/core receives a total of 1,928,856 weekly downloads. As such, @otplib/core popularity was classified as popular.
We found that @otplib/core demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.

Research
/Security News
A malicious Firefox extension fetches its payload after installation to evade detection, steal Google session cookies, and automate account takeover.

Research
/Security News
The compromise affects MemTensor's MemOS, an open source memory framework for large language models (LLMs) and AI agents. Both npm package @memtensor/memos-cloud-openclaw-plugin and the PyPI package MemoryOS are compromised. They drop cross-platform Go binaries that exfiltrate developer secrets.