npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

totp-web

v1.3.1

Published

A web-compatible TOTP (Time-based One-Time Password) implementation using Web Crypto API

Downloads

11

Readme

totp-web

Features

  • 🔒 Secure Implementation: Uses the Web Crypto API for cryptographic operations
  • 🌐 Browser Compatible: Works in all modern browsers without polyfills
  • 🪶 Zero Dependencies: Lightweight with no external dependencies
  • 📦 TypeScript Support: Full type definitions out of the box
  • Module Support: Compatible with both ESM and CommonJS
  • 🔄 Real-time Updates: Generate tokens that update every 30 seconds
  • 📱 QR Code Support: Generate QR codes for easy setup with authenticator apps
  • 🧪 Verification: Verify tokens with configurable time windows for clock skew
  • 🔐 Multiple Algorithms: Support for SHA-1, SHA-256, and SHA-512
  • 🎨 Custom Character Sets: Generate tokens with custom character sets
  • 🛡️ Rate Limiting: Built-in rate limiting utility to prevent brute force attacks

Motivation

Two-factor authentication (2FA) has become a standard security practice for protecting user accounts. While many services offer 2FA, implementing it in web applications has traditionally required server-side components or complex client-side libraries with dependencies.

totp-web was created to address these challenges:

  1. Client-Side Only: Enable 2FA functionality without requiring server-side token generation
  2. Simplicity: Provide a straightforward API for generating and verifying TOTP tokens
  3. Security: Leverage the Web Crypto API for secure cryptographic operations
  4. Performance: Keep the library lightweight with zero dependencies
  5. Accessibility: Make 2FA implementation accessible to developers of all skill levels

This package is particularly useful for:

  • Progressive Web Apps (PWAs) that need offline 2FA capabilities
  • Single Page Applications (SPAs) that want to reduce server load
  • Applications that need to implement 2FA without backend changes
  • Developers who want to understand how TOTP works through a clean implementation

Installation

# Using npm
npm install totp-web

# Using yarn
yarn add totp-web

# Using pnpm
pnpm add totp-web

Usage

Basic Token Generation

import { generateTOTP } from 'totp-web';

// Generate a TOTP token for a secret
const secret = 'JBSWY3DPEHPK3PXP'; // Base32 encoded secret
const result = await generateTOTP({ secret });

console.log('Current TOTP:', result.token); // e.g., "123456"
console.log('Seconds until next token:', result.remainingSeconds); // e.g., 15

Advanced Token Generation

import { generateTOTP } from 'totp-web';

// Generate a TOTP token with custom options
const result = await generateTOTP({
  secret: 'JBSWY3DPEHPK3PXP',
  algorithm: 'SHA-256', // Use SHA-256 instead of default SHA-1
  digits: 8, // Generate 8-digit token instead of default 6
  charSet: '0123456789ABCDEF', // Use hexadecimal characters
  period: 60, // Use 60-second period instead of default 30
  window: 1 // Allow for 1 period of clock skew
});

console.log('Current TOTP:', result.token); // e.g., "1A2B3C4D"
console.log('Seconds until next token:', result.remainingSeconds); // e.g., 45

Token Verification

import { verifyTOTP } from 'totp-web';

// Verify a TOTP token
const secret = 'JBSWY3DPEHPK3PXP';
const token = '123456';
const isValid = await verifyTOTP(token, { secret });

console.log('Token is valid:', isValid); // true or false

// Verify with custom window (default is 1)
// This allows for time skew of ±{window} 30-second periods
const isValidWithWindow = await verifyTOTP(token, { secret, window: 2 });

// Verify with custom options
const isValidWithOptions = await verifyTOTP(token, { 
  secret, 
  algorithm: 'SHA-256',
  digits: 8,
  charSet: '0123456789ABCDEF',
  period: 60
});

Generating QR Codes for Authenticator Apps

import { getTOTPAuthUri } from 'totp-web';

// Generate a URI for QR code generation
const secret = 'JBSWY3DPEHPK3PXP';
const uri = getTOTPAuthUri({
  secret,
  accountName: '[email protected]',
  issuer: 'MyApp',
  algorithm: 'SHA-256',
  digits: 8,
  period: 60
});

// Use this URI with any QR code library
// For example, with qrcode.react:
import { QRCodeSVG } from 'qrcode.react';

function QRCodeComponent() {
  return <QRCodeSVG value={uri} size={200} />;
}

Rate Limiting

import { RateLimiter } from 'totp-web';

// Create a rate limiter with 5 attempts per minute
const limiter = new RateLimiter(5, 60000);

// Check if a user is rate limited
function verifyUserInput(userId: string, token: string) {
  if (limiter.isRateLimited(userId)) {
    const remainingTime = limiter.getTimeUntilReset(userId);
    return {
      success: false,
      message: `Too many attempts. Please try again in ${Math.ceil(remainingTime / 1000)} seconds.`
    };
  }
  
  // Proceed with token verification
  // ...
  
  // Reset rate limiter on successful verification
  limiter.reset(userId);
  
  return { success: true };
}

// Get remaining attempts
function getRemainingAttempts(userId: string) {
  return limiter.getRemainingAttempts(userId);
}

Complete Example with React

import React, { useState, useEffect } from 'react';
import { QRCodeSVG } from 'qrcode.react';
import { generateTOTP, verifyTOTP, getTOTPAuthUri, RateLimiter } from 'totp-web';

function TOTPComponent() {
  const [secret, setSecret] = useState('');
  const [token, setToken] = useState('');
  const [verificationToken, setVerificationToken] = useState('');
  const [isValid, setIsValid] = useState(null);
  const [qrUri, setQrUri] = useState('');
  const [remainingSeconds, setRemainingSeconds] = useState(30);
  const [error, setError] = useState('');
  
  // Create a rate limiter
  const limiter = new RateLimiter(5, 60000); // 5 attempts per minute

  useEffect(() => {
    // Generate a new secret when component mounts
    const generateNewSecret = async () => {
      const result = await generateTOTP({
        algorithm: 'SHA-256',
        digits: 8
      });
      setSecret(result.secret);
      setRemainingSeconds(result.remainingSeconds);
      
      // Generate QR code URI
      setQrUri(getTOTPAuthUri({
        secret: result.secret,
        accountName: '[email protected]',
        issuer: 'MyApp',
        algorithm: 'SHA-256',
        digits: 8
      }));
    };

    generateNewSecret();
  }, []);

  // Update token every second
  useEffect(() => {
    const updateToken = async () => {
      if (!secret) return;
      const result = await generateTOTP({ 
        secret,
        algorithm: 'SHA-256',
        digits: 8
      });
      setToken(result.token);
      setRemainingSeconds(result.remainingSeconds);
    };

    updateToken();
    const interval = setInterval(updateToken, 1000);
    return () => clearInterval(interval);
  }, [secret]);

  const handleVerify = async () => {
    if (!secret || !verificationToken) return;
    
    // Check rate limiting
    if (limiter.isRateLimited('user')) {
      const remainingTime = limiter.getTimeUntilReset('user');
      setError(`Too many attempts. Please try again in ${Math.ceil(remainingTime / 1000)} seconds.`);
      return;
    }
    
    try {
      const result = await verifyTOTP(verificationToken, { 
        secret,
        algorithm: 'SHA-256',
        digits: 8
      });
      setIsValid(result);
      
      // Reset rate limiter on successful verification
      if (result) {
        limiter.reset('user');
      }
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Verification failed');
    }
  };

  return (
    <div>
      <h2>Your Secret</h2>
      <code>{secret}</code>
      
      <h2>QR Code</h2>
      {qrUri && <QRCodeSVG value={qrUri} size={200} />}
      
      <h2>Current Token</h2>
      <div>
        <code>{token}</code>
        <div>Expires in {remainingSeconds} seconds</div>
      </div>
      
      <h2>Verify Token</h2>
      <input
        type="text"
        value={verificationToken}
        onChange={(e) => setVerificationToken(e.target.value)}
        placeholder="Enter token to verify"
      />
      <button onClick={handleVerify}>Verify</button>
      
      {error && <div style={{ color: 'red' }}>{error}</div>}
      
      {isValid !== null && !error && (
        <div style={{ color: isValid ? 'green' : 'red' }}>
          {isValid ? 'Token is valid!' : 'Token is invalid!'}
        </div>
      )}
      
      <div>
        Remaining attempts: {limiter.getRemainingAttempts('user')}
      </div>
    </div>
  );
}

