Database-less OTP Verification
otp-without-db is a Node.js library, currently at version 1.0.6, designed for secure, database-less One-Time Password (OTP) verification. It leverages Node.js's built-in `crypto` module to create and verify HMAC-based hashes that encapsulate the OTP, recipient identifier (phone/email), and an expiration timestamp. This approach eliminates the need for persistent storage of OTPs on the server side, reducing database load and potential attack surface. The library's core functionality revolves around `createNewOTP` for generating a verifiable hash and `verifyOTP` for validating user-submitted credentials against that hash. While it handles verification, users must implement their own OTP generation (e.g., using `otp-generator`) and delivery mechanisms (SMS, email). The project has a relatively slow release cadence, suggesting a stable, feature-complete state since its initial publication. Its primary differentiator is the stateless, cryptographic verification model, which relies heavily on a shared secret key for security.
Common errors
-
Error: Invalid key length
cause The HMAC `key` argument passed to `createNewOTP` or `verifyOTP` is empty, null, or undefined, leading to an invalid key for the underlying `crypto.createHmac` function.fixEnsure a non-empty string or Buffer is provided for the `key` argument. It is highly recommended to use a strong, secret key via environment variables. -
ReferenceError: require is not defined in ES module scope
cause Attempting to use `require()` syntax in an ES module (`.mjs` file or `type: "module"` in `package.json`) environment.fixSwitch to ESM `import` statements (e.g., `import { createNewOTP } from 'otp-without-db';`) or ensure your file is treated as CommonJS (e.g., `.cjs` extension or `type: "commonjs"` in `package.json`).
Warnings
- gotcha This library explicitly relies on modern JavaScript features (Template literals, Default arguments, modern object literal). Using it with older Node.js versions might lead to syntax errors or unexpected behavior.
- breaking The security of your OTP verification system critically depends on the secrecy and uniqueness of the `key` argument. If this key is compromised or is not unique per application/environment, your system is vulnerable.
- gotcha The `expiresAfter` parameter in `createNewOTP` defines the OTP's validity period in minutes. Setting this too long can reduce security, while setting it too short can frustrate users.
- gotcha This library only handles the cryptographic verification of OTPs. You are responsible for generating the OTP itself (e.g., using `otp-generator`) and sending it to the user via SMS, email, or other channels.
Install
-
npm install otp-without-db -
yarn add otp-without-db -
pnpm add otp-without-db
Imports
- createNewOTP
const createNewOTP = require('otp-without-db').createNewOTP;import { createNewOTP } from 'otp-without-db'; - verifyOTP
const verifyOTP = require('otp-without-db').verifyOTP;import { verifyOTP } from 'otp-without-db'; - otpTool
const otpTool = require('otp-without-db');import * as otpTool from 'otp-without-db';
Quickstart
import { createNewOTP, verifyOTP } from 'otp-without-db';
import otpGenerator from 'otp-generator';
// Ensure you have otp-generator installed: npm install otp-generator
const SECRET_KEY = process.env.OTP_SECRET_KEY ?? 'your-very-secret-key-that-you-must-change-in-production-!!!!';
const userIdentifier = "+15551234567"; // Can be phone number or email
const expiresInMinutes = 5;
// 1. Generate OTP (using an external library like otp-generator)
const otp = otpGenerator.generate(6, { upperCaseAlphabets: false, specialChars: false, lowerCaseAlphabets: false });
console.log(`Generated OTP: ${otp}`);
// 2. Create a secure hash to send to the user (and keep track of on your server, if needed for context)
// This hash implicitly contains the identifier, OTP, and expiration time.
const hash = createNewOTP(userIdentifier, otp, SECRET_KEY, expiresInMinutes);
console.log(`Generated Hash: ${hash}`);
// In a real application, you would now send 'otp' to the user via SMS/email and 'hash' back to the client.
// For demonstration, we simulate the user receiving and sending back the details.
// --- User verification step (e.g., in an API endpoint) ---
const userProvidedOTP = otp; // User enters this, received via SMS/email
const userProvidedHash = hash; // Client sends this back, received in step 2
const userProvidedIdentifier = userIdentifier; // Client sends this back
// 3. Verify the OTP hash
const isVerified = verifyOTP(userProvidedIdentifier, userProvidedOTP, userProvidedHash, SECRET_KEY);
if (isVerified) {
console.log("OTP Verified Successfully!");
} else {
console.log("OTP Verification Failed or Expired.");
}