비트베이크

Building a Secure SMS OTP API in Express.js + TypeScript in 5 Minutes (Zero Paperwork & Rate Limited)

2026-05-26T01:02:06.691Z

A professional, clean, and modern image depicting developer authentication interfaces or abstract tech elements, suitable for a tech blog post thumbnail with text overlay.

Building a Secure SMS OTP API in Express.js + TypeScript in 5 Minutes (Zero Paperwork & Rate Limited)

😱 Blocked by SMS Authentication Paperwork?

If you're building a side project, an e-commerce platform, or a startup MVP, chances are you'll eventually need a phone verification (SMS OTP) feature for user registration or password recovery. However, when developers start looking for an SMS API provider, they are often hit with a frustrating reality:

  • Heavy Paperwork Requirements: Endless demands for business registration certificates, telecommunication carrier usage proofs, and other documents that indie hackers simply don't have.
  • Pre-registered Sender IDs: Even if you submit the paperwork, you face a tedious, multi-day review process just to register the phone number sending the SMS.
  • Prohibitive Costs: Expensive per-message pricing (often 30~50 KRW in the local market) that burns through a startup's limited budget.

For solo developers, freelancers, and early-stage startups trying to validate their ideas quickly, these barriers are incredibly discouraging. Isn't there a way to implement SMS verification immediately after signing up, completely free of paperwork?

In this comprehensive tutorial, we will learn how to build a highly secure SMS OTP API using Express.js and TypeScript. We'll be using EasyAuth, a developer-centric SMS API that requires absolutely zero paperwork and takes less than 5 minutes to integrate. We'll also cover crucial security implementations, specifically applying Rate Limiting to protect your API from malicious abuse, and how to manage OTP states without needing Redis.


💡 Why Choose EasyAuth?

Before diving into the code, let's briefly highlight why EasyAuth is the go-to solution for this implementation:

  1. Zero Paperwork: Simply sign up with your email and get your API Key instantly. No business licenses required.
  2. Automated Sender ID: Skip the manual review process; the system provisions and handles the sending numbers automatically.
  3. Affordable Pricing: Highly competitive rates at just 15~25 KRW per message—roughly half the traditional cost.
  4. Intuitive API Design: Forget complex setups. You only need two endpoints: POST /send and POST /verify.
  5. Free Trial: Receive 10 free SMS credits immediately upon signup to test your integration.

🛠️ Step 1: Project Setup and Dependencies

First, let's establish a solid server environment by setting up an Express.js and TypeScript project and installing the necessary packages.

# Initialize project
npm init -y

# Install core packages
# express: Web server framework
# axios: HTTP client for calling the EasyAuth API
# dotenv: Environment variable management
# express-rate-limit: Middleware to prevent excessive API requests
npm install express axios dotenv express-rate-limit

# Install TypeScript and type definitions for development
npm install -D typescript ts-node @types/express @types/node

# Generate tsconfig.json
npx tsc --init

Once installed, create a .env file in the root directory of your project and paste the API Key you generated from the EasyAuth dashboard.

PORT=3000
EASYAUTH_API_KEY=your_easyauth_api_key_here

🛡️ Step 2: Preventing Abuse with Rate Limiting

The most critical security vulnerability when exposing an SMS sending API is SMS Bombing. Because this endpoint is typically public (unauthenticated), malicious bots or users could theoretically call your /send endpoint thousands of times in a minute. This not only spams the victim but can also result in massive financial losses for you.

To mitigate this, we must configure an impregnable defense using the express-rate-limit package to block excessive requests originating from the same IP address within a specified timeframe.


🚀 Step 3: Complete Implementation Code

If you were using a traditional SMS API, you would have to generate a random 6-digit code on your backend, store it in a Redis cache or a database alongside its expiration time, and then send the message.

EasyAuth handles all of this internally. It generates the code, manages the state, and tracks expiration automatically. This stateless approach saves you from deploying and maintaining a Redis instance.

Here is the complete, production-ready server.ts code featuring both Rate Limiting and EasyAuth integration.

import express, { Request, Response } from 'express';
import rateLimit from 'express-rate-limit';
import axios from 'axios';
import dotenv from 'dotenv';

dotenv.config();

const app = express();
app.use(express.json());

// ==========================================
// 1. Rate Limiting Setup (Prevent SMS Bombing)
// ==========================================
const otpLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes window
  max: 5, // Limit each IP to 5 requests per 15 minutes
  message: { 
    success: false, 
    error: 'Too many requests. Please try again later.' 
  },
  standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
  legacyHeaders: false, // Disable the `X-RateLimit-*` headers
});

// EasyAuth Configuration
const EASYAUTH_API_URL = 'https://api.easyauth.kr/v1';
const EASYAUTH_API_KEY = process.env.EASYAUTH_API_KEY;

// ==========================================
// 2. Send OTP API (/send)
// We apply the rate limiter strictly to the sending endpoint.
// ==========================================
app.post('/api/otp/send', otpLimiter, async (req: Request, res: Response) => {
  const { phone } = req.body;

  if (!phone) {
    return res.status(400).json({ success: false, error: 'Phone number is required.' });
  }

  try {
    // Call EasyAuth /send endpoint
    await axios.post(`${EASYAUTH_API_URL}/send`, 
      { phone }, 
      { headers: { Authorization: `Bearer ${EASYAUTH_API_KEY}` } }
    );
    
    res.status(200).json({ success: true, message: 'OTP sent successfully.' });
  } catch (error: any) {
    console.error('OTP Send Error:', error.response?.data || error.message);
    res.status(500).json({ success: false, error: 'Failed to send OTP.' });
  }
});

