npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ciphercross/nestjs-twilio-otp

v1.0.1

Published

Universal NestJS module for Twilio OTP SMS sending with dynamic configuration

Readme

🚀 @ciphercross/nestjs-twilio-otp

Production-ready NestJS module for sending OTP SMS via Twilio

with dynamic configuration, async factory support,

built-in templates, mock mode, and phone utilities.

Ideal for authentication flows, onboarding, PIN resets,

and any SMS-based verification logic.


📦 Installation

npm install @ciphercross/nestjs-twilio-otp twilio
# or
yarn add @ciphercross/nestjs-twilio-otp twilio

Optional: For enhanced international phone number validation, install libphonenumber-js:

npm install libphonenumber-js
# or
yarn add libphonenumber-js

If libphonenumber-js is installed, the module will automatically use it for more accurate phone number validation. Otherwise, it falls back to basic regex validation.

⚙️ Features

  • 🔐 OTP SMS sending with templates
  • ⚡ Twilio-powered delivery
  • 🔁 forRoot, forRootAsync, forRootWithConfig
  • 🎛️ Configurable through ConfigModule
  • 🧪 Mock mode (enabled: false) for dev/test environments
  • 🌍 Phone formatting & validation helpers
  • 💡 Custom OTP message templates
  • 🧰 Fully typed TypeScript API
  • 🧱 Works with NestJS 10.x / 11.x

🚀 Quick Start

1) Basic usage (forRoot)

import { Module } from '@nestjs/common';
import { TwilioModule } from '@ciphercross/nestjs-twilio-otp';

@Module({
  imports: [
    TwilioModule.forRoot({
      accountSid: 'your-account-sid',
      authToken: 'your-auth-token',
      phoneNumber: '+1234567890', // or messagingServiceSid
      messagingServiceSid: 'your-service-sid', // optional
      enabled: true,
      appName: 'MyApp',
      defaultOtpExpiryMinutes: 10,
    }),
  ],
})
export class AppModule {}

2) Configuration using ConfigModule

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { TwilioModule } from '@ciphercross/nestjs-twilio-otp';

@Module({
  imports: [
    ConfigModule.forRoot(),
    TwilioModule.forRootWithConfig('twilio'), // configService.get('twilio.*')
  ],
})
export class AppModule {}

Example .env:

TWILIO_ACCOUNT_SID=...
TWILIO_AUTH_TOKEN=...
TWILIO_PHONE_NUMBER=+1234567890
TWILIO_MESSAGING_SERVICE_SID=...
TWILIO_ENABLED=true

3) Async factory (forRootAsync)

@Module({
  imports: [
    ConfigModule.forRoot(),
    TwilioModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: (config: ConfigService) => ({
        accountSid: config.get('TWILIO_ACCOUNT_SID'),
        authToken: config.get('TWILIO_AUTH_TOKEN'),
        phoneNumber: config.get('TWILIO_PHONE_NUMBER'),
        messagingServiceSid: config.get('TWILIO_MESSAGING_SERVICE_SID'),
        enabled: config.get('TWILIO_ENABLED') === 'true',
        appName: 'MyApp',
        defaultOtpExpiryMinutes: 10,
      }),
      inject: [ConfigService],
    }),
  ],
})
export class AppModule {}

📤 Sending SMS & OTP

TwilioService example

import { Injectable } from '@nestjs/common';
import { TwilioService } from '@ciphercross/nestjs-twilio-otp';

@Injectable()
export class AuthService {
  constructor(private readonly twilio: TwilioService) {}

  async sendOtp(phone: string, code: string) {
    const result = await this.twilio.sendOtpSms(phone, code, 'sign_up');
    if (result.success) {
      console.log('OTP sent:', result.messageId);
    } else {
      console.error('Failed to send OTP:', result.error);
    }
  }

  async sendCustomSms(phone: string, message: string) {
    return this.twilio.sendSms({
      to: phone,
      message,
      purpose: 'notification',
    });
  }

  validatePhone(phone: string) {
    return this.twilio.validatePhoneNumber(phone);
  }

  formatPhone(phone: string) {
    return this.twilio.formatPhoneNumber(phone, '+1');
  }
}

🎨 Custom OTP Message

TwilioModule.forRoot({
  accountSid: 'sid',
  authToken: 'token',
  phoneNumber: '+1234567890',
  customMessageFormatter: (code: string, purpose: string) =>
    `Your verification code is ${code} (${purpose})`,
});

🧪 Mock Mode (No SMS Sent)

Perfect for development & automated tests.

TwilioModule.forRoot({
  accountSid: 'test',
  authToken: 'test',
  enabled: false, // no requests sent to Twilio
});

Mock response example:

{
  "success": true,
  "messageId": "mock-<uuid>"
}

📘 API Reference

TwilioService

Methods

| Method | Description | |--------|-------------| | sendSms(options) | Send any SMS message | | sendOtpSms(phone, code, purpose) | Send OTP code | | validatePhoneNumber(phone) | Validate phone format | | formatPhoneNumber(phone, countryCode?) | Format into E.164 | | getMessageTemplate(code, purpose) | Build OTP message | | getConfigStatus() | Check Twilio configuration state | | testConnection() | Verify Twilio credentials |

🔑 Supported OTP Purposes

  • sign_up
  • sign_in
  • pin_reset
  • password_reset
  • business_secret_reset
  • phone_change
  • (any custom string uses fallback template)

🧰 Phone Utilities

Standalone import:

import {
  formatPhoneNumber,
  maskPhoneNumber,
  normalizePhoneNumber,
  isValidPhoneFormat,
  extractCountryCode,
  validatePhoneNumber,
} from '@ciphercross/nestjs-twilio-otp';

⚠️ Rate Limiting & Security

Important: This module does not implement rate limiting. To protect your application from abuse and prevent excessive SMS costs, you should implement rate limiting in your application layer.

Recommended approaches:

  • Use NestJS throttler guards (@nestjs/throttler)
  • Implement rate limiting middleware (e.g., express-rate-limit with Redis)
  • Track OTP requests per phone number/IP address
  • Set maximum requests per time window (e.g., 3 requests per 15 minutes per phone number)

Example with NestJS Throttler:

import { ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler';
import { APP_GUARD } from '@nestjs/core';

@Module({
  imports: [
    ThrottlerModule.forRoot([{
      ttl: 60000, // 1 minute
      limit: 3, // 3 requests per minute
    }]),
    TwilioModule.forRoot({...}),
  ],
  providers: [
    {
      provide: APP_GUARD,
      useClass: ThrottlerGuard,
    },
  ],
})
export class AppModule {}

📄 License

MIT