{"id":11507,"library":"otp","title":"OTP Utility for Google Authenticator","description":"This package provides comprehensive utilities for generating and verifying One-Time Passwords (OTP), adhering to both HOTP (HMAC-Based One-Time Password Algorithm) as defined in RFC 4226 and TOTP (Time-Based One-Time Password Algorithm) as defined in RFC 6238. It is designed to be compatible with popular OTP mechanisms like Google Authenticator. The current stable version is 2.0.1, indicating active development and maintenance. The library differentiates itself by offering direct support for generating Google Authenticator-compatible URLs, parsing existing OTP URLs or base32-encoded secrets, and including a JSON reviver for seamless serialization and deserialization of OTP objects. While a specific release cadence is not formally stated, significant refactors, such as the TypeScript conversion in v1.0.0, highlight ongoing efforts to modernize and improve the codebase.","status":"active","version":"2.0.1","language":"javascript","source_language":"en","source_url":"git://github.com/pipobscure/otp","tags":["javascript","one-time-password","google authenticator","hotp","totp","otp"],"install":[{"cmd":"npm install otp","lang":"bash","label":"npm"},{"cmd":"yarn add otp","lang":"bash","label":"yarn"},{"cmd":"pnpm add otp","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"The primary OTP class is a default export. For TypeScript and modern Node.js, use ESM import. CommonJS `require` is generally incorrect for v1.0.0+.","wrong":"const OTP = require('otp');","symbol":"OTP","correct":"import OTP from 'otp';"},{"note":"OTP.parse is a static method of the default exported OTP class, not a named export. Ensure you import the OTP class first.","wrong":"import { parse } from 'otp'; // parse is a static method of the OTP class","symbol":"OTP.parse","correct":"import OTP from 'otp';\nconst options = OTP.parse('otpauth://...');"},{"note":"OTP.reviveJSON is a static method of the OTP class, used as a replacer function for `JSON.parse`. Import the OTP class first.","wrong":"import { reviveJSON } from 'otp'; // reviveJSON is a static method of the OTP class","symbol":"OTP.reviveJSON","correct":"import OTP from 'otp';\nconst obj = JSON.parse(jsonString, OTP.reviveJSON);"}],"quickstart":{"code":"import OTP from 'otp';\n\nasync function demonstrateOtp() {\n  // Use a securely generated, base32-encoded secret.\n  // For demonstration, a common test secret \"JBSWY3DPEHPK3PXP\" (Hello!) is used.\n  const secret = 'JBSWY3DPEHPK3PXP'; // Replace with a strong, random secret in production\n\n  console.log('Using Secret (Base32):', secret);\n\n  // Initialize OTP with a secret and desired name\n  const otpInstance = new OTP({\n    name: 'MyOTPApp',\n    secret: secret,\n    codeLength: 6,\n    timeSlice: 30, // Default is 30 seconds\n  });\n\n  // --- TOTP Demonstration ---\n  console.log('\\n--- TOTP ---');\n  const currentTotpCode = await otpInstance.totp();\n  console.log(`Current TOTP code (valid for ~30s): ${currentTotpCode}`);\n  console.log('Google Authenticator URL (TOTP):', otpInstance.totpURL);\n\n  // --- HOTP Demonstration ---\n  console.log('\\n--- HOTP ---');\n  // For HOTP, the counter must be managed and incremented server-side\n  const counter = 123;\n  const hotpCode = await otpInstance.hotp(counter);\n  console.log(`HOTP code for counter ${counter}: ${hotpCode}`);\n  console.log('Google Authenticator URL (HOTP):', otpInstance.hotpURL);\n\n  // --- Parsing an OTP URL ---\n  console.log('\\n--- URL Parsing ---');\n  const exampleTotpUrl = otpInstance.totpURL; // Or any `otpauth://` URL\n  const parsedOptions = OTP.parse(exampleTotpUrl);\n  console.log('Parsed OTP options from URL:', parsedOptions);\n  // Example: parsedOptions might contain { type: 'totp', label: 'MyOTPApp', secret: 'JBSWY3DPEHPK3PXP', ... }\n\n  // --- Reviving an OTP object from JSON ---\n  console.log('\\n--- JSON Reviver ---');\n  const stringifiedOtp = JSON.stringify(otpInstance);\n  console.log('Stringified OTP object (truncated):', stringifiedOtp.substring(0, 100) + '...');\n  const revivedOtp = JSON.parse(stringifiedOtp, OTP.reviveJSON);\n  console.log('Revived OTP object secret matches original:', revivedOtp.secret === otpInstance.secret);\n}\n\ndemonstrateOtp().catch(console.error);","lang":"typescript","description":"This quickstart demonstrates how to initialize the OTP class with a secret, generate both Time-Based One-Time Passwords (TOTP) and HMAC-Based One-Time Passwords (HOTP), generate Google Authenticator-compatible URLs, parse existing OTP URLs, and utilize the provided JSON reviver for object serialization."},"warnings":[{"fix":"Review your import statements to ensure they align with ESM patterns (e.g., `import OTP from 'otp';`). Verify secret handling, ensuring it's a Base32 string or Buffer as expected by the new API.","message":"Version 1.0.0 introduced a significant TypeScript refactor, Buffer cleanup, and dependency removal. Users upgrading from pre-1.0.0 versions may encounter breaking changes related to import paths, module exports (ESM vs CJS), and how secrets (especially Buffer types) are handled.","severity":"breaking","affected_versions":"<1.0.0"},{"fix":"Always use `await` when calling `otpInstance.hotp(counter)` or `otpInstance.totp()` within an `async` function, or handle the Promise using `.then()`.","message":"The `hotp()` and `totp()` methods return Promises. Forgetting to `await` their results will lead to unhandled promise rejections and incorrect OTP retrieval.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Store secrets securely in environment variables, secret management services, or encrypted databases. Transmit them only over secure, encrypted connections (HTTPS/TLS).","message":"OTP secrets (keys) are highly sensitive. Improper storage (e.g., plaintext in code or insecure databases) or transmission (e.g., over unencrypted channels) can compromise the security of your two-factor authentication.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Implement robust server-side storage and atomic incrementation for each user's HOTP counter. Never reset the counter unless absolutely necessary (e.g., re-provisioning).","message":"For HOTP, the counter (`hotp(counter)`) must be managed externally and reliably incremented for each use. If the counter is not correctly synchronized between the client and server, HOTP codes will consistently fail validation.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Generate secrets that decode to 64-bit (8 bytes) or 128-bit (16 bytes) lengths. Typically, longer keys (e.g., 128-bit / 16 bytes base32 encoded) are recommended for stronger security.","message":"The `keySize` option for OTP generation (default 64) refers to the *bits* of the key after decoding, which means a 64-bit key or 128-bit key. Ensure your provided `secret` (when base32 decoded) matches the expected key length for robust security.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Use the correct ESM default import: `import OTP from 'otp';` Ensure your environment supports ESM modules (e.g., Node.js with `\"type\": \"module\"` in `package.json` or transpilation).","cause":"Attempting to import the OTP class using CommonJS `require()` syntax or an incorrect named import with ESM.","error":"TypeError: OTP is not a constructor"},{"fix":"Always `await` the asynchronous OTP generation methods: `const code = await otpInstance.totp();`","cause":"Calling `otpInstance.totp()` or `otpInstance.hotp()` without awaiting the returned Promise.","error":"UnhandledPromiseRejectionWarning: Promise { <pending> }"},{"fix":"Ensure your secret (either a Buffer or Base32-encoded string) corresponds to a decoded length of 8 bytes (64 bits) or 16 bytes (128 bits). Adjust `keySize` option if using a non-default length.","cause":"The provided secret, after base32 decoding, does not result in a key length of 64 or 128 bits, which are the supported `keySize` values.","error":"Error: Invalid secret length"},{"fix":"Verify that the URL string conforms to the `otpauth://` scheme, including type, label, and parameters like `secret` and `issuer`.","cause":"The string passed to `OTP.parse()` is not a valid `otpauth://` URL format or is malformed.","error":"Error: Failed to parse OTP URL"}],"ecosystem":"npm"}