@codixverse/totp
v1.0.0
Published
TOTP library for React Native, websites, Chrome/Firefox extensions, and Node.js. Works 100% in Expo Go without native modules.
Readme
@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/totpUsage
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); // trueAdvanced
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, '[email protected]', 'MyApp');
// otpauth://totp/MyApp:[email protected]?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); // cleanupRate 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(); // percentageAdvanced 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 codeverifyTOTP(secret, token, time?, options?, identifier?)- Verify codegenerateHOTP(secret, counter, options?)- Generate HOTPverifyHOTP(secret, token, counter, options?)- Verify HOTP
Security:
encryptSecret(rawSecret, password)- Encrypt with passworddecryptSecret(encryptedSecret, password)- DecryptzeroMemory(buffer)- Cleanup memorycheckThrottle(identifier, config)- Rate limiting
Utilities:
getRemainingTime(options?)- Time leftgetProgress(options?)- Progress %generateTOTPURI(secret, account, issuer)- QR URIparseTOTPURI(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
