chat-otp
v0.1.0
Published
Send and verify OTP codes via WhatsApp (unofficial, via Baileys) and Telegram (official API).
Maintainers
Readme
chat-otp
This package helps you send verification codes (OTPs) easily. You can send them via WhatsApp (unofficial, using Baileys) and Telegram (using the official Bot API).
Important: This package only sends the codes. Generating the code, storing it, setting an expiration time, and checking if it's correct is entirely up to you, on your backend. This gives you the freedom to use your own methods (like Redis, SQL database, custom timers) without being limited by this library.
Table of Contents
- Installation
- Important Warning
- Quick Start
- Telegram - Link Flow (Deep Link)
- Error Handling
- API Reference
Installation
Install the package using npm:
npm install chat-otpImportant Warning
- WhatsApp: We use an unofficial library that acts like WhatsApp Web. Meta (the company behind WhatsApp) does not provide or endorse this. Sending too many messages or using it for spam could get your phone number banned. It's best for smaller projects. For high volume, consider the official WhatsApp Business API.
- Telegram: We use the official Bot API. It's reliable, but be mindful of Telegram's rate limits.
- No Data Storage: This package does not store any data like codes, expiration times, or verification attempts. The security of your authentication system completely depends on how you manage this logic on your server.
Quick Start
Here's a simple example to get you started:
import { OtpSender, WhatsAppProvider } from 'chat-otp';
const sender = new OtpSender({
providers: [
new WhatsAppProvider({ authFolder: '.wa-auth' }), // Stores your WhatsApp session
],
});
await sender.connectAll(); // You'll need to scan a QR code the first time for WhatsApp
// YOU generate and manage the code!
const code = Math.floor(100000 + Math.random() * 900000).toString();
await sender.send('whatsapp', '+1234567890', code); // Send the code via WhatsAppFor Telegram, please see the Telegram - Link Flow (Deep Link) section below, as it's the only supported way for this channel.
To use WhatsApp, you need to configure the WhatsAppProvider:
new WhatsAppProvider({
authFolder: '.wa-auth', // Folder to save your login session (default: '.wa-auth')
printQrInTerminal: true, // Show the QR code in your terminal (default: true)
suppressSignalLogs: true, // Hide internal logs that might show sensitive info (default: true)
});First Time Login: A QR code will appear in your terminal. Scan it using your WhatsApp app (Settings → Linked Devices). The session will be saved in the authFolder, so you won't need to scan again next time.
Target Format: You can use the phone number with or without the country code (e.g., +1234567890 or 1234567890), or a raw WhatsApp JID (e.g., [email protected]).
Session Revoked: If your WhatsApp session gets disconnected (e.g., you log out on your phone), connect() will throw an error. You'll need to delete the authFolder and scan the QR code again.
suppressSignalLogs
The underlying library (Baileys) uses libsignal-node for encryption. Sometimes, it logs raw session data. By default, chat-otp filters these logs. Only turn off suppressSignalLogs if you need to see these logs for debugging during development.
Telegram - Link Flow (Deep Link)
This is useful when you don't know the user's chatId yet. The user needs to click a link that opens your Telegram bot first. This is a separate tool from OtpSender because its two-step process doesn't fit the send(channel, target, code) pattern.
import { TelegramLinkClient } from 'chat-otp';
const telegramLink = new TelegramLinkClient({
botToken: process.env.TELEGRAM_BOT_TOKEN!, // Your Telegram Bot Token
botUsername: process.env.TELEGRAM_BOT_USERNAME!, // Your Bot's username (without the @)
});Full Flow
Generate a unique link when the user requests verification:
// 1. Generate a unique link when the user requests verification const { token, url } = telegramLink.createLink(); // -> Show this `url` to the user (e.g., as a "Verify via Telegram" button)Store the link between the token and the pending request (this is your responsibility, with your own expiration time):
// 2. Store the token <-> pending request mapping (YOUR job, with your own expiration) myPendingRequests.set(token, { userId: currentUser.id, createdAt: Date.now() });Listen for the event that triggers when the user clicks the link and starts your bot:
// 3. Listen for the event triggered when the user clicks and starts the bot telegramLink.on('link', async ({ token, chatId }) => { const pending = myPendingRequests.get(token); if (!pending) return; // Token not found or expired (handled by you) myPendingRequests.delete(token); const code = generateOtpCode(); // Your logic await saveCodeSomewhere(pending.userId, code); // Your logic await telegramLink.sendCode(chatId, code); // Send the code to the user's chat });The user pastes the code received on Telegram into your UI. You then verify it as usual.
What this library does: Creates the token and link, listens for incoming /start commands from the bot link, and sends the message. What it doesn't do: Validate tokens, handle expiration, generate or compare codes – that's all on your end.
Error Handling
OtpSender.send() provides clear, typed errors to help you manage issues:
| Error Type | Reason |
| --- | --- |
| ProviderNotFoundError | The requested channel doesn't have a provider set up. |
| ProviderNotReadyError | The provider isn't connected (e.g., WhatsApp not scanned, or disconnected). |
| SendFailedError | The message failed to send on the provider's end (network issue, invalid recipient, etc.). |
try {
await sender.send('whatsapp', target, code);
} catch (err) {
if (err instanceof ProviderNotReadyError) {
// Example: Try reconnecting or use a different channel as a fallback
console.error('Provider not ready, maybe try reconnecting?');
}
// Re-throw other errors
throw err;
}API Reference
OtpSender
| Method | Description |
| --- | --- |
| connectAll() | Connects all providers that have a connect() method. |
| send(channel, target, code, options?) | Sends the code through the specified channel. Returns SendResult. |
WhatsAppProvider
| Option | Type | Default | Description |
| --- | --- | --- | --- |
| authFolder | string | .wa-auth | Folder to save the session. |
| printQrInTerminal | boolean | true | Displays the QR code in the terminal. |
| suppressSignalLogs | boolean | true | Filters sensitive internal logs. |
TelegramLinkClient
| Method | Description |
| --- | --- |
| createLink() | Generates { token, url } for the deep link. |
| sendCode(chatId, code, template?) | Sends the code to the resolved chatId. |
| on('link', listener) | Listens for link clicks and bot starts ({ token, chatId }). |
| Option | Type | Default | Description |
| --- | --- | --- | --- |
| botToken | string | — | Your Telegram Bot Token (required). |
| botUsername | string | — | Your Bot's username, without the @ (required). |
| defaultTemplate | string | 'Your verification code is: {code}' | The default message template. |
License
MIT
