@satyajeetsahoo/otp
v2.1.3
Published
Store-independent secure OTP service for Node.js
Maintainers
Readme
@satyajeetsahoo/otp
A highly secure OTP generation and verification service.
Why use this package?
Storing plain-text OTPs in your database is a severe security risk. This package generates cryptographically secure numeric OTPs and only stores their HMAC hashes in your cache (Redis/Local). It also automatically handles attempt rate-limiting, cooldown periods, and expiration, ensuring your authentication flows are virtually impenetrable to brute-force attacks.
Features
- Zero-knowledge Storage: Only stores HMAC SHA-256 hashes of OTPs.
- Brute Force Protection: Built-in tracking of failed attempts (
maxAttempts). - Cooldowns: Prevents users from spamming the "Resend OTP" button.
Installation
npm install @satyajeetsahoo/otpConfiguration
This package requires a Cache strategy (from @satyajeetsahoo/cache) to store the hashes.
import { createOtpService } from '@satyajeetsahoo/otp';
import { CacheService } from '@satyajeetsahoo/cache';
const cache = CacheService.createCache('redis', { client: redisInstance });
export const otp = createOtpService({
storeType: 'redis',
cacheStrategy: cache,
config: {
secret: process.env.OTP_SECRET, // Must be >= 32 characters!
length: 6, // 6-digit OTP
ttlSeconds: 300, // Expires in 5 minutes
maxAttempts: 5, // Locks out after 5 wrong tries
keyPrefix: 'otp:auth:'
}
});Usage Examples
1. Generating & Sending an OTP
This package does NOT send SMS/Emails automatically, allowing you to integrate with Twilio, AWS SNS, SendGrid, etc.
// 1. Generate the OTP
const response = await otp.sendOtp('+919999999999');
// 2. The response object
console.log(response);
/*
{
sent: true,
expiresInSeconds: 300,
debugOtp: '849201' // NOTE: Only present in non-production environments!
}
*/
// 3. Send it via your provider
await mySmsProvider.send('+919999999999', `Your code is ${response.debugOtp}`);2. Verifying an OTP
try {
// Returns true if valid, throws an OtpError otherwise
await otp.verifyOtp('+919999999999', req.body.code);
// Login successful!
} catch (error) {
// e.g., "Invalid OTP", "Too many incorrect attempts", or "OTP expired"
res.status(error.status).json({ message: error.message });
}