Implement SMS OTP Verification with MessageBird and NestJS - code-examples -

Frequently Asked Questions

Create a NestJS service that integrates with the MessageBird Verify API using their Node.js SDK. This service should handle sending the OTP to the user's phone number via SMS after validating the number format. The service will interact with MessageBird's API to generate and send the OTP, returning a verification ID to your application.
MessageBird's Verify API is a service for sending and verifying one-time passwords (OTPs) via SMS, commonly used for two-factor authentication (2FA). The API handles generating the OTP, delivering it to the user's phone number, and verifying user-submitted tokens, enhancing application security by adding an extra layer of verification beyond traditional passwords.
NestJS provides a structured and scalable framework for building server-side applications in Node.js, making it ideal for implementing OTP verification. It offers features like dependency injection, configuration management, and a modular architecture, making development more efficient and easier to maintain. Its support for TypeScript further improves code quality.
You can install the MessageBird Node.js SDK using either npm or yarn with the command `npm install messagebird` or `yarn add messagebird`. This SDK simplifies interaction with the MessageBird API, allowing your NestJS application to easily send SMS messages for OTP verification.
Store your MessageBird API key (test key for development, live key for production) in a `.env` file in your project root. Use the `@nestjs/config` module to load these environment variables securely into your NestJS application. Never commit `.env` to version control.
Class-validator, along with class-transformer, facilitates request data validation in NestJS. By defining Data Transfer Objects (DTOs) and decorating properties with validation rules, you ensure data integrity and prevent invalid data from reaching your service logic. This adds a layer of security and reliability.
Create a controller in your OTP module, define a `POST /otp/verify` endpoint, and inject the `OtpService`. Use the `@Body()` decorator and a DTO (VerifyOtpDto) to validate incoming data containing the verification ID and token. The controller calls the service's `verifyOtp` method, then returns the status ('verified' or an error) back to the client.
In your OTP controller, create a `POST /otp/send` endpoint and inject the `OtpService`. Use the `@Body()` decorator with a DTO (SendOtpDto) to validate the incoming phone number. The controller should then call the service's `sendOtp` method, returning the verification ID to the client.
The verification ID, returned by MessageBird's `verify.create` call, is a unique identifier associated with a specific OTP request. It links the OTP sent to the user with the subsequent verification process. This ID is then used along with the user-submitted OTP to complete the verification.
Implement comprehensive error handling in your `OtpService` by mapping MessageBird API error codes to appropriate HTTP exceptions. For example, an invalid token should return a 400 Bad Request, and an unexpected API failure should return a 500 Internal Server Error. Log errors with details to facilitate debugging.
Use `class-validator`'s `@IsPhoneNumber()` decorator within the `SendOtpDto` to validate the phone number format before it reaches your service logic. Handle any remaining format issues or MessageBird-specific number errors (like code 21) in the `OtpService` by throwing a `BadRequestException` with a clear message.
Only use your live MessageBird API key in your production environment. During development and testing, use the test key. This prevents accidental charges and allows you to use MessageBird's test phone numbers. Remember to switch to the live key for real OTP delivery when deploying to production.
Implement phone number normalization in your `OtpService` to handle variations in user input (spaces, dashes, parentheses). A basic `replace` function can handle simple cases, or consider using a dedicated phone number formatting library for more robust normalization across international formats.