Security-hardened TOTP for JavaScript & TypeScript. Zero dependencies, constant-time verification, replay protection.
Generate and verify TOTP codes in your browser. Same RFC 6238 algorithm as the library — running entirely client-side via the Web Crypto API.
No secrets leave your browser. Powered by the Web Crypto API.
Install via your preferred package manager. Requires Node.js 18+ with native crypto support.
npm install @authcraft/totp-jsyarn add totp-jspnpm add totp-jsGenerate and verify TOTP codes in four lines of code.
import { TOTP, generateSecret, Algorithm } from '@authcraft/totp-js';
// 1. Generate a secret for a new user
const secret = generateSecret(Algorithm.SHA256);
// 2. Create a TOTP instance
const totp = TOTP.defaultInstance();
// 3. Generate a code
const code = totp.generate(secret);
// 4. Verify user input
const valid = totp.verify(secret, userCode);
console.log(valid); // true or falsePrevent the same TOTP code from being used twice within its validity window.
import { TOTP, InMemoryReplayGuard } from '@authcraft/totp-js';
// Create a replay guard with 2-minute retention
const replayGuard = new InMemoryReplayGuard(120_000);
// Create TOTP with replay protection
const totp = TOTP.create({ replayGuard });
// Verify with a userId for per-user tracking
const valid = totp.verify(secret, code, userId);
// Same code + same userId = rejected on second attempt
// Or auto-configure retention based on TOTP config
const guard = InMemoryReplayGuard.forConfig({ period: 30, allowedDrift: 1 });Build otpauth:// URIs for authenticator apps like Google Authenticator, Microsoft Authenticator, and Authy.
import { buildOtpauthUri, sha256Config } from '@authcraft/totp-js';
// Build an otpauth:// URI for QR code generation
const uri = buildOtpauthUri(
secret,
'user@example.com',
'MyApp',
sha256Config()
);
// Result: otpauth://totp/MyApp%3Auser%40example.com?secret=...&issuer=MyApp&algorithm=SHA256&digits=6&period=30
// Use with any QR library (e.g., qrcode npm package)
import QRCode from 'qrcode';
const dataUrl = await QRCode.toDataURL(uri);Use preset configurations or create fully custom ones.
import { defaultConfig, sha256Config, highSecurityConfig } from '@authcraft/totp-js';
// Google Authenticator compatible (SHA-1, 6 digits, 30s)
defaultConfig();
// Recommended for new apps (SHA-256, 6 digits, 30s)
sha256Config();
// Maximum security (SHA-512, 8 digits, 30s)
highSecurityConfig();import { TOTP, Algorithm } from '@authcraft/totp-js';
const totp = TOTP.create({
algorithm: Algorithm.SHA256, // SHA1, SHA256, SHA512
digits: 8, // 6-8 digits
period: 30, // 15-120 seconds
allowedDrift: 1, // time window tolerance
});Drop-in examples for popular Node.js frameworks.
import express from 'express';
import {
TOTP, generateSecret, buildOtpauthUri,
Algorithm, InMemoryReplayGuard, sha256Config
} from '@authcraft/totp-js';
const app = express();
const totp = TOTP.create({
algorithm: Algorithm.SHA256,
replayGuard: new InMemoryReplayGuard(120_000),
});
app.post('/2fa/enroll', (req, res) => {
const secret = generateSecret(Algorithm.SHA256);
// Store secret in database (encrypted)
const uri = buildOtpauthUri(secret, req.user.email, 'MyApp', sha256Config());
res.json({ secret, uri });
});
app.post('/2fa/verify', (req, res) => {
const { code } = req.body;
const secret = getUserSecret(req.user.id); // from DB
const valid = totp.verify(secret, code, req.user.id);
res.json({ valid });
});// app/api/2fa/verify/route.ts
import { NextResponse } from 'next/server';
import { TOTP, Algorithm, InMemoryReplayGuard } from '@authcraft/totp-js';
const totp = TOTP.create({
algorithm: Algorithm.SHA256,
replayGuard: new InMemoryReplayGuard(120_000),
});
export async function POST(request: Request) {
const { code, userId } = await request.json();
const secret = await getUserSecret(userId);
const valid = totp.verify(secret, code, userId);
return NextResponse.json({ valid });
}import { Injectable } from '@nestjs/common';
import {
TOTP, generateSecret, buildOtpauthUri,
Algorithm, InMemoryReplayGuard, sha256Config
} from '@authcraft/totp-js';
@Injectable()
export class TwoFactorService {
private readonly totp = TOTP.create({
algorithm: Algorithm.SHA256,
replayGuard: new InMemoryReplayGuard(120_000),
});
enrollUser(email: string): { secret: string; uri: string } {
const secret = generateSecret(Algorithm.SHA256);
const uri = buildOtpauthUri(secret, email, 'MyApp', sha256Config());
return { secret, uri };
}
verifyCode(userId: string, code: string, secret: string): boolean {
return this.totp.verify(secret, code, userId);
}
}import Fastify from 'fastify';
import {
TOTP, generateSecret, buildOtpauthUri,
Algorithm, InMemoryReplayGuard, sha256Config
} from '@authcraft/totp-js';
const app = Fastify();
const totp = TOTP.create({
algorithm: Algorithm.SHA256,
replayGuard: new InMemoryReplayGuard(120_000),
});
app.post('/2fa/enroll', async (request, reply) => {
const secret = generateSecret(Algorithm.SHA256);
const uri = buildOtpauthUri(secret, request.user.email, 'MyApp', sha256Config());
return { secret, uri };
});
app.post('/2fa/verify', async (request, reply) => {
const { code } = request.body as { code: string };
const secret = await getUserSecret(request.user.id);
const valid = totp.verify(secret, code, request.user.id);
return { valid };
});Generate cryptographically secure secrets sized appropriately for each algorithm.
import { generateSecret, generateSecretBytes, isValidSecret, Algorithm } from '@authcraft/totp-js';
// Generate for a specific algorithm (recommended)
const sha1Secret = generateSecret(Algorithm.SHA1); // 20 bytes / 160 bits
const sha256Secret = generateSecret(Algorithm.SHA256); // 32 bytes / 256 bits
const sha512Secret = generateSecret(Algorithm.SHA512); // 64 bytes / 512 bits
// Or specify exact byte length
const secret = generateSecretBytes(32);
// Validate a Base32 secret
const valid = isValidSecret(secret); // trueFull compliance with TOTP (RFC 6238) and HOTP (RFC 4226) standards. Tested against reference vectors.
No runtime dependencies. Uses Node.js built-in crypto module for all cryptographic operations.
Built-in InMemoryReplayGuard prevents the same code from being used twice. Pluggable via the ReplayGuard interface.
All code comparisons use constant-time algorithms to prevent timing side-channel attacks.
Written in TypeScript with full type definitions. Supports ESM and CommonJS out of the box.
Ready-to-use presets: defaultConfig, sha256Config, and highSecurityConfig.
| Method | Description |
|---|---|
TOTP.create(options?) | Create instance with custom options (algorithm, digits, period, drift, replayGuard) |
TOTP.defaultInstance() | Create instance with default config (SHA-1, 6 digits, 30s) |
generate(secret) | Generate TOTP code for the current time |
generateAt(secret, timestamp) | Generate code for a specific Unix timestamp (ms) |
verify(secret, code, userId?) | Verify a code. Returns boolean. Includes replay protection when userId provided. |
verifyWithDetails(secret, code, userId?) | Verify with detailed result: { valid, timeOffset, message } |
getSecondsRemaining() | Seconds until current code expires |
getCurrentCounter() | Current TOTP time counter value |
| Function | Algorithm | Digits | Period | Use Case |
|---|---|---|---|---|
defaultConfig() | SHA-1 | 6 | 30s | Google Authenticator compatible |
sha256Config() | SHA-256 | 6 | 30s | Recommended for new apps |
highSecurityConfig() | SHA-512 | 8 | 30s | Maximum security |
createConfig(opts) | Create custom config with validation (period 15-120s, digits 6-8, drift 0-5) | |||
| Algorithm | Key Size | Constant | Use Case |
|---|---|---|---|
| SHA-1 | 20 bytes (160 bits) | Algorithm.SHA1 | Legacy / Google Authenticator |
| SHA-256 | 32 bytes (256 bits) | Algorithm.SHA256 | Recommended |
| SHA-512 | 64 bytes (512 bits) | Algorithm.SHA512 | Maximum security |
| Function | Description |
|---|---|
generateSecret(algorithm?) | Generate Base32-encoded secret sized for the given algorithm |
generateSecretBytes(length?) | Generate Base32 secret with exact byte length (min 16) |
generateRawSecret(length?) | Generate raw Uint8Array secret bytes |
isValidSecret(secret) | Validate a Base32 secret string |
buildOtpauthUri(secret, account, issuer, config?) | Build otpauth:// URI for QR codes |
algorithmFromName(name) | Look up algorithm by string name (e.g. "SHA256") |
InMemoryReplayGuard with auto-expiry, or implement the ReplayGuard interface for Redis/database-backed stores.node:crypto module backed by OpenSSL.TOTPError with ErrorCode enum for programmatic error handling.