// ==========================================
// 3. Verify OTP API (/verify)
// ==========================================
app.post('/api/otp/verify', async (req: Request, res: Response) => {
  const { phone, code } = req.body;

  if (!phone || !code) {
    return res.status(400).json({ success: false, error: 'Phone number and code are required.' });
  }

  try {
    // Call EasyAuth /verify endpoint
    const response = await axios.post(`${EASYAUTH_API_URL}/verify`, 
      { phone, code }, 
      { headers: { Authorization: `Bearer ${EASYAUTH_API_KEY}` } }
    );

    // Handle verification response
    if (response.data.isValid) {
      res.status(200).json({ success: true, message: 'OTP verified successfully.' });
    } else {
      res.status(400).json({ success: false, error: 'Invalid or expired OTP code.' });
    }
  } catch (error: any) {
    console.error('OTP Verify Error:', error.response?.data || error.message);
    res.status(500).json({ success: false, error: 'Failed to verify OTP due to server error.' });
  }
});

// Start the server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`🚀 SMS OTP Server is running on port ${PORT}`);
});

Running the Code

You can easily run the development server via your terminal:

npx ts-node server.ts

💡 Essential Tips & Best Practices

  1. Rate Limiting is Mandatory, Not Optional As mentioned, because your OTP sending API is publicly accessible, you must limit the number of requests per IP using libraries like express-rate-limit. For higher-traffic applications, consider combining this with front-end protections like Google reCAPTCHA or Cloudflare turnstile.

  2. Strict Environment Variable Management Your API Key represents direct financial value. Never hardcode sensitive information into your source files. Always use a .env file and ensure it is firmly listed in your .gitignore before pushing to GitHub or any public repository.

  3. Embrace Stateless Architecture By letting EasyAuth manage the validity and expiration of the OTPs internally, your backend becomes wonderfully stateless. This means you don't need to spin up Redis instances or map out database tables just to keep track of generated codes. Calling /send and /verify is genuinely all it takes!


🎉 Conclusion

We've successfully designed and built a highly secure, rate-limited SMS OTP API using Express.js and TypeScript. As you can see from the code, implementing the actual business logic takes merely a few minutes.

As a developer, spending more time drowning in bureaucratic paperwork than writing actual code is a massive waste of your valuable resources. By adopting EasyAuth, you can eliminate these frustrations entirely.

  • 🚫 Zero Paperwork: Bypass the painful business registration and certificate hurdles.
  • Lightning Fast Setup: Sign up and complete your API integration in under 5 minutes.
  • 🤖 Automated Sender ID: Send messages immediately without tedious pre-registration processes.
  • 💰 Affordable Pricing: Highly competitive rates at just 15~25 KRW per message, keeping your overhead low.

Whether you're hacking together a weekend toy project, freelancing for a client, or pushing out a startup MVP, try EasyAuth today. Grab your 10 free test credits and implement SMS verification the modern, painless way!

비트베이크에서 광고를 시작해보세요

광고 문의하기

다른 글 보기

2026-06-16T05:01:55.625Z

2026 다이소 여름 신상/인기템! 시원한 여름 꿀템 총정리

2026년 다이소 여름 신상부터 인기 쿨링템, 장마철 필수품, 홈캉스 아이템까지! 가성비 넘치는 다이소 여름 꿀템으로 시원하고 쾌적한 여름을 준비하는 완벽 가이드.

2026-06-16T05:01:31.367Z

지속 가능한 국내 워케이션: 2026년 숨은 보석 여행지

2026년 국내 워케이션 트렌드는 지속가능한 여행과 만납니다. 디지털 디톡스, 친환경 숙소, 로컬 체험을 통해 몸과 마음을 치유하고 지역 경제 활성화에 기여하는 숨은 명소 3곳을 소개합니다. 지금 바로 나만의 지속 가능한 워케이션을 계획해보세요!

2026-06-16T05:01:30.087Z

2026년 최신 의학 트렌드: AI와 정밀의료로 여는 초개인화 건강관리

2026년, AI와 정밀의료가 이끄는 초개인화 건강관리 시대가 열렸습니다. 딥러닝 기반 진단, 유전체 맞춤 치료, 웨어러블 및 디지털 치료제가 일상 속 건강을 혁신합니다. 미래 의학의 도전 과제와 현명한 건강 관리법을 알아보세요.

2026-06-16T05:01:16.613Z

2026 가을/겨울 출산준비물: 신생아 육아템 필수템 총정리

2026년 가을/겨울 출산을 앞둔 예비맘들을 위한 완벽 가이드! 최신 트렌드를 반영한 신생아 육아템 필수템부터 대형 육아용품 비교, 스마트한 케어 및 수유 용품, 쌀쌀한 날씨 대비 아기옷, 그리고 알뜰 구매 팁까지 모든 출산준비물을 총정리했습니다.

서비스

피드자주 묻는 질문고객센터

문의

비트베이크

레임스튜디오 | 사업자 등록번호 : 542-40-01042

경기도 남양주시 와부읍 수례로 116번길 16, 4층 402-제이270호

트위터인스타그램네이버 블로그