Skip to content

Codixverse/codixverse-totp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 

Repository files navigation

@codixverse/totp

Universal TOTP library for React Native, websites, Chrome/Firefox extensions, and Node.js.

Features

  • Works everywhere: React Native, Expo Go, websites, Node.js
  • No native modules needed (pure JavaScript)
  • TOTP and HOTP support
  • SHA1, SHA256, SHA512
  • Rate limiting and throttling
  • TypeScript support
  • Encrypted secret storage
  • Memory safe cleanup
  • QR code URI generation
  • Progress tracking

Installation

npm install @codixverse/totp

Usage

Basic Usage

import { generateTOTP, verifyTOTP, generateSecret } from '@codixverse/totp';

const secret = generateSecret();
const code = generateTOTP(secret);
console.log('Your TOTP code:', code); // "123456"

const isValid = verifyTOTP(secret, code);
console.log('Code is valid:', isValid); // true

Advanced

import { 
  generateTOTPAdvanced, 
  verifyTOTPAdvanced,
  generateSecureSecret,
  getRemainingTime,
  getProgress 
} from '@codixverse/totp';

const secret = generateSecureSecret();

const result = generateTOTPAdvanced(secret);
console.log('Code:', result.token);
console.log('Time remaining:', result.timeRemaining, 'seconds');

const verifyResult = verifyTOTPAdvanced(secret, userInput, undefined, {}, 'user123');
if (verifyResult.isValid) {
  console.log('Success!');
} else {
  console.log('Invalid code. Attempts remaining:', verifyResult.attemptsRemaining);
}

Configuration

const options = {
  timeStep: 30,      // seconds (default: 30)
  digits: 6,         // default: 6
  algorithm: 'sha1', // 'sha1' | 'sha256' | 'sha512'
  window: 1,         // verification tolerance
  maxAttempts: 5,    // before lockout
  lockoutDuration: 300 // seconds
};

const code = generateTOTP(secret, undefined, options);
const isValid = verifyTOTP(secret, userInput, undefined, options, 'user123');

// Check time sync
const result = verifyTOTPAdvanced(secret, userInput);
if (result.isValid && result.timeDelta && Math.abs(result.timeDelta) > 60) {
  console.warn('Clock out of sync by', result.timeDelta, 'seconds');
}

React Native Example

import React, { useState, useEffect } from 'react';
import { View, Text, TextInput, Button, StyleSheet } from 'react-native';
import { 
  generateTOTPAdvanced, 
  verifyTOTPAdvanced, 
  generateSecret 
} from '@codixverse/totp';

export default function TOTPAuthenticator() {
  const [secret, setSecret] = useState('');
  const [token, setToken] = useState('');
  const [timeRemaining, setTimeRemaining] = useState(0);
  const [progress, setProgress] = useState(0);
  const [userInput, setUserInput] = useState('');

  useEffect(() => {
    setSecret(generateSecret());
  }, []);

  useEffect(() => {
    if (!secret) return;
    
    const interval = setInterval(() => {
      const result = generateTOTPAdvanced(secret);
      setToken(result.token);
      setTimeRemaining(result.timeRemaining);
    }, 1000);

    return () => clearInterval(interval);
  }, [secret]);

  const handleVerify = () => {
    const result = verifyTOTPAdvanced(secret, userInput, undefined, {}, 'user123');
    
    if (result.isValid) {
      alert('Code verified!');
    } else {
      alert(`Invalid code. Attempts remaining: ${result.attemptsRemaining}`);
    }
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>TOTP Authenticator</Text>
      
      <View style={styles.tokenContainer}>
        <Text style={styles.token}>{token}</Text>
        <Text style={styles.timer}>{timeRemaining}s</Text>
      </View>
      
      <TextInput
        style={styles.input}
        placeholder="Enter code"
        value={userInput}
        onChangeText={setUserInput}
        keyboardType="numeric"
        maxLength={6}
      />
      
      <Button title="Verify" onPress={handleVerify} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, padding: 20, justifyContent: 'center' },
  title: { fontSize: 24, fontWeight: 'bold', marginBottom: 30 },
  tokenContainer: { padding: 20, alignItems: 'center', marginBottom: 20 },
  token: { fontSize: 48, fontWeight: 'bold' },
  timer: { marginTop: 10 },
  input: { padding: 15, fontSize: 24, textAlign: 'center', marginBottom: 20 }
});

Website Example

Works in any website or React app:

import { generateTOTP, verifyTOTP } from '@codixverse/totp';

