### 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
```