API Reference

generateTOTP(options: TOTPOptions): Promise

Generates a TOTP token and related information.

TOTPOptions

  • secret?: string: Optional Base32 encoded secret key. If not provided, a new secret will be generated.
  • algorithm?: TOTPAlgorithm: Hash algorithm to use (default: 'SHA-1'). Options: 'SHA-1', 'SHA-256', 'SHA-512'.
  • digits?: number: Number of digits in the token (default: 6).
  • charSet?: string: Custom character set for token generation (default: '0123456789').
  • period?: number: Time period in seconds (default: 30).
  • window?: number: Time window for validation (default: 0).

TOTPResult

  • token: The TOTP token
  • secret: The secret used to generate the token
  • remainingSeconds: Seconds until the token expires

verifyTOTP(token: string, options: TOTPVerifyOptions): Promise

Verifies a TOTP token against a secret.

TOTPVerifyOptions

  • secret: Base32 encoded secret key
  • algorithm?: TOTPAlgorithm: Hash algorithm to use (default: 'SHA-1')
  • digits?: number: Number of digits in the token (default: 6)
  • charSet?: string: Custom character set for token generation (default: '0123456789')
  • period?: number: Time period in seconds (default: 30)
  • window?: number: Time window for validation (default: 1, meaning ±30 seconds)

getTOTPAuthUri(options: TOTPAuthUriOptions): string

Generates a URI for QR code generation compatible with authenticator apps.

TOTPAuthUriOptions

  • secret: Base32 encoded secret key
  • accountName: The account name to display in the authenticator app
  • issuer?: string: Optional issuer name to display in the authenticator app
  • algorithm?: TOTPAlgorithm: Hash algorithm to use (default: 'SHA-1')
  • digits?: number: Number of digits in the token (default: 6)
  • period?: number: Time period in seconds (default: 30)

RateLimiter

A utility class for implementing rate limiting to prevent brute force attacks.

Constructor

  • new RateLimiter(maxAttempts: number = 5, windowMs: number = 60000)
    • maxAttempts: Maximum number of attempts allowed within the time window (default: 5)
    • windowMs: Time window in milliseconds (default: 60000, which is 1 minute)

Methods

  • isRateLimited(key: string): boolean: Check if a key is rate limited
  • reset(key: string): void: Reset the rate limit for a key
  • getRemainingAttempts(key: string): number: Get the number of remaining attempts for a key
  • getTimeUntilReset(key: string): number: Get the time in milliseconds until the rate limit resets for a key

Development Utilities

The package includes several development utilities to help with common TOTP operations:

import { TOTPUtils } from 'totp-web';

// Generate a random secret key
const secret = TOTPUtils.generateSecret();

// Generate backup codes for account recovery
const backupCodes = TOTPUtils.generateBackupCodes(8, 8);

// Test TOTP configuration
const isValid = await TOTPUtils.testConfiguration({
  algorithm: 'SHA-256',
  digits: 6,
  period: 30
});

// Format time remaining
const timeRemaining = TOTPUtils.formatTimeRemaining(29); // "29s"