function LoginForm() {
  const [code, setCode] = useState('');
  const secret = 'JBSWY3DPEHPK3PXP'; // from database

  const handleSubmit = () => {
    const isValid = verifyTOTP(secret, code);
    if (isValid) {
      // login success
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input 
        value={code} 
        onChange={e => setCode(e.target.value)} 
        placeholder="Enter 6-digit code"
      />
      <button type="submit">Verify</button>
    </form>
  );
}

Node.js Example

import { generateTOTP, verifyTOTP } from '@codixverse/totp';

const secret = 'JBSWY3DPEHPK3PXP';
const code = generateTOTP(secret);
console.log('TOTP code:', code);

// Verify on server
const isValid = verifyTOTP(secret, userInput);
if (isValid) {
  console.log('Code is valid');
}

Chrome/Firefox Extension Example

// background.js or content script
import { generateTOTP, verifyTOTP, generateSecret } from '@codixverse/totp';

// Generate secret
const secret = generateSecret();

// Generate code
const code = generateTOTP(secret);

// Verify
chrome.storage.local.set({ secret });
const isValid = verifyTOTP(secret, userInput);

HOTP

import { generateHOTP, verifyHOTP } from '@codixverse/totp';

let counter = 0;
const hotpCode = generateHOTP(secret, counter);

const isValid = verifyHOTP(secret, userInput, counter);

QR Codes

import { generateTOTPURI, parseTOTPURI } from '@codixverse/totp';

const uri = generateTOTPURI(secret, 'user@example.com', 'MyApp');
// otpauth://totp/MyApp:user@example.com?secret=...

const parsed = parseTOTPURI(uri);

Security Features

Encrypted Secrets

import { encryptSecret, decryptSecret } from '@codixverse/totp';

// Encrypt
const encrypted = encryptSecret(secret, 'password');
await AsyncStorage.setItem('secret', JSON.stringify(encrypted));

// Decrypt
const data = JSON.parse(await AsyncStorage.getItem('secret'));
const decrypted = decryptSecret(data, 'password');

Memory Cleanup

import { zeroMemory } from '@codixverse/totp';

const buffer = new Uint8Array(secret);
// ... use buffer
zeroMemory(buffer); // cleanup

Rate Limiting

const isValid = verifyTOTP(secret, userInput, undefined, {
  maxAttempts: 5,
  lockoutDuration: 300
}, 'user123');

// Check attempts
import { getAttemptsInfo } from '@codixverse/totp';
const attempts = getAttemptsInfo('user123');

Progress Tracking

import { getRemainingTime, getProgress } from '@codixverse/totp';

const remaining = getRemainingTime(); // seconds
const progress = getProgress(); // percentage

Advanced Features

Global Config

import { setGlobalTOTPConfig } from '@codixverse/totp';

setGlobalTOTPConfig({
  timeStep: 45,
  digits: 8
});

Hooks

import { onVerifySuccess, onVerifyFailure } from '@codixverse/totp';

const unsub = onVerifySuccess((info) => {
  console.log('Success', info);
});

onVerifyFailure((error) => {
  console.log('Failed', error);
});

// Cleanup
unsub();

Error Handling

import { TOTPError } from '@codixverse/totp';

try {
  generateTOTP(invalid);
} catch (error) {
  if (error instanceof TOTPError) {
    console.log(error.code); // 'INVALID_SECRET'
  }
}

Base32

import { encodeBase32, decodeBase32 } from '@codixverse/totp';

const encoded = encodeBase32(bytes);
const decoded = decodeBase32(encoded);

API Reference

Core Functions:

  • generateTOTP(secret, time?, options?) - Generate code
  • verifyTOTP(secret, token, time?, options?, identifier?) - Verify code
  • generateHOTP(secret, counter, options?) - Generate HOTP
  • verifyHOTP(secret, token, counter, options?) - Verify HOTP

Security:

  • encryptSecret(rawSecret, password) - Encrypt with password
  • decryptSecret(encryptedSecret, password) - Decrypt
  • zeroMemory(buffer) - Cleanup memory
  • checkThrottle(identifier, config) - Rate limiting

Utilities:

  • getRemainingTime(options?) - Time left
  • getProgress(options?) - Progress %
  • generateTOTPURI(secret, account, issuer) - QR URI
  • parseTOTPURI(uri) - Parse URI

Compatibility

Works in any JavaScript environment:

  • React Native 0.60+ (Expo included)
  • Websites (Chrome, Firefox, Safari, Edge)
  • Chrome Extensions (Manifest V2 & V3)
  • Firefox Add-ons (WebExtensions API)
  • Node.js 14+
  • Web Workers
  • Service Workers

Pure JavaScript - no native modules needed. Auto-detects available crypto APIs (WebCrypto, Expo, Node.js, Extensions).

License

MIT


GitHub | Issues | Codixverse

About

TOTP library for React Native, websites, Chrome/Firefox extensions, and Node.js. Works 100% in Expo Go without native modules.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors