### Usage with hotp.verify() Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/types.md Example usage of the `hotp.verify()` function with HOTPVerifyOptions. ```typescript import { hotp } from '@nds-stack/bun-otp'; const options: HOTPVerifyOptions = { secret: 'JBSWY3DPEBLW64TMMQ======', counter: 42, token: '654321', window: 10, // Check up to 10 counters ahead }; const isValid = await hotp.verify(options); ``` -------------------------------- ### Usage with hotp() Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/types.md Example usage of the `hotp()` function with HOTPOptions. ```typescript import { hotp } from '@nds-stack/bun-otp'; const options: HOTPOptions = { secret: 'JBSWY3DPEBLW64TMMQ======', counter: 0, digits: 6, algorithm: 'SHA1', }; const token = await hotp(options); ``` -------------------------------- ### generateOTPAuthURI example Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Example usage of the generateOTPAuthURI function to create an otpauth:// URI for TOTP. ```typescript const uri = generateOTPAuthURI({ type: 'totp', secret: 'JBSWY3DPEHPK3PXP', issuer: 'MyApp', accountName: 'user@example.com', }); // → otpauth://totp/MyApp:user%40example.com?secret=JBSWY3DPEHPK3PXP&issuer=MyApp ``` -------------------------------- ### Flexible verification window Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/configuration.md Example showing how to configure a verification window for TOTP to allow for clock tolerance. ```typescript import { totp } from '@nds-stack/bun-otp'; const secret = 'JBSWY3DPEBLW64TMMQ======'; // Strict verification (no clock tolerance) const strict = await totp.verify({ secret, token: userCode, window: 0, }); // Relaxed verification (±60s tolerance) const relaxed = await totp.verify({ secret, token: userCode, window: 2, // 2 × 30s period = ±60s }); ``` -------------------------------- ### Usage with totp() Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/types.md Example usage of the `totp()` function with TOTPOptions. ```typescript import { totp } from '@nds-stack/bun-otp'; const options: TOTPOptions = { secret: 'JBSWY3DPEBLW64TMMQ======', period: 30, digits: 6, algorithm: 'SHA1', }; const token = await totp(options); ``` -------------------------------- ### HOTP Configuration Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/configuration.md Example of configuring HOTP generation with parameters like secret, counter, digits, and algorithm. ```typescript import { hotp } from '@nds-stack/bun-otp'; const token = await hotp({ secret: 'JBSWY3DPEBLW64TMMQ======', // Required secret counter: 42, // Required counter value digits: 6, // OTP length (default: 6) algorithm: 'SHA1', // Hash algo (default: 'SHA1') }); ``` -------------------------------- ### SHA256 instead of SHA1 Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/configuration.md Example demonstrating the use of SHA256 for enhanced security with HOTP. ```typescript import { hotp } from '@nds-stack/bun-otp'; const secret = 'JBSWY3DPEBLW64TMMQ======'; const token = await hotp({ secret, counter: 0, algorithm: 'SHA256', // Enhanced security }); const isValid = await hotp.verify({ secret, counter: 0, token, algorithm: 'SHA256', // Must match }); ``` -------------------------------- ### Custom 8-digit TOTP Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/configuration.md Example demonstrating how to generate and verify a custom 8-digit TOTP by specifying the 'digits' parameter. ```typescript import { totp } from '@nds-stack/bun-otp'; const secret = 'JBSWY3DPEBLW64TMMQ======'; const token = await totp({ secret, digits: 8, // 8-digit OTP instead of 6 }); const isValid = await totp.verify({ secret, token, digits: 8, // Must match }); ``` -------------------------------- ### Usage with totp.verify() Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/types.md Example usage of the `totp.verify()` function with TOTPVerifyOptions. ```typescript import { totp } from '@nds-stack/bun-otp'; const options: TOTPVerifyOptions = { secret: 'JBSWY3DPEBLW64TMMQ======', token: '123456', window: 1, // Accept ±30s }; const isValid = await totp.verify(options); ``` -------------------------------- ### Step-by-step enrollment flow Source: https://github.com/nds-stack/bun-otp/blob/main/README.md TypeScript example demonstrating the process of generating a secret, storing it, creating an OTP Auth URI for QR code generation, and verifying the first token for authenticator app enrollment. ```typescript import { generateSecret, totp, generateOTPAuthURI, base32Encode } from '@nds-stack/bun-otp'; // 1. Generate a secret for the user const secret = generateSecret(); // 2. Store the secret in your database db.users.update(userId, { totpSecret: secret }); // 3. Create an OTP Auth URI for QR code const uri = generateOTPAuthURI({ type: 'totp', secret, issuer: 'MyApp', accountName: user.email, }); // 4. Generate QR code (any QR library) // npm install qrcode // import QRCode from 'qrcode'; // const qrImage = await QRCode.toDataURL(uri); // Display qrImage to user (HTML: ) // 5. Verify first token to confirm enrollment const firstToken = promptUser('Enter the code from your authenticator app:'); if (totp.verify({ secret, token: firstToken, window: 2 })) { // ✅ Enrollment confirmed } else { // ❌ Wrong code — ask user to try again } ``` -------------------------------- ### TOTP Configuration Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/configuration.md Example of configuring TOTP generation with various parameters like secret, period, digits, algorithm, and timestamp. ```typescript import { totp } from '@nds-stack/bun-otp'; const token = await totp({ secret: 'JBSWY3DPEBLW64TMMQ======', // Required secret period: 30, // Time step (default: 30s) digits: 6, // OTP length (default: 6) algorithm: 'SHA1', // Hash algo (default: 'SHA1') timestamp: Date.now(), // Override timestamp (optional) }); ``` -------------------------------- ### 8-digit HOTP Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/hotp.md Example showing how to generate an 8-digit HOTP token. ```typescript import { hotp } from '@nds-stack/bun-otp'; const secret = 'JBSWY3DPEBLW64TMMQ======'; const token = await hotp({ secret, counter: 0, digits: 8, }); console.log('8-digit HOTP:', token); // e.g., "12345678" ``` -------------------------------- ### HOTP Counter Persistence Pattern (Redis) Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Example of how to persist HOTP counters using Redis. ```typescript // HOTP counter persistence pattern (Redis) const counter = await redis.get(`hotp:${userId}`); const valid = hotp.verify({ secret, counter, token, window: 10 }); if (valid) { await redis.set(`hotp:${userId}`, counter + 10); // sync counter } ``` -------------------------------- ### Custom algorithm (SHA256) Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/hotp.md Example demonstrating how to use a custom algorithm like SHA256 for HOTP generation and verification. ```typescript import { hotp } from '@nds-stack/bun-otp'; const secret = 'JBSWY3DPEBLW64TMMQ======'; const token = await hotp({ secret, counter: 5, algorithm: 'SHA256', }); const isValid = await hotp.verify({ secret, counter: 5, token, algorithm: 'SHA256', // Must match }); ``` -------------------------------- ### Custom algorithm Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Example of generating a TOTP token using a custom HMAC algorithm. ```typescript const token = totp({ secret, algorithm: 'SHA256' }); const token = totp({ secret, algorithm: 'SHA512' }); ``` -------------------------------- ### Extending with custom encoding Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Example demonstrating how to extend bun-otp by providing a custom hex-to-base32 encoding function to generate a secret. ```typescript function hexToBase32(hex: string): string { const bytes = new Uint8Array(hex.match(/.{1,2}/g)!.map(b => parseInt(b, 16))); return base32Encode(bytes); } const secret = hexToBase32('12345678901234567890abcdef'); const token = totp({ secret }); ``` -------------------------------- ### Verification with tolerance Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Example of verifying a TOTP token with a specified time window for tolerance. ```typescript const ok = totp.verify({ secret, token, window: 2 }); ``` -------------------------------- ### Custom digits Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Example of generating a TOTP token with a custom number of digits. ```typescript const token = totp({ secret, digits: 8 }); ``` -------------------------------- ### Custom period Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Example of generating a TOTP token with a custom time period. ```typescript const token = totp({ secret, period: 60 }); ``` -------------------------------- ### Error — Web Crypto API unavailable example Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/errors.md Illustrates a scenario where an error might occur if the Web Crypto API is not available, which is a runtime environment issue. ```typescript // Error only occurs in environments without Web Crypto API // (e.g., Node.js < 15 without polyfill, older browsers) try { const secret = generateSecret(); } catch (err) { if (err instanceof TypeError || err instanceof ReferenceError) { console.error('Web Crypto API not available'); } } ``` -------------------------------- ### Decode with custom data (e.g., from authenticator app) Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/base32.md Example of decoding a base32 secret string, typically obtained from a QR code, for use in authenticator apps. ```typescript import { base32Decode, hotp } from '@nds-stack/bun-otp'; // User scans QR code and gets this base32 secret const secretFromQR = 'JBSWY3DPEBLW64TMMQ======'; // Decode to verify it's valid base32 try { const bytes = base32Decode(secretFromQR); console.log('Secret is valid, bytes:', bytes); } catch (err) { console.error('Invalid base32 secret:', err.message); } ``` -------------------------------- ### Verify functions return `false` for invalid tokens Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/errors.md Example demonstrating that `totp.verify()` returns `false` for invalid tokens instead of throwing an error. ```typescript import { totp } from '@nds-stack/bun-otp'; // Invalid token — returns false, does not throw const result = await totp.verify({ secret: 'JBSWY3DPEBLW64TMMQ======', token: 'wrongtoken', }); console.log(result); // false (no exception thrown) ``` -------------------------------- ### RangeError: Invalid `window` parameter in `totp.verify()` Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/errors.md Example showing how to catch a RangeError for an invalid `window` parameter in the `totp.verify()` function. ```typescript import { totp } from '@nds-stack/bun-otp'; try { await totp.verify({ secret: 'JBSWY3DPEBLW64TMMQ======', token: '123456', window: 11, // Exceeds max of 10 }); } catch (err) { if (err instanceof RangeError) { console.error(err.message); // "window must be 0-10, got 11" } } ``` -------------------------------- ### RangeError: Invalid `digits` parameter Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/errors.md Examples demonstrating how to catch RangeErrors for invalid `digits` parameters in TOTP and HOTP functions. ```typescript import { totp, hotp } from '@nds-stack/bun-otp'; try { await totp({ secret: 'JBSWY3DPEBLW64TMMQ======', digits: 11 }); } catch (err) { if (err instanceof RangeError) { console.error(err.message); // "TOTP: digits must be 1-10, got 11" } } ``` ```typescript } try { await hotp({ secret: 'JBSWY3DPEBLW64TMMQ======', counter: 0, digits: 0 }); } catch (err) { if (err instanceof RangeError) { console.error(err.message); // "HOTP: digits must be 1-10, got 0" } } ``` -------------------------------- ### Error: Invalid base32 in secret Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/errors.md Examples showing how to catch errors related to invalid base32 encoding in the secret parameter for TOTP and HOTP functions. ```typescript import { totp } from '@nds-stack/bun-otp'; try { await totp({ secret: 'INVALID!CHARACTER' }); } catch (err) { if (err instanceof Error) { console.error(err.message); // "Invalid base32 character: '!' ``` ```typescript } try { await totp({ secret: '' }); } catch (err) { if (err instanceof Error) { console.error(err.message); // "base32Decode: empty input" } } ``` -------------------------------- ### RangeError: Invalid `length` parameter in `generateSecret()` Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/errors.md Example demonstrating how to catch a RangeError when an invalid length parameter is provided to the `generateSecret()` function. ```typescript import { generateSecret } from '@nds-stack/bun-otp'; try { generateSecret(-1); } catch (err) { if (err instanceof RangeError) { console.error(err.message); // "generateSecret: length must be a positive integer, got -1" } } ``` -------------------------------- ### Package.json Summary Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/configuration.md Summary of the package.json file, highlighting its structure and dependencies. ```json { "name": "@nds-stack/bun-otp", "type": "module", "main": "dist/index.js", "types": "dist/index.d.ts", "engines": { "bun": ">=1.3.0" }, "devDependencies": { "@types/bun": "latest", "typescript": "^6.0.3" } } ``` -------------------------------- ### Import Paths Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/README.md Shows how to import all functions and types from the main entry point of the library. ```typescript // Functions import { generateSecret, totp, hotp, base32Encode, base32Decode } from '@nds-stack/bun-otp'; // Types import type { TOTPOptions, TOTPVerifyOptions, HOTPOptions, HOTPVerifyOptions } from '@nds-stack/bun-otp'; ``` -------------------------------- ### HOTP in multi-instance environment Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/hotp.md Illustrates how HOTP can be verified independently across multiple server instances using a shared secret, with an optional window for synchronization tolerance. ```typescript import { hotp } from '@nds-stack/bun-otp'; // Each server instance can independently verify using shared secret async function verifyUserToken( secret: string, currentCounter: number, userToken: string, ): Promise { try { return await hotp.verify({ secret, counter: currentCounter, token: userToken, window: 5, // Allow some out-of-sync }); } catch (err) { console.error('HOTP verification failed:', err); return false; } } // Multiple server instances verify independently (shared secret from DB/secrets manager) const isValid = await verifyUserToken( user.hotpSecret, user.lastHOTPCounter, req.body.code, ); ``` -------------------------------- ### Project Structure Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/README.md Illustrates the directory structure of the @nds-stack/bun-otp project. ```bash src/ ├─ index.ts Main entry point (exports all public symbols) ├─ types.ts Interface definitions (TOTPOptions, HOTPOptions, etc.) ├─ generate-secret.ts Secret key generation ├─ totp.ts TOTP algorithm and verification ├─ hotp.ts HOTP algorithm and verification ├─ base32.ts RFC 4648 base32 codec ├─ hmac.ts Web Crypto HMAC signing (internal) └─ timing-safe-equal.ts Constant-time string comparison (internal) ``` -------------------------------- ### generateQRCodeURL Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Generates a URL to a QR code API (qrserver.com) for any OTP Auth URI. Use this to generate QR codes for authenticator app enrollment. ```typescript const uri = generateOTPAuthURI({ type: 'totp', secret, issuer: 'MyApp', accountName: 'user@example.com' }); const qr = generateQRCodeURL(uri, 300); // → https://api.qrserver.com/v1/create-qr-code/?data=otpauth%3A%2F%2F...&size=300x300 ``` -------------------------------- ### Import from main entry point Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/types.md Importing types from the main entry point of the @nds-stack/bun-otp package. ```typescript import type { TOTPOptions, TOTPVerifyOptions, HOTPOptions, HOTPVerifyOptions, } from '@nds-stack/bun-otp'; ``` -------------------------------- ### RangeError: Invalid `period` parameter in TOTP Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/errors.md Examples showing how to catch RangeErrors for invalid `period` parameters in TOTP functions. ```typescript import { totp } from '@nds-stack/bun-otp'; try { await totp({ secret: 'JBSWY3DPEBLW64TMMQ======', period: 0 }); } catch (err) { if (err instanceof RangeError) { console.error(err.message); // "TOTP: period must be >= 1, got 0" } } ``` ```typescript } try { await totp({ secret: 'JBSWY3DPEBLW64TMMQ======', period: Infinity }); } catch (err) { if (err instanceof RangeError) { console.error(err.message); // "TOTP: period must be >= 1, got Infinity" } } ``` -------------------------------- ### Hardware token scenario (incremental counter) Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/hotp.md Simulates a hardware token scenario where the server needs to verify a token against a range of future counters. ```typescript import { hotp } from '@nds-stack/bun-otp'; // Simulate a hardware token that has generated tokens at counters 0–5 // but server only verified up to counter 3 const secret = 'JBSWY3DPEBLW64TMMQ======'; const lastVerifiedCounter = 3; const userToken = '555555'; // User provides a new token // Check if it matches any counter ahead of last verified const isValid = await hotp.verify({ secret, counter: lastVerifiedCounter + 1, // Start from next counter token: userToken, window: 10, // Allow up to 10 ahead }); if (isValid) { // Token matched at some counter in window // Server should now reject tokens from earlier counters console.log('Token verified, increment server counter'); } else { console.log('Token does not match, may be replay attack'); } ``` -------------------------------- ### RangeError: Invalid `timestamp` parameter in TOTP Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/errors.md Example demonstrating how to catch a RangeError for an invalid `timestamp` parameter in TOTP functions. ```typescript import { totp } from '@nds-stack/bun-otp'; try { await totp({ secret: 'JBSWY3DPEBLW64TMMQ======', timestamp: -1000 }); } catch (err) { if (err instanceof RangeError) { console.error(err.message); // "TOTP: timestamp must be a non-negative number, got -1000" } } ``` -------------------------------- ### HOTP with counter persistence Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Illustrates how to use HMAC-based One-Time Password (HOTP) with server-side counter persistence for code generation and verification. ```typescript import { hotp, generateSecret } from '@nds-stack/bun-otp'; let serverCounter = 0; function generateCode(): string { const token = hotp({ secret: process.env.HOTP_SECRET!, counter: serverCounter }); serverCounter++; // increment after each generation return token; } function verifyCode(token: string): boolean { const valid = hotp.verify({ secret: process.env.HOTP_SECRET!, counter: serverCounter, token, window: 10, }); if (valid) serverCounter++; // sync counter return valid; } ``` -------------------------------- ### Bun Runtime Requirement Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/configuration.md Specifies the minimum Bun version required for @nds-stack/bun-otp. ```json { "engines": { "bun": ">=1.3.0" } } ``` -------------------------------- ### Encode arbitrary data Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/base32.md Demonstrates encoding arbitrary string data into a base32 format. ```typescript import { base32Encode } from '@nds-stack/bun-otp'; // Encode a message (not typical for OTP, but the function is general-purpose) const message = 'Hello, World!'; const bytes = new TextEncoder().encode(message); const encoded = base32Encode(bytes); console.log('Encoded message:', encoded); ``` -------------------------------- ### TypeScript Configuration Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/configuration.md Recommended TypeScript compiler options for compatibility with the library, including strict mode and target environment. ```json { "compilerOptions": { "strict": true, "target": "ES2020", "lib": ["ES2020", "DOM"] } } ``` -------------------------------- ### Shared Secrets Across Instances Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/configuration.md Illustrates how to use the same secret across multiple server instances for horizontal scaling of TOTP. ```typescript // Instance 1 (Server A) const token1 = await totp({ secret: userSecret, // From database/secrets manager window: 1, }); // Instance 2 (Server B) const isValid = await totp.verify({ secret: userSecret, // Same secret from database token: token1, window: 1, }); // Both instances use identical configuration ``` -------------------------------- ### bun-otp vs speakeasy Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Comparison of function signatures and options between bun-otp and speakeasy for TOTP and HOTP generation and verification. ```typescript speakeasy.totp({ secret, encoding: 'base32' }) totp({ secret }) ``` ```typescript speakeasy.totp({ secret, encoding: 'base32', algorithm: 'sha256' }) totp({ secret, algorithm: 'SHA256' }) ``` ```typescript speakeasy.hotp({ secret, counter, encoding: 'base32' }) hotp({ secret, counter }) ``` ```typescript speakeasy.totp.verify({ secret, token, encoding: 'base32', window: 2 }) totp.verify({ secret, token, window: 2 }) ``` ```typescript speakeasy.generateSecret().base32 generateSecret() ``` -------------------------------- ### bun-otp vs otplib Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Comparison of function signatures and usage between bun-otp and otplib for OTP generation and verification. ```typescript await authenticator.generate(secret) totp({ secret }) ``` ```typescript await authenticator.check(token, secret) totp.verify({ secret, token }) ``` ```typescript await totp.generate(secret) totp({ secret }) ``` ```typescript await hotp.generate(secret, counter) hotp({ secret, counter }) ``` -------------------------------- ### Generate and verify TOTP Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/README.md Demonstrates generating a Time-based One-Time Password (TOTP) and verifying a user-provided token with a tolerance window. ```typescript import { totp } from '@nds-stack/bun-otp'; // Generate current token const token = await totp({ secret }); // Verify user-provided token const isValid = await totp.verify({ secret, token: userInput, window: 1, // ±30s tolerance }); ``` -------------------------------- ### TOTP 2FA for a web application Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Demonstrates how to implement Time-based One-Time Password (TOTP) two-factor authentication, including user enrollment and code verification. ```typescript import { generateSecret, totp, base32Encode } from '@nds-stack/bun-otp'; // ── Enrollment ────────────────────────────────────── // Called once when user enables 2FA function enrollUser(userId: string) { const secret = generateSecret(); // Store secret in database (associated with user) db.users.update(userId, { totpSecret: secret }); // Return secret for QR code generation return { secret }; } // ── Verification ──────────────────────────────────── // Called every time user logs in function verify2FA(userId: string, userCode: string): boolean { const user = db.users.get(userId); if (!user.totpSecret) throw new Error('2FA not enrolled'); return totp.verify({ secret: user.totpSecret, token: userCode, window: 1, // tolerate ±30s clock drift }); } // ── Usage ─────────────────────────────────────────── const { secret } = enrollUser('user-123'); // Send `secret` to authenticator app: // otpauth://totp/MyApp:user@example.com?secret=... const isValid = verify2FA('user-123', '428936'); console.log(isValid ? '✅ Access granted' : '❌ Invalid code'); ``` -------------------------------- ### Generate and verify HOTP Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/README.md Demonstrates generating a HMAC-based One-Time Password (HOTP) for a specific counter and verifying a user-provided token with a look-ahead window. ```typescript import { hotp } from '@nds-stack/bun-otp'; // Generate token at counter 0 const token = await hotp({ secret, counter: 0 }); // Verify with look-ahead window const isValid = await hotp.verify({ secret, counter: lastKnownCounter, token: userInput, window: 10, }); ``` -------------------------------- ### HOTPVerifyOptions Interface Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/types.md Configuration options for `hotp.verify()` function to verify an HMAC-based one-time password. ```typescript interface HOTPVerifyOptions extends HOTPOptions { token: string window?: number } ``` -------------------------------- ### Real-world 2FA verification flow Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/totp.md Demonstrates a typical 2FA verification flow using the `totp.verify` method with a time window for tolerance. ```typescript import { totp } from '@nds-stack/bun-otp'; async function verify2FA( storedSecret: string, userProvidedToken: string, ): Promise { try { // Verify with ±30s clock tolerance // Accounts for clock drift between client and server return await totp.verify({ secret: storedSecret, token: userProvidedToken, window: 1, }); } catch (err) { console.error('2FA verification error:', err); return false; } } // Usage in user login if (await verify2FA(user.totpSecret, req.body.code)) { // User authenticated } else { // Authentication failed } ``` -------------------------------- ### Error handling Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/base32.md Illustrates how to handle potential errors during base32 decoding, such as empty input, invalid characters, or input consisting only of padding. ```typescript import { base32Decode } from '@nds-stack/bun-otp'; // Empty input try { base32Decode(''); } catch (err: unknown) { if (err instanceof Error) { console.error('Empty input:', err.message); // "Empty input: base32Decode: empty input" } } // Invalid character try { base32Decode('AEBAGBA0'); // '0' is not valid base32 } catch (err: unknown) { if (err instanceof Error) { console.error('Invalid char:', err.message); // "Invalid char: Invalid base32 character: '0'" } } // Only padding try { base32Decode('========'); } catch (err: unknown) { if (err instanceof Error) { console.error('Only padding:', err.message); // "Only padding: base32Decode: input contains only padding characters" } } ``` -------------------------------- ### HOTPOptions Interface Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/types.md Configuration options for `hotp()` function to generate an HMAC-based one-time password. ```typescript interface HOTPOptions { secret: string counter: number digits?: number algorithm?: 'SHA1' | 'SHA256' | 'SHA512' } ``` -------------------------------- ### TOTPVerifyOptions Interface Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/types.md Configuration options for `totp.verify()` function to verify a time-based one-time password. ```typescript interface TOTPVerifyOptions extends TOTPOptions { token: string window?: number } ``` -------------------------------- ### Basic HOTP generation Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/hotp.md Generates a basic HOTP token using a secret and a counter. ```typescript import { generateSecret, hotp } from '@nds-stack/bun-otp'; const secret = generateSecret(); const token = await hotp({ secret, counter: 0 }); console.log('HOTP token (counter=0):', token); // Output example: "123456" ``` -------------------------------- ### Error handling Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/generate-secret.md Demonstrates how to handle a RangeError when an invalid (non-positive integer) length is provided to generateSecret. ```typescript import { generateSecret } from '@nds-stack/bun-otp'; try { generateSecret(-1); // Invalid } catch (err: unknown) { if (err instanceof RangeError) { console.error('Invalid length:', err.message); // Output: "Invalid length: generateSecret: length must be a positive integer, got -1" } } ``` -------------------------------- ### HOTP Verification Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Verifies an HOTP token with a look-ahead window. ```typescript const valid = hotp.verify({ secret, counter: 95, token: '123456', window: 10 }); ``` -------------------------------- ### Generate a secret Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/README.md Generates a base32-encoded cryptographic secret key. ```typescript import { generateSecret } from '@nds-stack/bun-otp'; const secret = generateSecret(); // Output: base32-encoded string (e.g., "JBSWY3DPEBLW64TMMQ======") ``` -------------------------------- ### Generate TOTP Token Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Generates a time-based one-time password. The default period is 30 seconds, default digits is 6, and default algorithm is SHA1. A custom timestamp can be provided in milliseconds. Alternatively, specify digits and algorithm. ```typescript const token = totp({ secret, timestamp: Date.now() }); const token = totp({ secret, digits: 8, algorithm: 'SHA256' }); ``` -------------------------------- ### Basic TOTP generation (default settings) Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/totp.md Generates a TOTP token using default settings. ```typescript import { generateSecret, totp } from '@nds-stack/bun-otp'; const secret = generateSecret(); const token = await totp({ secret }); console.log('Current OTP:', token); // Output example: "123456" ``` -------------------------------- ### Round-trip encode/decode Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/base32.md Demonstrates encoding and then decoding a Uint8Array to verify data integrity. ```typescript import { base32Encode, base32Decode } from '@nds-stack/bun-otp'; const original = new Uint8Array([10, 20, 30, 40, 50]); const encoded = base32Encode(original); const decoded = base32Decode(encoded); console.log('Same?', original === decoded); // false (different objects) console.log('Equal?', Array.from(original).toString() === Array.from(decoded).toString()); // true ``` -------------------------------- ### Case-insensitive decoding Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/base32.md Shows that base32 decoding is case-insensitive. ```typescript import { base32Decode } from '@nds-stack/bun-otp'; // All equivalent (base32 is case-insensitive in this implementation) const bytes1 = base32Decode('AEBAGBA='); const bytes2 = base32Decode('aebagba='); const bytes3 = base32Decode('AeBaGbA='); console.log('All equal:', Array.from(bytes1).toString() === Array.from(bytes2).toString() && Array.from(bytes2).toString() === Array.from(bytes3).toString() ); // true ``` -------------------------------- ### Import from types module Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/types.md Importing types directly from the types module within the @nds-stack/bun-otp package. ```typescript import type { TOTPOptions, TOTPVerifyOptions, HOTPOptions, HOTPVerifyOptions, } from '@nds-stack/bun-otp/src/types'; ``` -------------------------------- ### Basic secret generation (default) Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/generate-secret.md Generates a secret using the default length of 20 bytes, resulting in 32 base32 characters including padding. ```typescript import { generateSecret } from '@nds-stack/bun-otp'; const secret = generateSecret(); // Example output: "JBSWY3DPEBLW64TMMQ======" // (32 base32 characters including padding) // Store this secret in a database associated with the user ``` -------------------------------- ### steamTotp Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Generates a Steam Guard–style one-time password (5 characters, custom alphabet `23456789BCDFGHJKMNPQRTVWXY`). ```typescript const key = base32Decode(secret); const code = steamTotp(key, Date.now()); // → '2B3C7' (5-char alphanumeric) ``` -------------------------------- ### TOTPOptions Interface Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/types.md Configuration options for `totp()` function to generate a time-based one-time password. ```typescript interface TOTPOptions { secret: string period?: number digits?: number algorithm?: 'SHA1' | 'SHA256' | 'SHA512' timestamp?: number } ``` -------------------------------- ### HOTP Generation Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Generates an HMAC-based one-time password. ```typescript const token = hotp({ secret, counter: 0 }); const token = hotp({ secret, counter: 42, digits: 8 }); ``` -------------------------------- ### Generate shorter secret (for testing or reduced QR code complexity) Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/generate-secret.md Generates a shorter secret by specifying a length of 16 bytes, resulting in 26 base32 characters (128 bits). This is still considered cryptographically secure for most 2FA use cases. ```typescript import { generateSecret } from '@nds-stack/bun-otp'; const shortSecret = generateSecret(16); // Produces 26 base32 characters (128 bits) // Still cryptographically secure for most 2FA use cases ``` -------------------------------- ### RangeError — Invalid `window` parameter in `hotp.verify()` Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/errors.md Shows how to catch RangeError when the `window` parameter is outside the valid range (0-50) in `hotp.verify()`. ```typescript import { hotp } from '@nds-stack/bun-otp'; try { await hotp.verify({ secret: 'JBSWY3DPEBLW64TMMQ======', counter: 100, token: '123456', window: 51, // Exceeds max of 50 }); } catch (err) { if (err instanceof RangeError) { console.error(err.message); // "HOTP verify: window must be 0-50, got 51" } } ``` -------------------------------- ### HOTP with counter window (allow out-of-sync tokens) Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/hotp.md Verifies an HOTP token within a specified look-ahead window to accommodate out-of-sync counters. ```typescript import { hotp } from '@nds-stack/bun-otp'; const secret = 'JBSWY3DPEBLW64TMMQ======'; const serverCounter = 100; // Last known counter const userToken = '654321'; // Accept tokens from counter 100 to 110 (window=10) const isValid = await hotp.verify({ secret, counter: serverCounter, token: userToken, window: 10, }); if (isValid) { console.log('Token valid, user may have generated multiple tokens'); } else { console.log('Token does not match any counter in window'); } ``` -------------------------------- ### Verify TOTP Token Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Verifies a TOTP token against a secret. It accepts an optional `window` parameter to check tokens within a specified period before and after the current time. The maximum window size is 10. ```typescript const valid = totp.verify({ secret, token: '123456', window: 1 }); ``` -------------------------------- ### Base32 Decoding Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Decodes a base32 string to raw bytes. ```typescript const bytes = base32Decode('JBSWY3DPEHPK3PXP'); // → Uint8Array(10) ``` -------------------------------- ### Defensive parameter validation error handling pattern Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/errors.md A common pattern for handling errors in `totp.verify()`, distinguishing between parameter validation errors, Web Crypto errors, and invalid tokens. ```typescript import { totp } from '@nds-stack/bun-otp'; async function verify2FA(secret: string, token: string): Promise { try { // Parameter validation throws immediately // Web Crypto errors throw during HMAC // Invalid token returns false return await totp.verify({ secret, token, window: 1 }); } catch (err) { if (err instanceof RangeError) { // Parameter validation failed (bad window, bad period, bad digits, etc.) console.error('Configuration error:', err.message); return false; } else if (err instanceof Error) { // Likely base32 decoding error or Web Crypto unavailable console.error('Verification error:', err.message); return false; } return false; } } ``` -------------------------------- ### Base32 Encoding Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Encodes raw bytes to a base32 string. ```typescript const encoded = base32Encode(new Uint8Array([0, 1, 2])); // → 'AAAQE======' ``` -------------------------------- ### Generate Secret Source: https://github.com/nds-stack/bun-otp/blob/main/README.md Generates a base32-encoded secret. The default length is 20 bytes, resulting in 32 base32 characters. A length of 32 bytes results in 52 base32 characters. ```typescript const secret = generateSecret(); // 32 base32 chars (20 bytes) const secret = generateSecret(32); // 52 base32 chars (32 bytes) ``` -------------------------------- ### HOTP verification Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/hotp.md Verifies a given HOTP token against a secret and a specific counter. ```typescript import { hotp } from '@nds-stack/bun-otp'; const secret = 'JBSWY3DPEBLW64TMMQ======'; const userCounter = 42; const userToken = '987654'; const isValid = await hotp.verify({ secret, counter: userCounter, token: userToken, }); if (isValid) { console.log('HOTP verified at counter', userCounter); } else { console.log('HOTP invalid'); } ``` -------------------------------- ### Test with specific timestamp Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/totp.md Generates a TOTP token for a specific timestamp, demonstrating how to test with past or future times. ```typescript import { totp } from '@nds-stack/bun-otp'; const secret = 'JBSWY3DPEBLW64TMMQ======'; // Generate token for a specific time (e.g., 30 seconds ago) const thePast = Date.now() - 30000; const pastToken = await totp({ secret, timestamp: thePast, }); // Current token const currentToken = await totp({ secret }); console.log('Past:', pastToken, 'Current:', currentToken); // Tokens differ because time-based counter changed ``` -------------------------------- ### TOTP verification with clock tolerance Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/totp.md Verifies a TOTP token with a specified time window to account for clock skew. ```typescript import { totp } from '@nds-stack/bun-otp'; const secret = 'JBSWY3DPEBLW64TMMQ======'; // User's stored secret const userToken = '123456'; // User-provided token // Accept tokens from ±30s (window=1 with 30s period) const isValid = await totp.verify({ secret, token: userToken, window: 1, }); if (isValid) { console.log('2FA verified'); } else { console.log('2FA failed'); } ``` -------------------------------- ### Custom algorithm (SHA256) Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/totp.md Generates and verifies a TOTP token using the SHA256 algorithm. ```typescript import { totp } from '@nds-stack/bun-otp'; const secret = 'JBSWY3DPEBLW64TMMQ======'; // Generate using SHA256 instead of default SHA1 const token = await totp({ secret, algorithm: 'SHA256', }); // Verification must use the same algorithm const isValid = await totp.verify({ secret, token, algorithm: 'SHA256', }); ``` -------------------------------- ### Custom period (60 seconds instead of 30) Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/totp.md Generates and verifies a TOTP token with a custom period of 60 seconds. ```typescript import { totp } from '@nds-stack/bun-otp'; const secret = 'JBSWY3DPEBLW64TMMQ======'; // Generate token with 60-second period const token = await totp({ secret, period: 60, }); // Verification must use the same period const isValid = await totp.verify({ secret, token, period: 60, window: 1, // ±60s tolerance }); ``` -------------------------------- ### Decode base32 string Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/base32.md Decodes a base32-encoded string back into a Uint8Array. ```typescript import { base32Decode } from '@nds-stack/bun-otp'; const encoded = 'AEBAGBA='; const bytes = base32Decode(encoded); console.log('Bytes:', bytes); // Uint8Array(8) [1, 2, 3, 4, 5, 6, 7, 8] ``` -------------------------------- ### Base32 Encode Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/base32.md Encodes a byte array into a Base32 string. ```typescript export function base32Encode(data: Uint8Array): string { let base32 = ""; let bits = 0; let value = 0; for (let i = 0; i < data.length; i++) { value = (value << 8) | data[i]; bits += 8; while (bits >= 5) { base32 += BASE32_CHARS[value >>> (bits - 5)]; value &= (1 << (bits - 5)) - 1; bits -= 5; } } if (bits > 0) { base32 += BASE32_CHARS[value << (5 - bits)]; } return base32; } ``` -------------------------------- ### Signature Source: https://github.com/nds-stack/bun-otp/blob/main/_autodocs/api-reference/totp.md Function signatures for generating and verifying TOTP. ```typescript async function totp(options: TOTPOptions): Promise ``` ```typescript async function totp.verify(options: TOTPVerifyOptions): Promise ```