// Validate configuration
const validation = TOTPUtils.validateConfiguration({
  algorithm: 'SHA-256',
  digits: 6,
  period: 30
});

CLI Tool

The package includes a command-line interface for testing and debugging TOTP tokens:

# Install globally
npm install -g totp-web

# Generate a new TOTP token
totp-web generate
totp-web generate --algorithm SHA-256 --digits 8

# Verify a TOTP token
totp-web verify ABC123 --secret JBSWY3DPEHPK3PXP

# Generate a TOTP auth URI
totp-web uri --secret JBSWY3DPEHPK3PXP --accountName [email protected] --issuer Example

CLI Options

Generate Command

  • --secret <secret>: Secret key (optional, will generate if not provided)
  • --algorithm <algo>: Algorithm (SHA-1, SHA-256, SHA-512)
  • --digits <number>: Number of digits (default: 6)
  • --period <seconds>: Period in seconds (default: 30)
  • --charSet <chars>: Custom character set

Verify Command

  • --secret <secret>: Secret key (required)
  • --algorithm <algo>: Algorithm (SHA-1, SHA-256, SHA-512)
  • --digits <number>: Number of digits (default: 6)
  • --period <seconds>: Period in seconds (default: 30)
  • --charSet <chars>: Custom character set
  • --window <number>: Time window for verification (default: 1)

URI Command

  • --secret <secret>: Secret key (required)
  • --accountName <name>: Account name (required)
  • --issuer <name>: Issuer name (optional)
  • --algorithm <algo>: Algorithm (SHA-1, SHA-256, SHA-512)
  • --digits <number>: Number of digits (default: 6)
  • --period <seconds>: Period in seconds (default: 30)

Examples

Setting Up 2FA for a User

import { generateTOTP, getTOTPAuthUri } from 'totp-web';

// Generate a new secret for a user
const { secret } = await generateTOTP({
  algorithm: 'SHA-256',
  digits: 8
});

// Generate a QR code URI for the user to scan
const uri = getTOTPAuthUri({
  secret,
  accountName: '[email protected]',
  issuer: 'MyApp',
  algorithm: 'SHA-256',
  digits: 8
});

// Store the secret securely for later verification
// ...

Verifying User Input with Rate Limiting

import { verifyTOTP, RateLimiter } from 'totp-web';

// Create a rate limiter
const limiter = new RateLimiter(5, 60000); // 5 attempts per minute

async function verifyUserInput(userId: string, token: string, secret: string) {
  // Check if the user is rate limited
  if (limiter.isRateLimited(userId)) {
    const remainingTime = limiter.getTimeUntilReset(userId);
    return {
      success: false,
      message: `Too many attempts. Please try again in ${Math.ceil(remainingTime / 1000)} seconds.`
    };
  }
  
  try {
    // Verify the token
    const isValid = await verifyTOTP(token, { 
      secret,
      algorithm: 'SHA-256',
      digits: 8
    });
    
    // Reset rate limiter on successful verification
    if (isValid) {
      limiter.reset(userId);
    }
    
    return {
      success: true,
      isValid
    };
  } catch (error) {
    return {
      success: false,
      message: error instanceof Error ? error.message : 'Verification failed'
    };
  }
}

Security

This library uses the Web Crypto API for cryptographic operations, which provides a secure implementation of cryptographic primitives. The TOTP implementation follows the RFC 6238 specification.

Best Practices

  1. Secret Storage: Always store secrets securely. In a web application, this typically means storing them on the server, not in the client.
  2. Rate Limiting: Use the built-in RateLimiter class to prevent brute force attacks.
  3. Algorithm Selection: For maximum security, use SHA-256 or SHA-512 instead of the default SHA-1.
  4. Token Length: Consider using 8-digit tokens instead of 6-digit tokens for increased security.
  5. Custom Character Sets: For even more security, use custom character sets with more entropy.

License

MIT License - see the LICENSE file for details.